java基礎之線程 認識volatile

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

線程部分:緩存

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

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

                              n. 揮發物;有翅的動物ide

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

可見性

在多線程開發中,對共享數據的操做是會有頻繁操做的,爲了保證在開發中,對會頻繁變更的多線程操做數據保證一致性。java提供了synchronize,還有volatile。this

在瞭解以前,知道一個詞:可見--一個線程修改了這個變量,在另外一個線程中可以讀到這個修改後的值。這裏注意一下,只是讀到,而不是讀寫操做。不能保證原子性spa

synchronize是在保護他的代碼塊,不被同時兩個線程進入操做出現,讓線程是串行進入。重而保證了這個可見性。線程

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

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

lock指令:

在多處理器的系統上,1:將當前處理器緩存行的內容寫回都系統內存

                                  2:這個寫回內存的操做會使其餘CPU裏的緩存了該內存地址的數據失效


能夠理解爲volatile是讀鎖。在內存int a 的數據被線程1影響到了CPU線程2緩存的int i的數據,但注意。這裏只相信讀到的數據。但不影響線程2線程3這個共享內存的數據操做。這樣也就能夠知道,這個volatile的侷限性。它不具有原子性,只有可見性。及時更新,但不限制其餘數據退volition修飾的操做。

對於他的侷限性。運行作以下操做


實例:

對一先修飾也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原理和使用

相關文章
相關標籤/搜索