在Java并發編程中,as - if - serial
與 happens - before
原則是確保程序在多線程環境下正確執行的重要規則,下面為你詳細講解:
as - if - serial原則
- 定義:
as - if - serial
原則是指,不管編譯器和處理器如何優化,單線程程序的執行結果都不能被改變。編譯器、處理器會遵守這個原則對單線程程序的執行順序進行優化,保證最終執行結果和代碼按照順序執行的結果一致。 - 目的:它的主要目的是在不改變程序執行結果的前提下,盡可能地提高單線程程序的執行效率。因為在單線程環境下,程序員無需擔心多線程帶來的并發問題,編譯器和處理器可以通過重排序等優化手段,讓程序運行得更快。
- 示例:
int a = 1;
int b = 2;
int c = a + b;
在這個簡單的單線程代碼片段中,編譯器和處理器可能會對指令進行重排序。例如,它們可能先執行 int b = 2;
,再執行 int a = 1;
,最后執行 int c = a + b;
。但無論如何重排序,最終 c
的值都會是 3
,不會影響程序的執行結果,這就是 as - if - serial
原則的體現。
happens - before原則
- 定義:
happens - before
原則是Java內存模型(JMM)中定義的一種偏序關系,用于描述兩個操作之間的內存可見性。如果操作Ahappens - before
操作B,那么操作A的執行結果對操作B是可見的,并且操作A的執行順序在操作B之前。這里的“可見”不僅包括數據的可見性,還包括對內存操作順序的保證。 - 具體規則:
- 程序順序規則:在一個線程內,按照代碼順序,書寫在前面的操作
happens - before
書寫在后面的操作。例如:
- 程序順序規則:在一個線程內,按照代碼順序,書寫在前面的操作
int a = 1; // 操作A
int b = a + 1; // 操作B
這里操作A happens - before
操作B,因為在同一個線程內,代碼順序決定了執行順序和可見性。
- 監視器鎖規則:對一個鎖的解鎖操作 happens - before
后續對這個鎖的加鎖操作。例如:
synchronized (this) {// 臨界區1,鎖的加鎖操作int a = 1;
} // 鎖的解鎖操作synchronized (this) {// 鎖的加鎖操作int b = a + 1; // 這里能看到臨界區1中a的賦值結果
}
第一個 synchronized
塊的解鎖操作 happens - before
第二個 synchronized
塊的加鎖操作,所以第二個 synchronized
塊能看到第一個 synchronized
塊中對 a
的賦值。
- volatile變量規則:對一個 volatile
變量的寫操作 happens - before
后續對這個 volatile
變量的讀操作。例如:
volatile int a;Thread thread1 = new Thread(() -> {a = 1; // 對volatile變量a的寫操作
});Thread thread2 = new Thread(() -> {int b = a; // 對volatile變量a的讀操作,能看到thread1中對a的賦值
});
由于 a
是 volatile
變量,所以 thread1
中對 a
的寫操作 happens - before
thread2
中對 a
的讀操作。
- 線程啟動規則:Thread
對象的 start()
方法 happens - before
此線程的每一個動作。例如:
Thread thread = new Thread(() -> {int a = 1;
});
thread.start(); // start()方法happens - before線程內部的操作
start()
方法的調用 happens - before
線程內部對 a
的賦值操作,保證線程啟動后能正確執行內部代碼。
- 線程終止規則:線程中的所有操作都 happens - before
對此線程的終止檢測。例如:
Thread thread = new Thread(() -> {int a = 1;
});
thread.start();
thread.join(); // 等待線程終止,線程內部所有操作happens - before這里
thread.join()
能保證在其之前線程內部的所有操作都已完成。
- 線程中斷規則:對線程 interrupt()
方法的調用 happens - before
被中斷線程的代碼檢測到中斷事件的發生。例如:
Thread thread = new Thread(() -> {while (!Thread.currentThread().isInterrupted()) {// 循環}
});
thread.start();
thread.interrupt(); // interrupt()方法調用happens - before線程內部對中斷的檢測
interrupt()
方法的調用 happens - before
線程內部對中斷狀態的檢測。
- 對象終結規則:一個對象的初始化完成(構造函數執行結束) happens - before
它的 finalize()
方法的開始。
3. 作用:happens - before
原則為多線程編程提供了一種內存可見性的保障機制。通過這些規則,程序員可以判斷在多線程環境下,一個操作的結果是否對另一個操作可見,從而避免數據競爭和其他并發問題。同時,它也為編譯器和處理器的優化提供了一定的限制,即優化不能違反 happens - before
原則,以確保多線程程序的正確性。
as - if - serial
原則主要針對單線程程序的優化,而 happens - before
原則則重點解決多線程環境下的內存可見性和操作順序問題,兩者共同保證了Java程序在不同執行環境下的正確性和高效性。