標籤:
並發,我的理解就是同時運行多個程式。同時,難以避免的就是資料的同步問題,如果資料同步問題處理不好就很容易造成程式出現bug,當然,對於其造成的危害,不加詳述。
首先,來看一個簡單的例子,當然,這個例子也並非是我發現的。
public class StopTread { private static boolean stopRequested; static Thread backgroundThread = new Thread(new Runnable() { public void run() { int i = 0; while(!stopRequested) { i++; } } }); public static void main(String[] args) throws InterruptedException { backgroundThread.start(); TimeUnit.SECONDS.sleep(1); stopRequested = true; }}
造成這個問題的原因在於當主線程修改了stopRequested變數後,後台線程並沒有及時的讀取到最新的值,因此,造成了後台線程會一直運行下去。代碼內容很容易理解,就是通過一個變數來控制線程的停止與運行而已。當stopRequested被主線程設定為true時,後台線程就終止運行。但是,這個程式中並沒有對stopRequested做資料同步處理,這就造成了資料的不安全性,當然,並不是在所有情況都能發生這個資料的不安全性的。但至少理論上是存在,同時,我也花費了很長的時間,類比出了這個不安全性的存在。
根據相關資料解釋其原因為:
while(!stopRequested){ i++;}
被最佳化成了:
if(!stopRequested) while(true) i++;
也正是由於這個最佳化導致了程式無法前進執行。
對於解決這個問題的方法有兩種:其一是通過鎖機制,其二是通過volatile修飾符。
方法一:
public class StopTread { private static boolean stopRequested; static Thread backgroundThread = new Thread(new Runnable() { public void run() { int i = 0; while(!stopRequested()) { i++; } } }); private static synchronized void requestStop() { stopRequested = true; } private static synchronized boolean stopRequested() { return stopRequested; } public static void main(String[] args) throws InterruptedException { backgroundThread.start(); TimeUnit.SECONDS.sleep(1); requestStop(); }}
可以發現,寫方法和讀方法都被同步了,只同步寫方法是不能實現,如果沒有對讀和寫方法都進行同步的話,同步是不會起作用的。
方法二:
public class StopTread { private static volatile boolean stopRequested; static Thread backgroundThread = new Thread(new Runnable() { public void run() { int i = 0; while(!stopRequested) { i++; } } }); public static void main(String[] args) throws InterruptedException { backgroundThread.start(); TimeUnit.SECONDS.sleep(1); stopRequested = true; }}
Volatile的修飾符不執行互斥訪問,但是可以保證一個縣城在讀取該域的時候就講看到最近剛剛被寫入的值。
java資料同步陷阱