JAVA 併發編程—基礎2

對象的組合

###1、設計線程安全的類   在設計線程安全類的過程中,需要包含以下三個基本要素 - 找出構成對象狀態的所有變量。 - 找出約束狀態變量的不變性條件。 - 建立對象狀態的併發訪問策略。

  要分析對象的狀態,首先從對象的域開始。如果對象中所有的域都是基本類型的變量,那麼這些類將構成對象的全部狀態。
  同步策略定義瞭如何在不違背對象不變條件或後驗條件的情況下對其狀態的訪問操作進行協同。同步策略規定了如何將不可變性、線程封閉與加鎖機制等結合起來以維護線程的安全性。

###2、實例封閉
  如果對象不是線程安全的,可以通過多種技術使其在多線程程序中安全地使用。你可以確保對象只能由單個線程訪問,或者通過一個鎖保護對該對象的所有訪問。
  封裝簡化了線程安全類的實現過程,它提供了一種實例封閉機制。將數據封裝在對象內部,可以將數據的訪問限制在對象的方法上,從而更容易確保線程在訪問數據時總能持有正確的鎖。

###3、線程安全性的委託
  可以將類的線程安全性委託給單個線程安全的狀態變量。我們還可以將線程安全性委託給多個狀態變量,只要這些變量是彼此獨立的,即組合而成的類並不會在其包含的多個狀態變量上增加任何不變性條件。
  如果一個狀態變量是線程安全的,並且沒有任何不變性條件來約束它的值,在變量的操作上也不存在任何不允許的狀態轉換,那麼就可以安全地發佈這個變量。
  

###4、在現有的線程安全類中添加功能
  當爲現有的類添加一個原子操作時,有一個更好的辦法:組合。

構建基礎模塊

###1、同步容器類
  這些同步的封裝類是由Collections.synchronizedXxx等工廠方法創建的。

###2、併發容器
  同步容器將所有對容器狀態的訪問都串行化,以實現它們的線程安全性。這種方法的代價是嚴重降低併發性,當多個線程競爭容器的鎖時,吞吐量將嚴重降低。
  ConcurrentHashMap也是一個基於散列的Map,但它使用了一種完全不同的加鎖策略來提供更高的併發性和伸縮性。它在併發訪問環境下將實現更高的吞吐量,而在單線程環境中只損失非常小的性能。它提供的迭代器不會拋出ConcurrentModificationException,因此不需要在迭代過程中對容器加鎖。它返回的迭代器具有弱一致性。弱一致性的迭代器可以容忍併發的修改,當創建迭代器時會遍歷已有的元素,並可以(但是不保證)在迭代器被構造後將修改操作反映給容器。儘管有這些改進,但仍然有一些需要權衡的因素。對於一些需要在整個Map上進行計算的方法,例如size和isEmpty,這些結果在計算時可能已經過期了。只有當應用程序需要加鎖Map進行獨佔訪問時,才應該放棄使用ConcurrentHashMap。
  CopyOnWriteArrayList在每次修改時,都會創建並重新發佈一個新的容器副本,從而實現可變性。顯然,每當修改容器時都會複製底層數組,這需要一定的開銷,特別是當容器的規模較大時。僅當迭代操作遠遠多於修改操作時,才應該使用“寫入時複製”容器。

###3、阻塞隊列和生產者-消費者模式
  put方法的阻塞特性也極大地簡化了生產者的編碼。阻塞隊列同樣提供了一個offer方法,如果數據項不能被添加到隊列中,那麼將返回一個失敗狀態。這樣就能創建更多靈活的策略來處理負荷過載的情況。在構建高可用的應用程序時,有界隊列是一種強大的資源管理工具:它們能抑制並防止產生過多的工作項,是應用程序在負荷過載的情況下變得更加健壯。

###4、阻塞方法與中斷方法
  線程可能會阻塞或暫停執行,原因有多種:等待I/O操作結束,等待獲得一個鎖,等待從Thread.sleep方法中醒來,或是等待另一個線程的計算結束。

###5、同步工具類
  CountDownLatch,FutureTask,Semaphore,CyclicBarrier

###6、構建高效且可伸縮的結果緩存
  

第一部分小結

  • 可變狀態是至關重要的
      所有的併發問題都可以歸結爲如何協調對併發狀態的訪問。可變狀態越少,就越容易保證現行安全
  • 儘量將域聲明爲final類型,除非需要它們是可變的。
  • 不可變對象一定是線程安全的
      不可變對象能極大地降低併發編程的複雜性。它們更爲簡單而且安全,可以任意共享而無須使用加鎖或保護性複製等機制。
  • 封裝有助於管理複雜性
      在編寫線程安全的程序時,雖然可以將所有數據都保存在全局變量中,但爲什麼要這樣做?將數據封裝在對象中,更易於維持不變性條件;將同步機制封裝在對象中,更易於遵循同步策略。
  • 用鎖來保護每個可變變量
  • 當保護同一個不變性條件中的所有變量時,要使用同一個鎖
  • 在執行復合操作期間,要持有鎖
  • 如果從多個線程中訪問同一個可變變量時沒有同步機制,那麼程序會出現問題
  • 不要故作聰明的推斷出不需要使用同步
  • 在設計過程中考慮線程安全,或者在文檔中明確地指出它不是線程安全的
  • 將同步策略文檔化。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章