多執行緒和併發。
- 不推薦覆寫start方法
- 啟動執行緒前stop方法是不可靠的
- 不使用stop方法停止執行緒
有以下三個問題:
1、stop方法是過時的
2、stop方法會導致程式碼邏輯不完整
3、stop方法會破壞原子邏輯
如果期望終止一個正在執行的執行緒,則不能使用已經過時的stop方法,需要自行編碼實現,如此即可保證原子邏輯不被破壞,程式碼邏輯不會出現異常。當然,如果我們使用的是執行緒池(比如ThreadPoolExecutor類),那麼可以通過shutdown方法逐步關閉池中的執行緒,他採用的是比較溫和、安全的關閉執行緒方法,完全不會產生類似stop方法的弊端。
- 執行緒優先順序只使用三個等級
- 使用執行緒異常處理器提升系統可靠性
Java 1.5版本以後在Thread類中增加了setUncaughtExceptionHandler方法,實現了執行緒異常的捕捉和處理。
實際環境中應用,需要注意以下三個方面:
1、共享資源鎖定
2、髒資料引起系統邏輯混亂
3、記憶體溢位
- volatile不能保證資料同步
- 非同步運算考慮使用Callable介面
從Java 1.5開始引入了一個新的介面Callable,他類似於Runable介面,實現他就可以實現多執行緒任務。
此類非同步計算的好處是:
1、儘可能多地佔用系統資源,提供快速運算。
2、可以監控執行緒執行的情況,比如是否執行完畢、是否有返回值、是否有異常等。
3、可以為使用者提供更好的支援,比如例子中的運算進度等。
- 優先選擇執行緒池
一個執行緒的執行時間分為三部分:T1為執行緒啟動時間,T2為執行緒體的執行時間,T3為執行緒銷燬時間,如果一個執行緒不能被重複使用,每次建立一個執行緒都需要經過啟動、執行、銷燬這三個過程,那麼這勢必會增大系統的響應時間,有沒有更好的辦法降低執行緒的執行時間呢?
T2是無法避免的,只有通過優化程式碼來實現降低執行時間。T1和T2都可以通過執行緒池(Thread Pool)來縮減時間,比如在容器(或系統)啟動時,建立足夠多的執行緒,當容器(或系統)需要時直接從執行緒池中獲得執行緒,運算出結果,再把執行緒返回到執行緒池中。
執行緒池的建立過程:建立一個阻塞佇列以容納任務,在第一次執行任務時建立足夠多的執行緒(不超過許可執行緒數),並處理任務,之後每個工作執行緒自行從任務佇列中獲得任務,直到任務佇列中的任務數量為0為止,此時執行緒將處於等待狀態,一旦有任務再加入到佇列中,即喚醒工作執行緒進行處理,實現執行緒的可複用性。
使用執行緒減少的是執行緒的建立和銷燬時間。
- 適時選擇不同的執行緒池來實現、
Java的執行緒池實現從最根本上來說只有兩個:ThreadPoolExecutor類和ScheduledThreadPoolExecutor類,這兩個類還是父子關係,但是Java為了簡化平行計算,還提供了一個Executors的靜態類,他可以直接生成多種不同的執行緒池執行器,比如單執行緒執行器、帶緩衝功能的執行器等,但歸根結底還是使ThreadPoolExecutor類或ScheduledThreadPoolExecutor類的封裝性。
newSingleThreadExecutor、newCachedThreadPool、newFixedThreadPool是執行緒的簡化版,而ThreadPoolExecutor則是旗艦版——簡化版更容易操作,需要了解的知識相對少些,方便實用,而且旗艦版功能齊全,適用面廣,但難於駕馭。
- Lock與synchronized是不一樣的
顯示鎖和內部鎖的不同之處:
1、Lock支援更細粒度的鎖控制
2、Lock是無阻塞鎖,synchronized是阻塞鎖
3、Lock可實現公平鎖,synchronized只能是非公平鎖
4、Lock是程式碼級的,synchronized是JVM級的
根據實際情況考慮:靈活、強大則選擇Lock,快捷、安全則選擇synchronized。
- 預防執行緒死鎖
在我們Java多執行緒併發程式設計中,死鎖很難避免,也不容易預防,對付他的最好辦法是測試:提高測試覆蓋率,建立有效地邊界測試,加強資源監控,這些方法能使死鎖無處遁形,即使發生了死鎖現象也能迅速查詢到原因,提高系統的可靠性。
- 適當設定阻塞佇列長度
- 使用CountDownLatch協調子執行緒
- CyclicBarrier讓多執行緒齊步走