1. 爲何要併發
a) 併發是一種解耦策略。他幫助咱們吧作什麼(目的)和什麼時候作(時機)分解開。
b) 在web應用的servlet模式下,當有web請求時,servlet就會異步執行。
2. 挑戰
a) 當兩個線程相互影響時就會出現不可預期的狀況。這是由於線程在執行那行java代碼時有許多可能路徑可行,有些路徑會產生錯誤的結果。回答這個問題須要理解 Just-IN-Time編譯器如何對待生成的字節碼,還java
要理解java內存模型認爲何東西具備原子性
3. 併發防護原則
a) SRP
i. 併發相關的代碼有本身的開發,修改和調優生命週期
ii. 開發相關代碼有本身要對付的挑戰,和非併發代碼不一樣
iii. 即使沒有周邊應用程序增長的負擔,寫的很差的併發代碼可能的出錯方式數量也足夠挑戰性
iv. 建議:分離併發代碼和其餘代碼
b) 推論:限制數據做用域
i. 謹記數據封裝;嚴格限制對可能被共享的數據的訪問
c) 推論:使用數據複本
i. 從一開始就避免共享數據,從多線程收集全部副本的結果,並在單個線程中合併這些結果
d) 推論:線程應儘量地獨立
i. 嘗試將數據分解到可被獨立線程(可能在不一樣處理器上)操做的獨立子集
4. 瞭解java庫
a) 線程安全羣集
i. Java.util.concurrent, java.util.concurrent.atomic java.util.concurrent.locks
5. 瞭解執行模型
a) web
b) 生產者-消費者模型
c) 讀者-做者模型 (吞吐量和正常操做)
d) 宴席哲學家
6. 警戒同步方法之間的依賴
數據庫
7. 保持同步區域微小
8. 很難編寫正確的關閉代碼
a) 考慮正常關閉問題
9. 測試線程代碼
a) 不要將系統錯誤歸咎於偶發事件
b) 不要追蹤非線程缺陷和線程缺陷。確保代碼能夠在線程以外工做
c) 編寫可插拔的線程代碼,這樣就能在不一樣的配置環境運行編程
附錄:
A1:客戶端/服務器段例子
安全
對於併發編程,因其複雜性,應該將所有代碼,根據SRP,放到少數類中。服務器
A2:可能執行的路徑
多線程
理解線程之間如何相互干涉,並不必定要精通字節碼文件,只須要知道多個線程之間互相干涉的可能性。
有必要理解內存模型,明白什麼是安全的,什麼是不安全的。
必須知道什麼地方有共享對象/值;哪些代碼會致使併發讀/寫的問題;如何防止這種併發問題發生。併發
A3: 瞭解類庫
異步
3.2:非鎖定的解決方案:測試
原子類。
CAS(compare and swap )機制,相似於數據庫中的樂觀鎖定,而其同步版本相似於保守鎖定。
3.3非線程安全類:
數據庫鏈接、java.util容器、servlet
A4:方法之間的依賴可能破壞併發代碼
多線程調用的時候,hasnext()的地方可能擊穿
解決的方法:
容忍錯誤: 至關於電腦壞了重啓電腦,並不能解決問題
基於客戶端代碼的鎖定: 不可靠
基於服務端的修改:
可使用下述方法不改變客戶端接口:
A5:提高吞吐量