1. 程式人生 > 其它 >1. 併發程式設計的三個問題

1. 併發程式設計的三個問題

技術標籤: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).

博主的堅持 離不開大家關注、評論和點贊,感謝大家支援。護髮路上互相扶持!!!