JAVA學習筆記--4.多線程編程 part5.這些年的那些坑
基本要求
- 沒指定線程name。
- 沒有限定線程個數。
- Thread#stop等被廢棄的方法不安全,詳見TODO。
- 注意鎖做用的對象。1.
synchronized (new Object()) {}
這段代碼其實不會執行任何操做,你的編譯器會把它徹底移除掉,由於編譯器知道沒有其餘的線程會使用相同的監視器進行同步。TODO
- voliate i++是線程非安全,屬於Read-Modify-Write操做,每個步驟計算的計算的結果依賴前一個步驟的狀態。
- 注意java命令行的client server 的參數區別,詳見TODO。
- 注意鎖的力度,儘可能減小臨界區的大小;經過縮小同步範圍,而且而且應該儘可能將不影響共享狀態的操做從同步代碼分離出去。
- 注意組合的原子操做並非線程安全的。如
if(!vector.contains(element)) 。vector.add(element);
也就是說,"若是不存在那麼添加"操做存在競態條件,須要額外的鎖機制。
- 直接拋出中斷異常;捕獲異常,處理後再拋出中斷異常;設置中斷狀態,業務程序檢查該狀態。
- 注意在CAS的ABA問題,主要在鏈表中危害較大。可使用AtomicStampedReference來規避。
線程通訊
- 一旦線程調用了wait()方法,它就釋放了所持有的監視器對象上的鎖.一旦一個線程被喚醒,不能馬上就退出wait()的方法調用,直到調用notify()的線程退出了它本身的同步塊。換句話說:被喚醒的線程必須從新得到監視器對象的鎖,才能夠退出wait()的方法調用,由於wait方法調用運行在同步塊裏面。若是多個線程被notifyAll()喚醒,那麼在同一時刻將只有一個線程能夠退出wait()方法,由於每一個線程在退出wait()前必須得到監視器對象的鎖。
- 爲了不信號丟失, 用一個變量來保存是否被通知過。在notify前,設置本身已經被通知過。在wait後,設置本身沒有被通知過,須要等待通知。
- 在wait()/notify()機制中,不要使用全局對象,字符串常量等。應該使用對應惟一的對象。
- 因爲莫名其妙的緣由,線程有可能在沒有調用過notify()和notifyAll()的狀況下醒來。這就是所謂的(虛)假喚醒(spurious wakeups).
- 注意死鎖:死鎖是兩個或更多線程阻塞着等待其它處於死鎖狀態的線程所持有的鎖。死鎖一般發生在多個線程同時但以不一樣的順序請求同一組鎖的時候。當多個線程須要相同的一些鎖,可是按照不一樣的順序加鎖,死鎖就很容易發生。若是能確保全部的線程都是按照相同的順序得到鎖,那麼死鎖就不會發生。可是須要注意,嵌套管程鎖死時鎖獲取的順序是一致的.嵌套管程鎖死中,線程1持有鎖A,同時等待從線程2發來的信號,線程2須要鎖A來發信號給線程1。
- 避免飢餓。飢餓的緣由:1.無CPU時間2.等待鎖3.處於wait狀態,沒法被notify。
- 注意驚羣現象
- 避免虛假喚醒,使用while(condition)
JUC類庫
- 線程池是先指定core size,而後填滿隊列,最後再到max size。因此要注意參數的合理設置。
- 沒指定默認隊列大小。
- 在線程池狀況下,沒有在finally中調用ThreadLocal#remove方法,或者ThreadLocal不是static變量
- 須要注意在使用await()和signal()方法時,若是你在condition上調用await()方法而卻沒有在這個condition上調用signal()方法,這個線程將永遠睡眠下去。
設計思路
- 儘可能使服務無狀態,這樣可使用單例,避免多線程併發問題,同時也能夠節省CPU和內存的開銷。
- 儘可能避免僞共享問題,能夠經過padding來規避。
參考
安全構造對象html
當構造函數泄露this指針時java
歡迎關注本站公眾號,獲取更多信息