Java併發編程番外篇(二)happens-before關係

Java 併發編程(三)同步中,提到了內存一致性錯誤,而避免內存一致性錯誤的關鍵就是了解happens-before關係。那麼什麼是happens-before關係呢?如何判斷兩個操作是否存在happends-before關係呢?本文將來介紹這兩個方面。

1. happens-before關係

Wikipedia, Happened-before是這樣定義的:

In computer science, the happened-before relation (denoted: ->) is a relation between the result of two events, such that if one event should happen before another event, the result must reflect that, even if those events are in reality executed out of order (usually to optimize program flow).

簡答翻譯一下,就是:

在計算機科學領域,happened-before是指兩個事件結果的關係(用->表示),如果一個事件發生在另一個事件之前,那麼第一個事件的結果必須影響到第二個事件,即使這事件實際並不按順序執行(通常用來優化程序流程)。

在Java規範中,happened-before保證了語句A內存的寫入對語句B是可見的,也就是在B開始讀數據之前,A已經完成了數據的寫入。

happends-before關係滿足傳遞性非自反性非對稱性,即:

  • 任意的a,b,c,如果a->b,b->c,那麼a->c;
  • 任意的a,a->a永遠不會成立。
  • 任意的a,b,如果a->b,那麼b->a不會成立。

2. 如何判斷happens-before關係

根據Java SE 8 Docs, Memory Consistency Properties,synchronized,volatile,Thread.start()和Thread.join() 方法可以形成happens-before關係,特別是:

  • 一個線程中的語句和它之後的語句之間存在happens-before關係;
  • 一個鎖的釋放(同步塊或者方法的退出)和該鎖的後續獲得(同步塊或者方法的進入)存在happens-before關係;
  • volatile變量的寫與該域後續的讀操作存在happens-before關係;
  • 開啓線程的語句域線程中的語句存在happens-before關係;
  • 線程中的所有操作與該線程join返回的其他線程存在happens-before關係。

java.util.concurrent中的類及其子類的方法保證了高級別的同步,特別是:

  • 任何併發集合的寫操作與該集合的後續訪問或者刪除操作存在happens-before關係;
  • 線程中提交Runnable到Executor之前的代碼與Runnable中的代碼存在happens-before關係。對提交Callable到ExecutorService也一樣;
  • 一個Future代表的異步計算和另一個線程中Future.get()的後續操作存在happens-before關係;
  • 釋放同步方法(比如Lock.unlock,Semaphore.release和 CountDownLatch.countDown)之前的代碼和隨後的在相同對象上的獲得方法(比如Lock.lock, Semaphore.acquire, Condition.await和 CountDownLatch.await)存在happens-before關係;
  • 通過Exchanger成功交換對象的線程對,exchange()之前的代碼和exchange()之後的代碼存在happens-before關係;
  • 調用CyclicBarrier.await和Phaser.awaitAdvance之前的代碼和執行barrier操作存在happens-before關係;執行barrier操作和其他線程中對應await返回後的代碼存在happens-before關係。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章