一、偏向鎖->輕量級鎖->重量級鎖的說明
1穆碎、偏向鎖
含義:當(dāng)線程A第一次競爭到鎖的時候梗逮,通過操作修改MarkWord中的偏向線程ID橄仍,鎖變?yōu)槠蚰J?/p>
作用:不存在其他線程競爭的情況下,不需要反復(fù)的獲得和釋放鎖稚机,減少性能的消耗
場景:有且只有一個線程訪問的情況
2幕帆、輕量級鎖
含義:多線程競爭,但是任一時刻最多只有一個線程競爭
作用:有線程來參與競爭赖条,但是獲取鎖的沖突時間極短失乾,本質(zhì)就是CAS常熙,避免線程的阻塞
場景:有多個線程來交替訪問進(jìn)行競爭
3、重量級鎖
含義:直接到操作系統(tǒng)級別碱茁,使用monitor管程
場景:多個線程來訪問競爭
二裸卫、用戶態(tài)與核心態(tài)的切換
用一個例子來理解下,我們的應(yīng)用程序需要從磁盤讀取某個文件的數(shù)據(jù)纽竣,此時并不是直接從磁盤加載到應(yīng)用內(nèi)存中墓贿,而是:
先將數(shù)據(jù)從「磁盤」復(fù)制到「內(nèi)核 Buffer」-內(nèi)核空間
再將數(shù)據(jù)從「內(nèi)核 Buffer」復(fù)制到「用戶 Buffer」 -用戶空間
用戶空間中的代碼被限制了只能使用一個局部的內(nèi)存空間,我們說這些程序在用戶態(tài)(User Mode) 執(zhí)行蜓氨。內(nèi)核空間中的代碼可以訪問所有內(nèi)存聋袋,我們稱這些程序在內(nèi)核態(tài)(Kernal Mode) 執(zhí)行。
以上是對用戶態(tài)和核心態(tài)的解釋穴吹,接下來我們要明白java 的線程是映射到操作系統(tǒng)原生線程之上的幽勒,如果要阻塞或喚醒一個線程就需要操作系統(tǒng)介入,需要在用戶態(tài)與核心態(tài)之間切換港令,這種切換是需要消耗大量的系統(tǒng)資源的(因為用戶態(tài)與內(nèi)核態(tài)都有客自專用的內(nèi)存空間啥容,專用的寄存器等,用戶態(tài)切換至內(nèi)核態(tài)需要傳遞給許多變量缠借、參數(shù)給內(nèi)核干毅,內(nèi)核也需要保護(hù)好用戶態(tài)在切換時的一些寄存器值、變量等泼返,以便內(nèi)核態(tài)調(diào)用結(jié)束后切換回用戶態(tài)繼續(xù)工作)硝逢。
在Java早期版本中,synchronized 屬于重量級鎖绅喉,效率低下渠鸽,因為監(jiān)視器鎖(moni tor)是依賴于底層的操作系統(tǒng)的Mutex Lock(系統(tǒng)互斥量)來實現(xiàn)的,掛起線程和恢復(fù)線程都需要轉(zhuǎn)入內(nèi)核態(tài)去完成柴罐,阻塞或喚醒一個 Java 線程需要操作系統(tǒng)切換 CPU 狀態(tài)來完成徽缚,這種狀態(tài)切換需要耗費處理器時間,如果同步代碼塊中內(nèi)容過于簡單革屠,這種切換的時間可能比用戶代碼執(zhí)行的時間還長”凿试,時間成本相對較高,這也是為什么早期的 synchronized 效率低的原因似芝,在Java6之后那婉,為了減少獲得鎖和釋放鎖所帶來的性能消著毛,引入了輕量級鎖和偏向鎖党瓮。
三详炬、鎖的升級過程
? ? ?無鎖->偏向鎖->輕量級鎖->重量級鎖
1、無鎖狀態(tài) -> 偏向鎖
首先當(dāng)處于無鎖狀態(tài)時寞奸,MarkWord中存儲的是對象的hash code等信息呛谜,偏向鎖為0在跳,此時線程1進(jìn)入,發(fā)現(xiàn)沒有記錄線程ID信息隐岛,則直接CAS操作將自己的線程ID設(shè)置進(jìn)去猫妙,設(shè)置成功則獲取到偏向鎖,偏向鎖標(biāo)志為改為1聚凹;失敗則要升級為輕量級鎖吐咳;
2、偏向鎖 -> 輕量級鎖
出現(xiàn)兩個及以上線程競爭時(已經(jīng)偏向給了一個線程元践,此時又出現(xiàn)了另外一個線程競爭韭脊,即升級),開始升級為輕量級鎖单旁。
3沪羔、輕量級鎖 -> 重量級鎖
設(shè)置失敗,則證明有競爭象浑,此時會進(jìn)入自旋狀態(tài)蔫饰。
線程超過10次自旋, 或者自旋線程數(shù)超過CPU核數(shù)的一半愉豺,(JDK1.6之后篓吁,加入自適應(yīng)自旋 Adapative Self Spinning , JVM自己控制)蚪拦。就會升級為重量級鎖杖剪。