多執行緒的安全問題
阿新 • • 發佈:2020-07-25
一、可見性
- 例如下面的程式,先啟動一個執行緒,線上程中將一個變數的值更改,而主執行緒卻一直無法獲得此變數的新值。
//1.執行緒類 public class MyThread extends Thread { public static int a = 0; @Override public void run() { System.out.println("執行緒啟動,休息2秒..."); try { Thread.sleep(
//測試類public class Demo {
public static void main(String[] args) {
t.start();
//主執行緒繼續
while (true) {
if (MyThread.a == 1) {
System.out.println("主執行緒讀到了a = 1");
}
}
}
}
二、有序性
- 有些時候“編譯器”在編譯程式碼時,會對程式碼進行“重排”,例如:
- 但在“多執行緒”情況下,程式碼重排,可能會對另一個執行緒訪問的結果產生影響:
三、原子性
- 請看以下示例
//執行緒類 public class MyThread extends Thread { public static int a = 0; @Override public void run() { for (int i = 0; i < 10000; i++) { a++; } System.out.println("修改完畢!"); } } //測試類 public class Demo { public static void main(String[] args) throws InterruptedException { MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); t1.start(); t2.start(); Thread.sleep(1000); //總是不準確的。原因:兩個 執行緒訪問a的步驟不具有:原子性 System.out.println("獲取a最終值:" + MyThread.a); } }
- 記憶體工作圖
執行緒t1先讀取a 的值為:0
t1被暫停
執行緒t2讀取a的值為:0 t2將a = 1 t2將a寫回主記憶體 t1將a = 1 t1將a寫回主記憶體(將t2更改的1,又更改為1) 所以兩次加1,但結果仍為1,少加了一次。 原因:兩個執行緒訪問同一個變數a的程式碼不具有"原子性"