1. 併發程式設計的三個問題
阿新 • • 發佈:2021-01-18
技術標籤:java一些事synchronizedjava併發程式設計
1. 可見性
指一個執行緒對共享變數進行修改,另一個執行緒立即得到修改後的值
測試程式碼
public class Test01Visibility { private static boolean flag = true; public static void main(String[] args) throws InterruptedException { new Thread(() -> { while (flag) { //千萬別列印,列印就沒有效果 } }).start(); Thread.sleep(2000); new Thread(() -> { flag = false; System.out.println("執行緒修改了值為false"); }).start(); } }
結果是值修改成了false了,但是程式還沒結束進入死迴圈
執行緒2對共享變數進行了修改,但執行緒1卻不知道。
2. 原子性
指一次或多次操作,要麼所有操作執行成功並且不受其他因素干擾而停止,要麼就是所有操作都不成功。
測試程式碼
public class Test02Atomicity { private static int number = 0; public static void main(String[] args) throws InterruptedException { List<Thread> list = new ArrayList<Thread>(); for (int i = 0; i < 5; i++) { Thread t = new Thread(() -> { for (int j = 0; j < 1000; j++) { number++; } }); t.start(); list.add(t); } //免得主執行緒跑完了 for (Thread thread : list) { thread.join(); } System.out.println(number); } }
最後執行有可能少於5000
這是因為number++;並不是一個原子性操作,通過javap -p -v反編譯該class檔案,可以看到其由4條指令構成
分別對應的大概意思是,(1)獲取值,(2)準備常量1,(3)值+常量1,(4)把結果返回。
因此多個執行緒操作的時候,比如有可能執行緒1獲取值的是100,正要準備100+1前,執行執行緒2了,此時執行緒2也獲取到值100,也是100+1,最後執行緒1,和執行緒2都把101值返回到變數中。即做了兩次加法但是結果只加了1.
3. 有序性
指程式中程式碼的執行順序,java在編譯和執行時會對程式碼進行優化,會導致最後程式的執行順序不一定是我們編寫程式碼的順序
這個測試類有點難寫,借用了一個jsrtress包
<dependency>
<groupId>org.openjdk.jcstress</groupId>
<artifactId>jcstress-core</artifactId>
<version>0.7</version>
</dependency>
package demo1;
import org.openjdk.jcstress.annotations.*;
import org.openjdk.jcstress.infra.results.I_Result;
@JCStressTest
@Outcome(id={"1","4"},expect = Expect.ACCEPTABLE,desc="ok")
@Outcome(id={"0"},expect = Expect.ACCEPTABLE_INTERESTING,desc="danger")
@State
public class Test03Ordering {
int num = 0;
boolean ready = false;
@Actor
public void actor1(I_Result r){
if (ready) {
r.r1 = num + num;
} else {
r.r1 = 1;
}
}
@Actor
public void actor2(I_Result r){
num = 2;
ready = true;
}
}
大家可以自行百度一下怎麼玩jcstress,這裡就不多說了,只說結果,因為java對程式碼進行了優化,所以有可能 ready = true;會在 num = 2;前面折行,得到了一個順序執行時不可能出現的結果(結果為0).
博主的堅持 離不開大家關注、評論和點贊,感謝大家支援。護髮路上互相扶持!!!