
Synchornized做了哪些優(yōu)化?
synchornized底層都是使用monitorenter和monitorexit指令實(shí)現(xiàn)的,進(jìn)入同步塊就意味著拿到了monitorenter的所有權(quán),而持有這個(gè)monitorenter所有權(quán)的線程就可以執(zhí)行代碼塊,沒有持有的線程就都在外面等著,早期JDK1.6之前都是使用阻塞線程的方式等待鎖的釋放,但很多輕量級(jí)的同步塊,迅速執(zhí)行完的代碼塊來(lái)說(shuō),這個(gè)鎖就太重了,所以就在重量級(jí)鎖的基礎(chǔ)上引入了偏向鎖和輕量級(jí)鎖這兩個(gè)狀態(tài),如果當(dāng)前的synchornized加鎖的情況下面,他這個(gè)偏向鎖,是當(dāng)前的對(duì)象沒有競(jìng)爭(zhēng),而且總是由同一個(gè)線程獲得鎖的時(shí)候就會(huì)進(jìn)入偏向鎖的狀態(tài),一旦產(chǎn)生了競(jìng)爭(zhēng)就會(huì)膨脹為輕量級(jí)鎖,如果輕量級(jí)鎖自旋超過(guò)了一定次數(shù)又會(huì)膨脹為重量級(jí)鎖。
synchronized的執(zhí)行過(guò)程:
- 檢測(cè)Mark Word里面是不是當(dāng)前線程的ID,如果是,表示當(dāng)前線程處于偏向鎖
- 如果不是,則使用CAS將當(dāng)前線程的ID替換Mard Word,如果成功則表示當(dāng)前線程獲得偏向鎖,置偏向標(biāo)志位1
- 如果失敗,則說(shuō)明發(fā)生競(jìng)爭(zhēng),撤銷偏向鎖,進(jìn)而升級(jí)為輕量級(jí)鎖。
- 當(dāng)前線程使用CAS將對(duì)象頭的Mark Word替換為鎖記錄指針,如果成功,當(dāng)前線程獲得鎖
- 如果失敗,表示其他線程競(jìng)爭(zhēng)鎖,當(dāng)前線程便嘗試使用自旋來(lái)獲取鎖。
- 如果自旋成功則依然處于輕量級(jí)狀態(tài)。
- 如果自旋失敗,則升級(jí)為重量級(jí)鎖。
Monitor 原理
每個(gè) Java 對(duì)象都可以關(guān)聯(lián)一個(gè)Monitor對(duì)象,如果使用 synchronized 給對(duì)象上鎖(重量級(jí))之后,該對(duì)象頭的
Mark Word 中就被設(shè)置指向Monitor 對(duì)象的指針。
Monitor 結(jié)構(gòu)如下:

剛開始 Monitor 中 Owner 為 null。
當(dāng) Thread-2 執(zhí)行 synchronized(obj) 就會(huì)將 Monitor 的所有者 Owner 置為 Thread-2,Monitor中只能有一個(gè)Owner。
在 Thread-2上鎖的過(guò)程中,如果 Thread-3,Thread-4,Thread-5 也來(lái)執(zhí)行 synchronized(obj),就會(huì)進(jìn)入
EntryList BLOCKED。
Thread-2 執(zhí)行完同步代碼塊的內(nèi)容,然后喚醒EntryList 中等待的線程來(lái)競(jìng)爭(zhēng)鎖,競(jìng)爭(zhēng)的時(shí)是非公平的。
圖中 WaitSet 中的 Thread-0,Thread-1 是之前獲得過(guò)鎖,但條件不滿足進(jìn)入調(diào)用wait()方法進(jìn)入 WAITING 狀態(tài)的線程。當(dāng)調(diào)用notifyAll()方法之后,WaitSet中的 Thread-0,Thread-1 進(jìn)入EntryList BLOCKED。
自適應(yīng)自旋鎖
自旋鎖優(yōu)點(diǎn)在于它避免一些線程的掛起和恢復(fù)操作,因?yàn)閽炱鹁€程和恢復(fù)線程都需要從用戶態(tài)轉(zhuǎn)入內(nèi)核態(tài),這個(gè)過(guò)程是比較慢的,所以通過(guò)自旋的方式可以一定程度上避免線程掛起和恢復(fù)所造成的性能開銷
但是,如果長(zhǎng)時(shí)間自旋還獲取不到鎖,那么也會(huì)造成一定的資源浪費(fèi),所以我們通常會(huì)給自旋設(shè)置一個(gè)固定的值來(lái)避免一直自旋的性能開銷
自適應(yīng)自旋鎖是指,線程自旋的次數(shù)不再是固定的值,而是一個(gè)動(dòng)態(tài)改變的值。簡(jiǎn)單來(lái)說(shuō),如果線程自旋成功了,則下次自旋的次數(shù)會(huì)增多,如果失敗,下次自旋的次數(shù)會(huì)減少。
上面幾種鎖都是JVM自己內(nèi)部實(shí)現(xiàn),當(dāng)我們執(zhí)行synchronized同步塊的時(shí)候jvm會(huì)根據(jù)啟用的鎖和當(dāng)前線程的爭(zhēng)用情況,決定如何執(zhí)行同步操作;