并發(fā)的挑戰(zhàn)
上下文切換: 是消耗資源的操作,進(jìn)入內(nèi)核態(tài)需要
資源限制 : ?I/O 數(shù)據(jù)庫盯串,cpu核數(shù)
死鎖 :等待不到需要的資源
volatile
內(nèi)存語義
當(dāng)寫一個volatile變量時,JMM會把該線程對應(yīng)的本地內(nèi)存中的共享變量值刷新到主內(nèi)存中富蓄。當(dāng)讀一個volatile變量時车吹,JMM會把該線程對應(yīng)的本地內(nèi)存置為無效,線程接下來將從主內(nèi)存中讀取共享變量
硬件實現(xiàn)
使用硬件指令當(dāng)前緩存行刷入主內(nèi)存
是其他緩存中此變量的緩存行無效
使得讀操作需要重新從主內(nèi)存加載此變量
適用場景
只有一個線程對volatile變量寫
Synchronized
鎖的對象
Java中的每一個對象都可以作為鎖抖僵。
對于同步方法,鎖是當(dāng)前實例對象缘揪。
對于靜態(tài)同步方法耍群,鎖是當(dāng)前對象的Class對象。
對于同步方法塊找筝,鎖是Synchonized括號里配置的對象
實現(xiàn)
同步方法
使用 ACC_SYNCHRONIZED 標(biāo)記符隱示的實現(xiàn)蹈垢,原理是通過方法調(diào)用指令檢查該方法在常量池中是否包含 ACC_SYNCHRONIZED 標(biāo)記符,JVM 要求線程在調(diào)用之前請求鎖
同步代碼塊
JVM通過monitorenter和monitorexist指令實現(xiàn)同步鎖的獲取和釋放功能
monitorenter指令是在編譯后插入到同步代碼塊的開始位置
monitorexit指令是插入到方法結(jié)束處和異常處
JVM要保證每個monitorenter必須有對應(yīng)的monitorexit與之配對
任何對象都有一個monitor與之關(guān)聯(lián)袖裕,當(dāng)且一個monitor被持有后曹抬,它將處于鎖定狀態(tài)
線程執(zhí)行monitorenter指令時,將會嘗試獲取對象所對應(yīng)的monitor的所有權(quán)急鳄,即嘗試獲得對象的鎖
線程執(zhí)行monitorexit指令時谤民,將會將進(jìn)入次數(shù)-1直到變成0時釋放監(jiān)視器
同一時刻只有一個線程能夠成功,其它失敗的線程會被阻塞疾宏,并放入到同步隊列中张足,進(jìn)入BLOCKED狀態(tài)
虛擬機(jī)做的鎖優(yōu)化
1.鎖消除,消除無謂的鎖
2.鎖粗化坎藐,合并太小粒度的加鎖
3.鎖自旋为牍,自適應(yīng)自旋
4.鎖膨脹
鎖膨脹
Java對象頭
偏向鎖
為了在無多線程競爭的情況下盡量減少不必要的輕量級鎖執(zhí)行路徑
,而偏向鎖則是在只有一個線程執(zhí)行同步塊時進(jìn)一步提高性能
輕量級鎖
目的是沒有多線程競爭的前提下,減少傳統(tǒng)的重量級鎖
輕量級鎖是為了在線程交替執(zhí)行同步塊時提高性能
重量級鎖實現(xiàn)
Monitor Record結(jié)構(gòu)
MonitorRecord(統(tǒng)一簡稱MR)是Java線程私有的數(shù)據(jù)結(jié)構(gòu)碉咆,每一個線程都有一個可用MR列表抖韩,同時還有一個全局的可用列表
一個被鎖住的對象都會和一個MR關(guān)聯(lián)(對象頭的MarkWord中的LockWord指向MR的起始地址)
MR中有一個Owner字段存放擁有該鎖的線程的唯一標(biāo)識,表示該鎖被這個線程占用
Monitor Record工作機(jī)理
線程如果獲得監(jiān)視鎖成功吟逝,將成為該監(jiān)視鎖對象的擁有者
在任一時刻帽蝶,監(jiān)視器對象只屬于一個活動線程(Owner)
擁有者可以調(diào)用wait方法自動釋放監(jiān)視鎖赦肋,進(jìn)入等待狀態(tài)