第一章

  1. 執行緒會共享程序範圍內的資源,例如記憶體控制代碼和檔案控制代碼,但每個執行緒都有各自的程式計數器(Program Counter)、棧以及區域性變數。
  2. 通過使用執行緒,可以將複雜並非同步的工作進一步分解為一組簡單並且同步的工作流,每個工作流在一個單獨的執行緒中執行,並在特定的同步位置進行互動。現有的一些框架可以實現上述目標,例如Servlet和RMI(Remote Mothod Invocation,遠端方法呼叫)。
  3. 安全性的含義是“永遠不發生糟糕的事情”,而活躍性則關注另一個目標,即“某件正確的事情最終會發生”。當某個操作無法繼續執行下去時,就會發生活躍性問題。在序列程式中,活躍性問題的形式之一就是無意中造成的無限迴圈。
  4. 與活躍性問題密切相關的是效能問題。活躍性意味著某件正確的事情最終會發送,但卻不夠好,因為我們希望正確的事情儘快傳送。

第二章

  1. 要編寫執行緒安全的程式碼,其核心在於要對狀態訪問操作進行管理,特別是對共享的(Shared)和可變的(Mutable)狀態的訪問。
  2. 如果當多個執行緒訪問同一個可變的狀態變數時沒有使用合適的同步,那麼程式就會出現錯誤,有3中方式可以修復這個問題:
    i. 不線上程之間共享該變數。
    ii. 將狀態變數修改為不可變的變數。
    iii. 在訪問狀態變數時使用同步。
  3. 在編寫併發程式碼時,應始終遵循一個原則:首先使程式碼正確執行,然後才提高程式碼的執行速度。即便如此,最好也是當效能測試結果和應用需求告訴你必須提高效能,以及測量結果表明這種優化在實際環境中確實能帶來效能提升時,才進行優化。
  4. 線上程安全性的含義中,最核心的概念就是正確性,而正確性的含義是:某個類的行為與其規範完全一致。在良好的規範中通常會定義各種不變性條件(Invariant)來約束物件的狀態,以及定義各種後驗條件(Postcondition)來描述物件操作的結果。
  5. 當多個執行緒訪問某個類時,這個類始終都能表現出正確的行為,那麼就稱這個類是執行緒安全的。
  6. 無狀態物件一定是執行緒安全的。無狀態:既不包含任何域,也不包含任何對其他類中域的引用。
  7. 競態條件:在併發程式設計中,這種由於不恰當的執行時序而出現不正確的結果是一種非常重要的情況。
  8. 假定有兩個操作A和B,如果從執行A的執行緒來看,當另一個執行緒執行B時,要麼將B全部執行完,要麼完全不執行B,那麼A和B對彼此來說都是原子的。原子操作是指,對於訪問同一個狀態的所有操作(包括該操作本身)來說,這個操作是一個以原子方式執行的操作。
  9. 複合操作:包含了一組必須以原子方式執行的操作以確保執行緒安全性。
  10. 在實際情況中,應儘可能使用現有的執行緒安全物件(例如AtomicLong)來管理類的狀態。與非執行緒安全的物件相比,判斷執行緒安全物件的可能狀態及其狀態轉換情況要更為容易,從而也更容易驗證和維護執行緒安全性。
  11. 每個Java物件都可以用做一個實現同步的鎖,這些鎖被稱為內建鎖(Intrinsic Lock)或監視器鎖(Monitor Lock)。
  12. Java的內建鎖相當於一種互斥體(或互斥鎖),這意味著最多隻有一個執行緒能持有這個鎖。
  13. 內建鎖是可以重入的,因此如果某個執行緒試圖獲得一個已經有它自己持有的鎖,那麼這個請求就會成功。
  14. 對於可能被多個執行緒同時訪問的可變狀態變數,在訪問它時都需要持有同一個鎖,我們稱狀態變數是由這個鎖保護的。
  15. 每個共享的和可變的變數都應該只由一個鎖來保護,從而使維護人員知道是哪一個鎖。一種常見的加鎖約定是,將所有的可變狀態都封裝在物件內部,並通過物件的內建鎖對所有訪問可變狀態的程式碼路徑進行同步,使得在該物件上不會發生併發訪問。
  16. 在獲取與釋放鎖等操作上都需要一定的開銷,因此如果將同步程式碼塊分解的過細,那麼通常並不好,儘管這樣不會破壞原子性。
  17. 當執行時間較長的計算或者可能無法快速完成的操作時,一定不要持有鎖。

第三章

  1. Synchronized關鍵字不止能用於實現原子性或者確定“臨界區(Critical Section)”,還有另一個重要的方面:記憶體可見性(Memory Visibility)。
  2. 僅當volatile變數能簡化程式碼的實現以及對同步策略的驗證時,才應該使用它們。如果在驗證正確性時需要對可見性進行復雜的判斷,那麼就不要使用volatile變數。Volatile變數的正確使用方式包括:確保它們自身狀態的可見性,確保它們所引用物件的狀態的可見性,以及標識一些重要的程式生命週期事件的發生。
  3. 加鎖機制既可以確保可見性又可以確保原子性,而volatile變數只能確保可見性。
  4. 當且僅當滿足以下所有條件時,才應該使用volatile變數:
    i. 對變數的寫入操作不依賴變數的當前值,或者你能確保只有單個執行緒更新變數的值。
    ii. 該變數不會與其他狀態變數一起納入不變性條件中。
    iii. 在訪問變數時不需要加鎖。
  5. 釋出(publish)一個物件的意思是指,是物件能夠在當前作用域之外的程式碼中使用。
  6. 逸出(Escape):當某個不應該釋出的物件被髮布時。
  7. 執行緒封閉:如果僅在單執行緒內訪問資料,就不需要同步。它是實現執行緒安全性的最簡單方式之一。
  8. Ad-hoc執行緒封閉:指維護執行緒封閉性的職責完全由程式實現來承擔。非常脆弱。程式中儘量少用。
  9. 棧封閉:它是執行緒封閉的一種特例,在棧封閉中,只能通過區域性變數才能訪問物件。區域性變數的固有屬性之一就是封閉在執行執行緒中。它們位於執行執行緒的棧中,其他執行緒無法訪問這個棧。
  10. ThreadLocal類:維護執行緒封閉性的一種更規範的方法是使用ThreadLocal類,這個類能使執行緒中的某個值與儲存值的物件關聯起來。ThreadLocal提供了get與set等訪問介面或方法,這些方法為每個使用該變數的執行緒都存有一份獨立的副本,因此get總是返回由當前執行執行緒在呼叫set時設定的最新值。
  11. ThreadLocal物件通常用於防止對可變的單例項變數或全域性變數進行共享。從概念上看,你可以將ThreadLocal視為包含了Map
.