目錄java
代碼解析:新起一個子線程執行m()方法,1秒後主線程將b置爲false,子線程是否會中止執行死循環while(b){},打印「end」緩存
package com.bernardlowe.concurrent.t01; import java.util.concurrent.TimeUnit; public class Test_09 { boolean b = true; void m(){ System.out.println("start"); while(b){} System.out.println("end"); } public static void main(String[] args) { final Test_09 t = new Test_09(); new Thread(new Runnable() { @Override public void run() { t.m(); } }).start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } t.b = false; } }
結果:1秒鐘事後並不會中止執行死循環while(b){},打印「end」
這時候,若是將boolean b = true;這段代碼前加一個volatile關鍵字
即volatile boolean b = true;
,就會達到預想中的效果安全
思考:爲何加上這個關鍵字,其餘線程就會讀取到已經改變的變量的值了?ide
是由於在CPU計算過程當中,會將計算過程須要的數據加載到CPU計算緩存中,當CPU計算中斷時,有可能刷新緩存,從新讀取內存中的數據。在線程運行的過程當中,若是某變量被其餘線程修改,可能形成數據不一致的狀況,從而致使結果錯誤。
而volatile修飾的變量是線程可見的,當JVM解釋volatile修飾的變量時,會通知CPU,在計算過程當中,每次使用變量參與計算時,都會檢查內存中的數據是否發生變化,而不是一直使用CPU緩存中的數據,能夠保證計算結果的正確。atom
可是這樣還有一個問題,volatile只能保證可見性,不能保證原子性線程
下面再看一個示例:
預期結果:起10個線程,每一個線程都對count增長10000,預期結果爲count=100000code
package com.bernardlowe.concurrent.t01; import java.util.ArrayList; import java.util.List; public class Test_10 { volatile int count = 0; /*synchronized*/ void m(){ for(int i = 0; i < 10000; i++){ count++; } } public static void main(String[] args) { final Test_10 t = new Test_10(); List<Thread> threads = new ArrayList<>(); for(int i = 0; i < 10; i++){ threads.add(new Thread(new Runnable() { @Override public void run() { t.m(); } })); } for(Thread thread : threads){ thread.start(); } for(Thread thread : threads){ try { thread.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(t.count); } }
但結果並非blog
緣由是volatile只是通知底層計算時,CPU檢查內存數據,而不是讓一個變量在多個線程中同步。內存
這時候能夠給m()方法增長一個synchronized關鍵字,能夠達到預期的效果,即synchronized void m()
rem
還有另外一種方法能夠保證原子性,在上面代碼將count聲明爲AtomicInteger原子操做,結果仍然是100000
// 其中的每一個方法都是原子操做。能夠保證線程安全。 AtomicInteger count = new AtomicInteger(0); void m(){ for(int i = 0; i < 10000; i++){ count.incrementAndGet(); } }
這裏不單單可聲明Integer類型,java.util.concurrent.atomic包裏面還有其餘類型的