1.鎖
2.volitaile
3.final
4.輕量級鎖,偏向鎖,重量級鎖
關(guān)于Synchronized的維基百科定義
https://wiki.openjdk.java.net/display/HotSpot/Synchronization
主要的圖如下

synchronized(可重入)的作用范圍
1.靜態(tài)方法(鎖住的是Class實例),字節(jié)碼方法的訪問標(biāo)記包含,ACC_SYNCHRONIZED
2.實例方法(鎖住的是當(dāng)前類實例)
3.代碼塊(鎖住的是當(dāng)前類),編譯后包含monitorenter和monitoreixt(可能會有多個,因為要確保鎖的正常執(zhí)行路徑以及異常執(zhí)行路徑上都能夠被解鎖)
鎖的代價由低到高
偏向鎖,輕量級鎖,重量級鎖
偏向鎖:針對的是鎖僅會被同一線程持有的情況。
只會在第一次請求時采用CAS操作,在鎖對象的標(biāo)記字段中記錄下當(dāng)前線程的地址。
在之后的運行過程中,持有該偏向鎖的線程加鎖操作將直接返回。
輕量級鎖:針對的是多個線程在不同時間段申請同一把鎖的情況。
采用CAS操作,將鎖對象的標(biāo)記字段替換為一個指針,指向當(dāng)前線程棧上的一塊空間,存儲著鎖對象原本的標(biāo)記字段。
重量級鎖:針對的是多個線程同時競爭同一把鎖的情況。
java虛擬機(jī)會采用自適應(yīng)(根據(jù)以往自旋等待時是否能夠獲得鎖,動態(tài)調(diào)整自旋時間,即循環(huán)數(shù)目,自旋也會影響公平的鎖機(jī)制,處于阻塞狀態(tài)的線程,并沒有辦法立刻競爭被釋放的鎖,但處于自旋狀態(tài)的線程,很有可能立刻能獲取到鎖),自旋(當(dāng)執(zhí)行任務(wù)的時間小于線程調(diào)度的時間時是劃算的),來避免在面對非常小的synchronized代碼塊時,仍然會被阻塞,喚醒的情況。
其次關(guān)于偏向鎖和輕量級鎖的區(qū)分
對象頭的標(biāo)記字段(mark word),最后兩位是用來表示該對象的鎖狀態(tài).
00代表輕量級鎖
01代表無鎖(或者偏向鎖)
10代表重量級鎖
11代表垃圾回收算法的標(biāo)記
當(dāng)進(jìn)行加鎖的時候,java虛擬機(jī)會首先判斷是不是重量級鎖。
不是,則
①在當(dāng)前線程的棧中劃出一塊空間,作為該鎖的記錄,并且將鎖對象的標(biāo)記字段復(fù)制到鎖記錄中。
②嘗試用CAS操作替換鎖對象的標(biāo)記字段
假設(shè)鎖對象標(biāo)記字段為X...XYZ
java虛擬機(jī)會首先比較該字段是否為X...X01
如果是,則替換為剛才分配的鎖記錄的地址。
如果不是,X...X01有兩種可能
①該線程重復(fù)獲取同一把鎖,此時,java虛擬機(jī)會將鎖記錄清零,代表該鎖被重復(fù)獲取。
②其他線程持有該鎖,java虛擬機(jī)會將這把鎖膨脹為重量級鎖,并且阻塞當(dāng)前線程。
當(dāng)進(jìn)行解鎖操作時
如果當(dāng)前鎖記錄的值為0(會有多個鎖記錄,可以把所有鎖記錄看成一個棧結(jié)構(gòu),加鎖即壓入一條鎖記錄,解鎖即彈出一條鎖記錄,當(dāng)前鎖即棧頂?shù)逆i記錄),代表重復(fù)進(jìn)入同一把鎖,直接返回
否則,java虛擬機(jī)會嘗試用CAS操作,比較鎖對象的標(biāo)記字段的值是否為當(dāng)前鎖記錄的地址。
如果是,則替換鎖記錄中的值,也就是鎖對象原本的標(biāo)記字段。此時,成功釋放這把鎖
如果不是,則意味著已經(jīng)膨脹為重量級鎖。此時會進(jìn)入重量級鎖的釋放過程,喚醒因為競爭該鎖而被阻塞的線程。
32位系統(tǒng)中Mark Word的32bit空間中的25bit用于存儲對象哈希碼(HashCode),4bit用于存儲對象的分代年齡,2bit用于存儲鎖標(biāo)志位,1bit固定為0
HotSpot虛擬機(jī)對象頭Mark Word
| 存儲內(nèi)容 | 標(biāo)志位 | 狀態(tài) |
|---|---|---|
| 對象哈希碼,對象分代年齡 | 01 | 未鎖定 |
| 指向鎖記錄的指針 | 00 | 輕量級鎖 |
| 指向重量級鎖的指針 | 10 | 膨脹(重量級鎖定) |
| 空,不需要記錄信息 | 11 | GC標(biāo)記 |
| 偏向線程ID,偏向時間戳,對象分代年齡 | 01 | 可偏向 |