1.2.1線程安全之可見性問題
1.多線程中的問題
(1)所見非所得
(2)無法肉眼去檢測程序的準確性
(3)不同的運行平臺有不同的表現
(4)錯誤很難重現
2.問題
(1)從內存結構到內存模型
(2)工作內存緩存
(3)指令重排序
Java編程語言的語義允許編譯器和微處理器執行優化,這些優化可以與不正確的同步代碼交互,從而產生看似矛盾的行爲。(不僅僅是Java級別,也是CPU級別;
內存屏障,不僅會調用jit,還會調用CPU的指令禁止重排序)
3.內存模型的含義
內存模型描述程序的可能行爲。
【內存模型決定了線程在程序的每個點上可以讀取什麼值。】
4.Shared Variables共享變量描述
5.線程操作的定義
程序順序:如果一個程序沒有數據競爭,那麼程序的所有執行看起來都是順序一致的。
本規範只涉及到線程間(多線程)的操作。
6.對同步的規則定義(定義了讀數據)
7.happens-before先行發生原則
當程序包含兩個沒有被happens-before關係排序的衝突訪問時,就稱存在【數據爭用】。
遵守了這個原則,也就意味着有些代碼不能進行重排序,有些數據不能緩存。
8.volatile關鍵字
9.final在jvm中的處理
10.Word Tearing字節處理
11.double 和long的特殊處理
1.2.2線程安全概念之原子操作
編譯反編譯查看class內容的命令 :java -p -v 名稱
1.原子操作定義
【示例】
存在競態條件線程不安全,需要轉變爲原子操作才能安全。方式:循環CAS、鎖。
2.CAS機制
底層提供,針對變量級別,某一個屬性或者某一個內存地址的操作。
實際應用中,不需要這麼麻煩。因爲Java爲我們提供了一個J.U.C包內原子操作封裝類。
三個問題
3.J.U.C包內原子操作封裝類。
1.2.3鎖的概念和synchronized關鍵字
1.Java中鎖的概念
幾種重要的鎖實現方式:synchronized、 ReentrantLock、 ReentrantReadWriteLock
2.同步關鍵字synchronized
(1)概念
Java中每個對象都會有一個與之對應的監視器(object–mointor)
鎖消除:如果沒有什麼競爭,就不應該用鎖。
鎖粗化:如果存在多個小範圍的鎖,可以變成一個大的鎖。
同步關鍵字,不僅是實現同步,根據JVM規定還能保證可見性(讀取最新主內存數據,結束後寫入主內存)
(2)同步關鍵字加鎖原理
3.偏向鎖到輕量級鎖
4.重量級鎖-監視器(monitor)
修改mark word如果失敗,會自旋CAS一定次數,該次數可以通過參數配置:
超過次數,仍未搶到鎖,則鎖升級爲重量級鎖,進入阻塞。
monitor也叫做管程,計算機系統原理中有提及類似的概念。一個對象會有一個對應的monitor。
1.2.4Lock鎖接口實現
1.Lock的核心API
根據Lock的源碼註釋,Lock接口的實現,具備和同步關鍵字同樣的內語義。
2.RenentrantLock
獨享鎖;支持公平鎖、非公平鎖兩種模式;可重入鎖;
重入的時候,加鎖和解鎖的次數要一致;有多少次lock就需要有多少次unlock。
3.ReadWriteLock
4.Condition
源碼示例:
synchronized要了解
lock 要學會使用