JAVA編程中29個保證線程安全的方法。

1,保證線程安全的三種方法:a,不要跨線程訪問共享變量b,使共享變量是final類型的c,將共享變量的操作加上同步。

2,一開始就將類設計成線程安全的,比在後期重新修復它,更容易。

3,編寫多線程程序,首先保證它是正確的,其次再考慮性能。

4,無狀態或只讀對象永遠是線程安全的。

5,不要將一個共享變量裸露在多線程環境下(無同步或不可變性保護)

6,多線程環境下的延遲加載需要同步的保護,因爲延遲加載會造成對象重複實例化

7,對於volatile聲明的數值類型變量進行運算,往往是不安全的(volatile只能保證可見性,不能保證原子性)。詳見volatile原理與技巧中,髒數據問題討論。

8,當一個線程請求獲得它自己佔有的鎖時(同一把鎖的嵌套使用),我們稱該鎖爲可重入鎖。在jdk1.5併發包中,提供了可重入鎖的java實現-ReentrantLock。

9,每個共享變量,都應該由一個唯一確定的鎖保護。創建與變量相同數目的ReentrantLock,使他們負責每個變量的線程安全。

10,雖然縮小同步塊的範圍,可以提升系統性能。但在保證原子性的情況下,不可將原子操作分解成多個synchronized塊。

11,在沒有同步的情況下,編譯器與處理器運行時的指令執行順序可能完全出乎意料。原因是,編譯器或處理器爲了優化自身執行效率,而對指令進行了的重排序(reordering)。

12,當一個線程在沒有同步的情況下讀取變量,它可能會得到一個過期值,但是至少它可以看到那個線程在當時設定的一個真實數值。而不是憑空而來的值。這種安全保證,稱之爲最低限的安全性(out-of-thin-air safety)在開發併發應用程序時,有時爲了大幅度提高系統的吞吐量與性能,會採用這種無保障的做法。但是針對,數值的運算,仍舊是被否決的。

13,volatile變量,只能保證可見性,無法保證原子性。

14,某些耗時較長的網絡操作或IO,確保執行時,不要佔有鎖。

15,發佈(publish)對象,指的是使它能夠被當前範圍之外的代碼所使用。(引用傳遞)對象逸出(escape),指的是一個對象在尚未準備好時將它發佈。

  原則:爲防止逸出,對象必須要被完全構造完後,纔可以被髮布(最好的解決方式是採用同步)

  this關鍵字引用對象逸出

  例子:在構造函數中,開啓線程,並將自身對象this傳入線程,造成引用傳遞。而此時,構造函數尚未執行完,就會發生對象逸出了。

16,必要時,使用ThreadLocal變量確保線程封閉性(封閉線程往往是比較安全的,但一定程度上會造成性能損耗)封閉對象的例子在實際使用過程中,比較常見,例如hibernate openSessionInView機制,jdbc的connection機制。

17,單一不可變對象往往是線程安全的(複雜不可變對象需要保證其內部成員變量也是不可變的)良好的多線程編程習慣是:將所有的域都聲明爲final,除非它們是可變的

18,保證共享變量的發佈是安全的a,通過靜態初始化器初始化對象(jls 12.4.2敘述,jvm會保證靜態初始化變量是同步的)b,將對象申明爲volatile或使用AtomicReference c,保證對象是不可變的d,將引用或可變操作都由鎖來保護

19,設計線程安全的類,應該包括的基本要素:a,確定哪些是可變共享變量b,確定哪些是不可變的變量c,指定一個管理併發訪問對象狀態的策略

20,將數據封裝在對象內部,並保證對數據的訪問是原子的。建議採用volatile javabean模型或者構造同步的getter,setter。

21,線程限制性使構造線程安全的類變得更容易,因爲類的狀態被限制後,分析它的線程安全性時,就不必檢查完整的程序。

22,編寫併發程序,需要更全的註釋,更完整的文檔說明。

23,在需要細分鎖的分配時,使用java監視器模式好於使用自身對象的監視器鎖。前者的靈活性更好。

  Object target = new Object();

  // 這裏使用外部對象來作爲監視器,而非this

  synchronized(target) {

  // TODO

  }

   針對java monitor pattern,實際上ReentrantLock的實現更易於併發編程。功能上,也更強大。

24,設計併發程序時,在保證伸縮性與性能折中的前提下,優先考慮將共享變量委託給線程安全的類。由它來控制全局的併發訪問。

25,使用普通同步容器(Vector,Hashtable)的迭代器,需要外部鎖來保證其原子性。原因是,普通同步容器產生的迭代器是非線程安全的。

26,在併發編程中,需要容器支持的時候,優先考慮使用jdk併發容器(ConcurrentHashMap,ConcurrentLinkedQueue,CopyOnWriteArrayList。。。)。

27,ConcurrentHashMap,CopyOnWriteArrayList併發容器的迭代器,以及全範圍的size(),isEmpty()都表現出弱一致性。他們只能標示容器當時的一個數據狀態。無法完整響應容器之後的變化和修改。

28,使用有界隊列,在隊列充滿或爲空時,阻塞所有的讀與寫操作。(實現生產-消費的良好方案)BlockQueue下的實現有LinkedBlockingQueue與ArrayBlockingQueue,前者爲鏈表,可變操作頻繁優先考慮,後者爲數組,讀取操作頻繁優先考慮。PriorityBlockingQueue是一個按優先級順序排列的阻塞隊列,它可以對所有置入的元素進行排序(實現Comparator接口)

29,當一個方法,能拋出InterruptedException,則意味着,這個方法是一個可阻塞的方法,如果它被中斷,將提前結束阻塞狀態。當你調用一個阻塞方法,也就意味着,本身也稱爲了一個阻塞方法,因爲你必須等待阻塞方法返回。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章