Java保證執行緒安全的方式有哪些?
一位工作5年的小夥伴面試時被問到這樣一道題,說Java保證執行緒安全的方式有哪些?
今天,我給大家分享一下我的理解。
1、執行緒不安全的原因
回答這個問題之前,得先了解導致物件執行緒不安全的原因,主要有三個:
- 原子性:一個或者多個操作在CPU執行過程中被中斷。
- 可見性:一個執行緒物件共享變數的修改,導致另一個執行緒不能立即看到。
- 有序性:程式執行的順序沒有按照程式碼的先後順序執行。
原子性和可見性比較容易理解,重點分析一下有序性。為什麼程式執行的順序會和程式碼的編寫順序不一致呢?這就得理解Java平臺的兩種編譯器,靜態編譯器javac和動態編譯器jit(just in time)。
靜態編譯器是將.java檔案編譯成.class檔案,JVM載入後就可以執行了。
而動態編譯器是要將.class檔案編譯成機器碼,再由JVM執行。有時候,動態編譯器為了程式的整體效能會對指令進行重排序,但是,這又會導致原始碼中指定的記憶體訪問順序和實際的執行順序不一致,就會出現執行緒不安全的問題。
2、如何保證執行緒安全
那麼,針對以上三種情況,如何保證物件的執行緒安全呢?
第1個,針對原子性。
(1)JDK提供了非常多的Atomic類,比如AtomicInteger、AtomicLong、AtomicBoolean等等。這些類都是通過CAS來保證原子性。
(2)另外,Java還提供了各種鎖機制,來保證鎖內的程式碼塊在同一時刻只能被一個執行緒執行。比如用synchronized加鎖。這樣,就可以保證一個執行緒對資源進行讀、寫操作時,其他執行緒不可以對這個資源進行操作,從而保證了執行緒安全。
第2個,針對可見性。
同樣可以使用synchronized關鍵字加鎖來解決。與此同時,Java提供了volatile關鍵字。它要優於synchronized的效能,同樣也可以保證修改後對其他執行緒可見。volatile一般用於對變數的寫操作,不依賴於當前值的場景中,比如狀態標記量等等。
第3個,針對有序性。
也可以使用synchronized關鍵字定義同步程式碼塊,或者同步方法來保證有序性。另外也可以通過Lock介面來保證有序性。
以上就是對Java保證執行緒安全的思路。當然,保證物件執行緒安全的方式還有很多,比如還可以使用ThreadLocal實現多個執行緒之間的資料隔離,使用final關鍵字等等,我這裡就不一一列舉了。最後,我留一個思考題,單用volatile關鍵字,能保證執行緒安全嗎?
- Spring中實現非同步呼叫的方式有哪些?
- 帶引數的全型別 Python 裝飾器
- 整理了幾個Python正則表示式,拿走就能用!
- SOLID:開閉原則Go程式碼實戰
- React中如何引入CSS呢
- 一個新視角:前端框架們都卷錯方向了?
- 編碼中的Adapter,不僅是一種設計模式,更是一種架構理念與解決方案
- 手寫程式語言-遞迴函式是如何實現的?
- 一文搞懂模糊匹配:定義、過程與技術
- 新來個阿里 P7,僅花 2 小時,做出一個多執行緒永動任務,看完直接跪了
- Puzzlescript,一種開發H5益智遊戲的引擎
- @Autowired和@Resource到底什麼區別,你明白了嗎?
- CSS transition 小技巧!如何保留 hover 的狀態?
- React如此受歡迎離不開這4個主要原則
- LeCun再炮轟Marcus: 他是心理學家,不是搞AI的
- Java保證執行緒安全的方式有哪些?
- 19個殺手級 JavaScript 單行程式碼,讓你看起來像專業人士
- Python 的"self"引數是什麼?
- 別整一坨 CSS 程式碼了,試試這幾個實用函式
- 再有人問你什麼是MVCC,就把這篇文章發給他!