並發學習筆記10-happens-before
- 2020 年 1 月 22 日
- 筆記
該並發學習系列以閱讀《Java並發編程的藝術》一書的筆記為藍本,彙集一些閱讀過程中找到的解惑資料而成。這是一個邊看邊寫的系列,有興趣的也可以先自行購買此書學習。 本文首發:[windCoder]( https://windcoder.com/bingfaxuexibiji10-happens-before "windCoder")
JMM把happens-before要求禁止的重排序分為下面兩類: - 會改變程式執行結果的重排序; - 不會改變程式執行結果的重排序。
JMM對這兩種不同性質的重排序採取了如下不同的策略: - 對於會改變程式執行結果的重排序,JMm要求編譯器和處理器必須禁止這種重排序。 - 對於不會改變程式執行結果的重排序,JMM對編譯器和處理器不做要求(即允許這種)。

happens-before關係的定義如下: - 如果一個操作happens-before另一個操作,那麼第一個操作的執行結果將對第二個操作可見,而第一個操作的執行順序排在第二個操作之前。 - 兩個操作之間存在happens-before關係,並不意味著Java平台的具體實現必須要按照happens-before關係指定的順序來執行。如果重排序之後的執行結果,與按happens-before關係來執行的結果一致,那麼這種重排序並不非法(即允許這種重排序)。
1是JMM對程式設計師的承諾,2是JMM對編譯器和處理器重排序的約束規則。happens-before關係本質上和as-if-serial語義是一回事:
as-if-serial | happens-before | |
|---|---|---|
保證 | 單執行緒內程式的執行結果不被改變。 | 正確同步的多執行緒程式的執行結果不被改變。 |
幻境 | 單執行緒程式是按程式的順序來執行的。 | 正確同步的多執行緒程式是按照happens-before指定的順序來執行的。 |
happens-before規則
- 程式順序規則:一個執行緒中的每個操作,happens-before於該執行緒中的任意後續操作。
- 監視器鎖規則:對一個鎖的解鎖,happens-before於隨後對這個鎖的加鎖。
- volatile變數規則:對一個volatile域的寫,happens-before於任意後續對這個volatile域的讀。
- 傳遞性:如果A happens-before B,且B happens-before C,那麼A happens-before C。
- start()規則:如果執行緒A執行操作ThreadB.start()(啟動執行緒B),那麼A執行緒的THreadB.start()操作happens-before於執行緒B中的任意操作。
- join()規則:如果執行緒A執行操作ThreadB.join()並成功返回,那麼執行緒B中的任意操作happens-before於執行緒A從ThreadB.join()操作成功返回。
start()規則意味著執行緒A在執行ThreadB.start()之前對共享變數所做的修改,接下來在B執行緒開始執行後都將確保對執行緒B可見。
join()規則意味著執行緒A執行操作ThreadB.join()並成功返回後,執行緒B中的任意操作都將對執行緒A可見。

