當多個線程操做同一個變量時,每一個線程都會將該變量拷貝一份到本身工做內存中,而後線程完成操做以後,將變量寫回主內存。所以可見性就是一個線程在修改變量以後,回通知其餘線程,告知改變量已經被修改了。
首先建立一個資源類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
。性能
爲了提升性能,編譯器和處理器經常會進行指令重排,在多線程環境下,因爲指令重排,致使代碼的執行順序和咱們書寫代碼順序不一致,最終變量可否保持一致是沒法肯定的,結果沒法預測。測試