java中同步synchronized的意義,如何用它解決線程不安全的問題

馬克-to-win:從上節(jié)我們學(xué)到,當(dāng)多個線程訪問且更改同一個變量時,很容易出現(xiàn)線程安全問題,誠然,我們可以通過一些其他手段,比如局部變量,多個實例,調(diào)整程序結(jié)構(gòu)來解決線程安全問題,但是通常來講,通過同步機(jī)制 synchronized來解決線程安全問題更加確定。比如,由于需求等其他限制條件決定,我們不能夠用局部變量或多個實例或什么其他辦法解決怎么辦? synchronized為我們提供了比較確定的方法。換句話說,線程安全問題, synchronized基本能解決。分析上一節(jié)的線程安全問題,我們發(fā)現(xiàn)問題的起因主要是兩個線程同時訪問更改共同的變量造成的,只要我們讓能夠更改共同變量的方法序列的執(zhí)行,(換句話就是一個執(zhí)行完后,另一個再執(zhí)行,) 就沒問題了。如何實現(xiàn)呢? 用synchronized,現(xiàn)在針對上一節(jié)有問題的例子:1.8.1_b,我們只加一個字synchronized, 問題就解決了,馬克- to-win:馬克 java社區(qū):防盜版實名手機(jī)尾號: 73203。



例1.9.1-本章源碼

class Photoshop {
    private Photoshop() {
    }
    private static Photoshop photoshop = null;
    public synchronized static Photoshop getInstanceQixy() {
        if (photoshop == null) {
            photoshop = new Photoshop();
        }
        return photoshop;
    }
}
class MyThreadMark_to_win extends Thread {
    public void run() {
        Photoshop photoshopI1 = Photoshop.getInstanceQixy();
        System.out.println(Thread.currentThread().getName() + "實例是 "
                + photoshopI1);
    }
}
public class Test {
    public static void main(String[] args) {
        MyThreadMark_to_win mt1 = new MyThreadMark_to_win();
        MyThreadMark_to_win mt2 = new MyThreadMark_to_win();
        mt1.start();
        mt2.start();
    }
}

輸出結(jié)果:

Thread-1實例是 Photoshop@a62fc3
Thread-0實例是 Photoshop@a62fc3

現(xiàn)在針對上一節(jié)有問題的例子:1.8.2_b,我們只加一個字synchronized, 問題也能解決,我們看一下。




例1.9.2-本章源碼

class BookMark_to_win {
    int bookNum=10;
    synchronized void onlySellOne() {
        if (bookNum > 0) {
            System.out.println(Thread.currentThread().getName()
                    + " before" + bookNum);
            bookNum--;
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
            }
            System.out.println(Thread.currentThread().getName()
                    + " after " + bookNum);
        }
    }
}
class MyThread extends Thread {
    BookMark_to_win book;
    MyThread(BookMark_to_win tmp) {
        this.book = tmp;
    }
    public void run() {
/*run()里不能就只是寫book.onlySellOne(), 因為會呈現(xiàn)
兩個線程在那交替的效果*/      
        while (book.bookNum>0) {
            book.onlySellOne();
        }
    }
}
public class Test {
    public static void main(String[] args) {
        BookMark_to_win bookM = new BookMark_to_win();
        Thread t1 = new MyThread(bookM);
        Thread t2 = new MyThread(bookM);
        t1.start();
        t2.start();
    }
}

輸出結(jié)果:

Thread-0 before10
Thread-0 after 9
Thread-0 before9
Thread-0 after 8
Thread-0 before8
Thread-0 after 7
Thread-0 before7
Thread-0 after 6
Thread-1 before6
Thread-1 after 5
Thread-1 before5
Thread-1 after 4
Thread-0 before4
Thread-0 after 3
Thread-0 before3
Thread-0 after 2
Thread-0 before2
Thread-0 after 1
Thread-0 before1
Thread-0 after 0

if (bookNum > 0) {直接執(zhí)行完了,就可以退出synchronized塊兒了,要想不切換,就if變成while,就一個線程知道執(zhí)行完為止。),完美配合,從10到0,一個一個的遞減。perfect!