併發程式設計中的三個問題
阿新 • • 發佈:2020-07-09
可見性
package juc.synchronized_test; import java.util.concurrent.TimeUnit; /** * @author : 雪飛oubai * @date : 2020/4/9 11:07 * 目的:演示可見性問題 * 1、建立一個貢獻變數 * 2、建立一條執行緒不斷的讀取共享變數 * 3、建立一條執行緒修改共享變數 */ public class Test01Visibility {// 多個執行緒都會訪問的資料,我們稱為執行緒的共享資料 private static boolean flag = true; public static void main(String[] args) throws InterruptedException { new Thread(() -> { while(flag){ } }).start(); TimeUnit.SECONDS.sleep(1); new Thread(() -> { flag= false; System.out.println("時間到,執行緒2設定為false"); }).start(); } }
原子性
概念:原子性(Atomicity)在一次或多次操作中,要麼所有的操作都執行並且不會受其它因素影響,要麼所有的操作都不執行;
package juc.synchronized_test; import java.util.ArrayList; import java.util.List; /** * @author : 雪飛oubai * @date : 2020/4/9 11:27 * 目標:演示原子性問題 * 1、定義一個共享變數 number * 2、對number進行10000次 ++ 操作 * 3、使用 5 個執行緒來進行*/ public class Test02Atomicity { //1、定義一個共享變數 number private static int number = 0; public static void main(String[] args) throws InterruptedException { Runnable increment = () -> { for (int i = 0; i < 10000; i++) { number++; } }; List<Thread> list = new ArrayList<>(); for (int i = 0; i < 5; i++) { Thread t = new Thread(increment); t.start(); list.add(t); } for (Thread thread : list) { thread.join(); } System.out.println("number="+number); } }
其中,對於 number ++ 而言(number為靜態變數),實際會產生如下的JVM位元組碼指令
由此可見 number++ 是由多條語句組成,以上多條指令在一個執行緒的情況下不會出現問題,但是再多執行緒情況下就可能會出現問題。比如一個執行緒在執行 13:iadd時,另一個執行緒又執行 9:getstatic,會導致兩次number++,實際上只會加一次;
小結
併發程式設計會出現原子性問題,當一個執行緒對共享變數操作到一半時,另外的執行緒也有可能來操作共享變數,干擾了前一個執行緒的操作;
有序性
概念:有序性(Ordering)是指程式中程式碼的執行順序,Java在編譯時和執行時會對程式碼進行優化,會導致程式最終的執行順序不一定就是我們編寫程式碼時的順序;