介紹
我比較認同的線程安全的定義: "一段代碼, 被多線程訪問, 多線程之間不需要任何顯式的協同, 並且運行結果是正確的, 那麼這段代碼就是線程安全的".
線程安全的程度
- Immutable: 不可變
- Thread-safe: 單線程下行爲正確, 任何的執行序列都無法將實例帶到一個非法狀態; 多線程下也要繼續延續該特性, 這個要求很高
- Conditionally thread-safe: 有條件的線程安全, 在某些條件下線程安全, 比如Vector的所有方法都是synchronized, 但併發訪問時還是會出問題, 比如先獲取size再get可能會NPE.
- Thread-Compitable: 線程兼容, 本來非多線程安全, 但可以通過顯示的外部同步來獲得安全(並且行爲正確), 大部分實例都是這樣.
- Thread-hostile: 很少見, 線程敵對, 一定非線程安全的(比如輸出輸出流), 我也不懂了, 直接看原文吧.
如何實現線程安全
根據我的經驗, 有以下幾個建議:
- 使用不可變對象
- 使用無狀態設計
- 讓調用方維護狀態(狀態是入參): 比如HTTP的cookie. 用得不好的話會被認爲是推卸責任, 取決於具體設計, 狀態總工會有人要存的, 逃不掉...
- 結合框架的線程模型進行具體考慮
- 比如Netty裏, 一個Channel在其生命週期內只會被一個EventLoop調度.
- 還要結合各個項目的具體設計了, 有的代碼看起來是不安全的, 但實際(邏輯上)上並不會被併發調用.
- 原子操作
- 原子計數器
- 併發安全集合
- 鎖
- 阻塞型集合