【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 - 笔记
引入
CAS
lock cmpxchg在硬件層面實(shí)現(xiàn):在操作過(guò)程中不允許被其他CPU打斷,避免CAS在寫數(shù)據(jù)的時(shí)候被其他線程打斷,相比操作系統(tǒng)級(jí)別的鎖,效率要高很多。
加鎖才能讓多線程的訪問(wèn)變?yōu)樾蛄谢?/p>
用戶態(tài)和內(nèi)核態(tài)
對(duì)于操作系統(tǒng)來(lái)說(shuō),普通程序希望操作硬件,需要進(jìn)行申請(qǐng)。所有指令可以直接被操作系統(tǒng)內(nèi)核直接訪問(wèn),而用戶進(jìn)程想要訪問(wèn)硬件資源,需要通過(guò)操作系統(tǒng)才能訪問(wèn)。
內(nèi)核態(tài):執(zhí)行在內(nèi)核空間,能夠訪問(wèn)所有指令
用戶態(tài):只能訪問(wèn)用戶能夠訪問(wèn)的指令
linux內(nèi)核工作在ring0,用戶進(jìn)程工作在ring3
syncronized的升級(jí):不同于早期,有時(shí)候只需要在用戶態(tài)進(jìn)行操作,不需要經(jīng)過(guò)內(nèi)核態(tài)。
int 0x80 向OS申請(qǐng)一個(gè)中斷的調(diào)用
markword
工具:JOL=Java Object Layout,添加 Maven 依賴:
對(duì)象的內(nèi)存布局:當(dāng)new出一個(gè)對(duì)象之后,這個(gè)對(duì)象在內(nèi)存是怎么分布的?
我們來(lái)看HotSpot的實(shí)現(xiàn)。
要求對(duì)象8字節(jié)對(duì)齊(對(duì)象大小字節(jié)數(shù)必須是8的整數(shù)倍,如果不是,補(bǔ)4個(gè)空字節(jié))
8字節(jié)markword
4字節(jié)classpointer(默認(rèn))
4字節(jié)instance data(用于存儲(chǔ)成員變量)
…關(guān)于類方法,方法放在虛方法表里,那是另外一個(gè)實(shí)現(xiàn)了。
那么,synchronized 做了什么事?
結(jié)論:鎖信息被記錄在了markword里面
JDK8 markword實(shí)現(xiàn)表:
鎖升級(jí)初步
輕量級(jí)鎖也叫自旋鎖
偏向鎖
前提:
StringBuffer是同步的
多數(shù)代碼段在實(shí)際運(yùn)行時(shí)只有一個(gè)線程,所以沒有必要設(shè)計(jì)競(jìng)爭(zhēng)機(jī)制。
偏向鎖
沒有必要設(shè)計(jì)鎖競(jìng)爭(zhēng)機(jī)制時(shí),只是把第一個(gè)訪問(wèn)的線程的id寫到markword中,而不去真正的加鎖
自旋鎖
偏向鎖時(shí),有人來(lái)競(jìng)爭(zhēng)鎖了,現(xiàn)在操作系統(tǒng)把偏向鎖撤銷,進(jìn)行自旋鎖(輕量級(jí)鎖)競(jìng)爭(zhēng)。
競(jìng)爭(zhēng)方式:每個(gè)人在自己的線程內(nèi)部生成一個(gè)自己LR(Lock Record鎖記錄),兩個(gè)線程通過(guò)自己的方式嘗試將 LR 寫門上,競(jìng)爭(zhēng)成功的開始運(yùn)行,競(jìng)爭(zhēng)失敗的一直自旋等待。
重量級(jí)鎖
當(dāng)必須加鎖時(shí),markword中記錄的是objectmonitor(JVM用C++寫的一個(gè)Object)
class文件的字節(jié)碼
monitorenter(sync開始時(shí))
monitorexit(sync完成或發(fā)生異常)
鎖重入
synchronized是可重入鎖(在未解鎖的情況下,可以多次被加鎖)。
用來(lái)滿足子類和父類都是sync的情況。
重入次數(shù)必須記錄,因?yàn)橐怄i幾次必須要對(duì)應(yīng)。
偏向鎖實(shí)現(xiàn):記錄在線程棧里,自旋鎖->線程棧->每重入一次,LockRecord+=1
重量鎖實(shí)現(xiàn):驚動(dòng)了操作系統(tǒng),記錄在ObjectMonitor字段上
輕量級(jí)鎖什么時(shí)候升級(jí)為重量級(jí)鎖
什么是偏向鎖啟動(dòng)/未啟動(dòng)
為什么有自旋鎖,還需要有重量級(jí)鎖?
自旋是占用CPU時(shí)間,消耗CPU資源的。如果鎖的時(shí)間長(zhǎng)或者自旋線程多,CPU資源會(huì)被大量消耗。這是不劃算的。在這種情況下,升級(jí)為重量級(jí)鎖。重量級(jí)鎖中有等待隊(duì)列,拿不到鎖的進(jìn)入等待隊(duì)列,不需要消耗CPU資源(比如競(jìng)爭(zhēng)隊(duì)列、執(zhí)行隊(duì)列、等待隊(duì)列waitset)
偏向鎖是否一定比自旋鎖效率高?
不一定。在明確知道一個(gè)資源會(huì)有多線程競(jìng)爭(zhēng)的情況下,偏向鎖肯定會(huì)涉及鎖撤銷。這時(shí)候應(yīng)給直接使用自旋鎖。
JVM啟動(dòng)過(guò)程,會(huì)有很多線程競(jìng)爭(zhēng)(明確知道),所以默認(rèn)情況,JVM啟動(dòng)時(shí)不打開偏向鎖(默認(rèn)時(shí)延4秒)。一段時(shí)間之后再打開。可以使用Thread.sleep(5000);之后再new對(duì)象驗(yàn)證
普通對(duì)象 怎么直接到 偏向鎖?
批量重偏向與批量鎖撤銷
總結(jié)
以上是生活随笔為你收集整理的【Java】什么是CAS、synchronized升级概述、偏向锁/轻量级锁详解 - 笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【ElasticSearch】使用Doc
- 下一篇: 【Java】多线程Synchronize