鎖是多線程軟件開發(fā)的必要工具之一,它的基本作用是保護(hù)臨界資源不會被多個線程同時訪問而受到破壞。如果由于多線程訪問造成對象數(shù)據(jù)的不一致,那么系統(tǒng)運(yùn)行將會得到錯誤的結(jié)果。通過鎖,可以讓多個線程排隊,一個一個地進(jìn)入臨界區(qū)訪問目標(biāo)對象,使目標(biāo)對象的狀態(tài)總是保持一致,這也就是鎖存在的價值。
java中,鎖的優(yōu)化策略分為偏向鎖、輕量級鎖、自旋鎖、鎖消除、鎖膨脹
偏向鎖
偏向鎖是jdk1.6提出的一種鎖優(yōu)化。核心思想是,如果程序沒有競爭,則取消之前已經(jīng)取得鎖的線程的同步操作。也就是說,若鎖被線程獲取后,便進(jìn)入偏向模式,當(dāng)線程再次請求這個鎖時,無需再進(jìn)行相關(guān)的同步操作,從而節(jié)省了操作時間。如果在此之間有其他線程進(jìn)行了鎖請求,則鎖退出偏向模式。在jvm中使用-XX:+UseBiasedLocking可以設(shè)置啟用偏向鎖(一般是默認(rèn)開啟)。也可以配合BiasedLockingStartupDelay來設(shè)置啟動偏向鎖在虛擬機(jī)啟動多久后開啟。
當(dāng)對象處于偏向鎖模式時,對象頭的MarkWord最后三位是101。

輕量級鎖
如果偏向鎖失敗,java虛擬機(jī)會讓線程申請輕量級鎖。輕量級鎖在虛擬機(jī)內(nèi)部使用一個成為BasicObjectLock的對象實現(xiàn),,這個對象內(nèi)部由一個BasicLock對象和一個持有該鎖的Java對象指針組成。BasicObjectLock對象放置在Java棧的棧幀中。在BasicLock對象內(nèi)部還維護(hù)著displaced_header字段,它用于備份對象頭部的Mark Word。
由于BasicObjectLock對象在線程棧中,因此該指針必然指向持有該鎖的線程棧空間。當(dāng)需要判斷某一線程是否持有該對象鎖,只需簡單地判斷對象頭的指針是否在當(dāng)前線程的棧地址范圍內(nèi)即可。同時,BasicLock對象的displaced_header字段備份了原對象的MarkWord內(nèi)容。BasicObjectLock對象的obj字段則指向該對象。
首先,BasicLock通過set_displaced_header()方法備份了原對象的MarkWord。接著,使用CAS操作,嘗試將BasicLock的地址復(fù)制到對象頭的Mark Word,如果復(fù)制成功,那么加鎖成功,否則認(rèn)為加鎖失敗。如果加鎖失敗,那么輕量級鎖就有可能被膨脹為重量級鎖。
當(dāng)對象處于輕量級鎖定時,其Mark Word的最后兩位為00,此時它指向存放在獲得鎖的線程棧中的該對象真實對象頭。

鎖膨脹
當(dāng)鎖由輕量級鎖膨脹為重量級鎖后,對象的Mark Word最后兩位是10.整個Mark Word表示指向monitor對象的指針。
重量級鎖是依賴對象內(nèi)部的monitor鎖來實現(xiàn)的,而monitor又依賴操作系統(tǒng)的MutexLock(互斥鎖)來實現(xiàn)的,所以重量級鎖也被成為互斥鎖。
當(dāng)輕量級所經(jīng)過鎖撤銷等步驟升級為重量級鎖之后,它的Markword部分?jǐn)?shù)據(jù)大體如下

自旋鎖
鎖消除
鎖消除是java虛擬機(jī)在JIT編譯時,通過對運(yùn)行上下文的掃描(逃逸分析?),去除不可能存在共享資源競爭的鎖。通過鎖消除,可以節(jié)省毫無意義的請求鎖時間。