Java 中的 volatile

volatile 是Java虛擬機提供的輕量級的同步機制。

  1. 保證可見性
  2. 不保證原子性
  3. 禁止指令重排

可見性

當多個線程操做同一個變量時,每一個線程都會將該變量拷貝一份到本身工做內存中,而後線程完成操做以後,將變量寫回主內存。所以可見性就是一個線程在修改變量以後,回通知其餘線程,告知改變量已經被修改了。
首先建立一個資源類java

class MyData {
    volatile int number = 0;
    public void setNumber () {
        this.number = 60;
    }
    public void numberPlus() {
        this.number++;
    }
}
// 多線程下測試
public static void main(String[] args) {
   MyData myData = new MyData();
   new Thread(() -> {
            System.out.println(myData.number);
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            myData.setNumber();
            System.out.println(myData.number);
        }, "AAA").start();;

        while(myData.number == 0) {
        }
}

當使用 volatile 修飾 number 以後,程序回輸出 0 和 60 以後執行完成退出。
當沒有使用 volatile 修飾 number,程序回輸出 0 和 60 以後一直保持執行(死循環),不退出。
由此能夠看出,volatile 修飾的變量在修改後,回通知其餘線程,保證可見性。多線程

原子性

class MyData {
    volatile int number = 0;
    public void setNumber () {
        this.number = 60;
    }
    public void numberPlus() {
        this.number++;
    }
    AtomicInteger atomicInteger = new AtomicInteger(); // 默認爲0
    public void atomicAdd() {
        atomicInteger.getAndIncrement();
    }
}
public static void main(String[] args) {
    MyData myData = new MyData();
    for(int i=0; i<20; i++) {
            new Thread(() -> {
                for(int j=0; j<1000; j++) {
                    myData.numberPlus();
                    myData.atomicAdd();
                }
            }, String.valueOf(i)).start();;
        }

        while(Thread.activeCount() >2) {
            Thread.yield();
        }
        System.out.println(myData.number);
        System.out.println(myData.atomicInteger);
}

程序輸出 number 的值小於20000,atomicIntege r等於20000。
由於 volatile 不保證原子性,因此在多線程下操做 number 會出現值被覆蓋的問題,也就是一個線程尚未完成++,另外一個線程就取出了 number 進行++, 最後致使值小於了 20000。
解決 volatile 原子性問題,可使用 AtomicInteger性能

指令重排

爲了提升性能,編譯器和處理器經常會進行指令重排,在多線程環境下,因爲指令重排,致使代碼的執行順序和咱們書寫代碼順序不一致,最終變量可否保持一致是沒法肯定的,結果沒法預測。測試

相關文章
相關標籤/搜索