java基礎之執行緒 認識volatile

楚棠發表於2019-03-14

把java基礎擼一邊,從簡單的開始。

執行緒部分:

對synchronize初步瞭解之後,知道大概原理暫時先放下,其他深入的後續再來(原因是我也還不會)。本章是對java提供的另一個關鍵字volatile認識一下,並使用它。

volatile 單詞意思:adj. [化學] 揮發性的;不穩定的;爆炸性的;反覆無常的

                              n. 揮發物;有翅的動物

我理解為是個可變的意思,不穩定。

可見性

在多執行緒開發中,對共享資料的操作是會有頻繁操作的,為了保證在開發中,對會頻繁變動的多執行緒運算元據保證一致性。java提供了synchronize,還有volatile。

在瞭解之前,知道一個詞:可見--一個執行緒修改了這個變數,在另一個執行緒中能夠讀到這個修改後的值。這裡注意一下,只是讀到,而不是讀寫操作。不能保證原子性

synchronize是在保護他的程式碼塊,不被同時兩個執行緒進入操作出現,讓執行緒是序列進入。重而保證了這個可見性。

volatile是怎麼樣保證引數的可見呢?

這裡直接講原理會好點:在建立例項的時候,加了volatile修飾詞的話,在彙編中會多了一個lock指令。

lock指令:

在多處理器的系統上,1:將當前處理器快取行的內容寫回都系統記憶體

                                  2:這個寫回記憶體的操作會使其他CPU裡的快取了該記憶體地址的資料失效

java基礎之執行緒 認識volatile

可以理解為volatile是讀鎖。在記憶體int a 的資料被執行緒1影響到了CPU執行緒2快取的int i的資料,但注意。這裡只相信讀到的資料。但不影響執行緒2執行緒3這個共享記憶體的資料操作。這樣也就可以知道,這個volatile的侷限性。它不具備原子性,只有可見性。及時更新,但不限制其他資料退volition修飾的操作。

對於他的侷限性。執行做如下操作

java基礎之執行緒 認識volatile

例項:

對一先修飾也volition的資料,程式只執行一方進行操作,其他執行緒不允許進行更改,只可以讀。這也是叫輕量級鎖的原因。下面展示程式碼

public class A3 {

    private volatile int a ;

    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }
}複製程式碼

public class Demo31 {

    public static void main(String[] age ){
        A3 a3 = new A3();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0 ; i <= 100 ; i++){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+ "修改值"+i);
                    a3.setA(i);
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0 ; i <= 100 ; i++){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+ "讀取值"+a3.getA());

                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0 ; i <= 100 ; i++){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+ "讀取值"+a3.getA());
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0 ; i <= 100 ; i++){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+ "讀取值"+a3.getA());
                }
            }
        }).start();

    }

}複製程式碼

Thread-0修改值0
Thread-1讀取值0
Thread-2讀取值0
Thread-3讀取值0
Thread-0修改值1
Thread-1讀取值1
Thread-2讀取值1
Thread-3讀取值1
Thread-0修改值2
Thread-1讀取值2
Thread-2讀取值2
Thread-3讀取值2
Thread-0修改值3
Thread-1讀取值3
Thread-2讀取值3
Thread-3讀取值3
Thread-0修改值4
Thread-1讀取值4
複製程式碼

可以看到,一旦執行緒被修改之後,讀取到的資料就不會更改過來。但如果同時對資料進行修改

public class Demo31 extends Thread {

    public volatile int a = 0 ;

    public void set(){
        for (int i = 0 ; i  < 100 ; i++){
            a++;
            System.out.println(Thread.currentThread().getName() + "   a : "+a);
        }
    }

    @Override
    public void run() {
        set();
    }

    public static void main(String[] age ){
        new Demo31().start();
        new Demo31().start();
        new Demo31().start();
    }

}複製程式碼

結果

Thread-0   a : 1
Thread-1   a : 1
Thread-1   a : 2
Thread-0   a : 2
Thread-1   a : 3
Thread-2   a : 1
Thread-1   a : 4
複製程式碼

即使被volatile修飾之後,但並不會保證原子性。對於volatile的操作。要儘量保證是一個執行緒修改,其他執行緒只是讀。

推薦文章:

深入理解volatile原理和使用


相關文章