初識(shí)
synchronized 可以加在方法和類上面,作用于類和對(duì)象。下面代碼中列出了 synchronized 的用法。
public class SynchronizedTest {
public static final Object lock = new Object();
// 鎖的是SynchronizedTest.class對(duì)象
public static synchronized void sync1() {
}
// 鎖的是SynchronizedTest.class對(duì)象
public static void sync2() {
synchronized (SynchronizedTest.class) {
}
}
// 鎖的是當(dāng)前實(shí)例this
public synchronized void sync3() {
}
// 鎖的是當(dāng)前實(shí)例this
public void sync4() {
synchronized (this) {
}
}
// 鎖的是指定對(duì)象lock
public void sync5() {
synchronized (lock) {
}
}
}
synchronized 大家都知道是用 monitorenter 和 monitorexit 兩個(gè)指令鎖住同步塊的。
那么 synchronized 是怎么膨脹的呢?為什么會(huì)膨脹呢?
先從 JVM 內(nèi)存開(kāi)始講起,對(duì)象在被實(shí)例化后,是存放在堆內(nèi)存中的,它由 3 部分組成:
- 對(duì)象頭:存放對(duì)象運(yùn)行時(shí)的狀態(tài)的信息、指向該對(duì)象所屬 Class 的元數(shù)據(jù)的指針。
- 實(shí)例數(shù)據(jù):存放對(duì)象的屬性數(shù)據(jù)信息,包括父類的信息。
- 對(duì)齊填充字節(jié):由于虛擬機(jī)要求對(duì)象的大小必須是 8 字節(jié)的整數(shù)倍。不是必須存在,僅僅是為了字節(jié)對(duì)齊。
其中對(duì)象頭里面包含了 Mark Word(標(biāo)記字段)和 Class Pointer(類型指針)

- Mark Word 默認(rèn)的存儲(chǔ)對(duì)象的 hashcode、分代年齡、是否偏向鎖、鎖標(biāo)識(shí)位的信息,它在運(yùn)行期間的存儲(chǔ)內(nèi)容會(huì)隨著鎖的變化而變化。
| Mark Word (32 bits) | 是否偏向鎖 | 鎖標(biāo)識(shí)位值 | 鎖狀態(tài) |
|---|---|---|---|
| 對(duì)象的hashcode(25)、分代年齡(4)、是否偏向鎖(1)、鎖標(biāo)識(shí)位(2) | 0 | 01 | 無(wú)鎖 |
| 線程ID(23)、偏向時(shí)間戳(2)、分代年齡(4)、是否偏向鎖(1)、鎖標(biāo)識(shí)位(2) | 1 | 01 | 偏向鎖 |
| 指向棧中鎖記錄的指針(30)、鎖標(biāo)識(shí)位(2) | 00 | 輕量級(jí)鎖 | |
| 指向重量級(jí)鎖的指針(30)、鎖標(biāo)識(shí)位(2) | 10 | 重量級(jí)鎖 |
- Class Pointer(類型指針):對(duì)象指向類的元數(shù)據(jù)的指針,虛擬機(jī)通過(guò)這個(gè)指針來(lái)確定對(duì)象是哪一個(gè)類的實(shí)例。
鎖膨脹
偏向鎖、輕量級(jí)鎖、重量級(jí)鎖、自旋鎖,這些都是Synchronzied的鎖的實(shí)現(xiàn)。Synchrozied會(huì)根據(jù)不同的場(chǎng)景選擇不同的鎖,我們只使用Synchronzied,不用關(guān)心它具體使用的哪個(gè)鎖。
偏向鎖
在java 程序中,大多數(shù)情況不存在多個(gè)線程同時(shí)競(jìng)爭(zhēng)鎖,往往都是同一個(gè)線程多次獲得同一個(gè)鎖。
當(dāng)只有一個(gè)線程在競(jìng)爭(zhēng)鎖的時(shí)候,在線程獲取到鎖后,將進(jìn)入偏向模式,程序會(huì)將對(duì)象的頭的前 23 個(gè)字節(jié)用 CAS 的方式存儲(chǔ)線程 ID。下次有線程競(jìng)爭(zhēng)鎖,只需要比較對(duì)象頭中的線程 ID 是不是和此時(shí)獲取到鎖的線程 ID 相同。如果相同線程就直接進(jìn)入同步代碼塊,不需要 CAS 競(jìng)爭(zhēng)鎖。

有另外的線程在競(jìng)爭(zhēng)鎖的時(shí)候,持有偏向鎖的線程才會(huì)釋放鎖,持有偏向鎖的線程不會(huì)主動(dòng)釋放偏向鎖。偏向鎖的撤銷,是在沒(méi)有字節(jié)碼執(zhí)行的時(shí)候進(jìn)行的。首先會(huì)暫停偏向鎖的線程,判斷鎖對(duì)象是否被鎖住。撤銷偏向鎖后恢復(fù)成無(wú)鎖或者是輕量級(jí)鎖。
輕量級(jí)鎖
當(dāng)有另外的線程在競(jìng)爭(zhēng)偏向鎖的時(shí)候并且競(jìng)爭(zhēng)失敗了,偏向鎖就會(huì)膨脹為輕量級(jí)鎖,其他的線程會(huì)通過(guò)自旋的方式嘗試獲取鎖。
JVM 會(huì)在當(dāng)前線程的棧幀中創(chuàng)建一個(gè)叫做鎖記錄(Lock Record)的空間,將鎖對(duì)象的 Mark Word 復(fù)制進(jìn)去。這個(gè)官方稱為 Displaced Mard Word。然后 JVM 將使用 CAS 操作嘗試將鎖對(duì)象的Mark Word 更新為指向 Lock Record 的指針。如果更新成功,鎖標(biāo)識(shí)位就成為 00,此時(shí)為輕量級(jí)鎖。

重量級(jí)鎖
從上面的表格中就指出重量級(jí)鎖的對(duì)象頭里面存儲(chǔ)的是指向 monitor 的指針,那 monitor 是什么呢?
monitor 又稱為管程,Java 中由 ObjectMonitor 實(shí)現(xiàn)。當(dāng)線程要將對(duì)象加鎖的時(shí)候,對(duì)象會(huì)創(chuàng)建一個(gè)monitor。

ObjectMonitor 主要的字段有:
- owner:就是當(dāng)前加鎖的線程
- waitSet:就是 owner的線程調(diào)用了 wait() 方法,就進(jìn)入這個(gè)里面
- entryList:加鎖失敗的線程阻塞在這個(gè)里面
- recursions:鎖的重入次數(shù)
- count:用來(lái)記錄是不是有對(duì)象加鎖:0.當(dāng)前對(duì)象沒(méi)有線程加鎖,1. 當(dāng)前對(duì)象有線程加鎖
從輕量級(jí)鎖升級(jí)到重量級(jí)鎖的時(shí)候,對(duì)象頭 Mark Word 存儲(chǔ)已經(jīng)變成了指向 Monitor 的指針。線程可以通過(guò)這個(gè)指針找到 ObjectMonitor,放入 entryList 等待重量級(jí)鎖釋放后競(jìng)爭(zhēng)。entryList 中的線程 CAS 嘗試更新 count = 1,當(dāng)更新成功后將 owner 設(shè)置為當(dāng)前的線程。當(dāng) owner 的線程調(diào)用了 wait() 方法,線程就會(huì)釋放鎖,進(jìn)入 waitSet 中。這個(gè)時(shí)候 count = 1,owner = null,entryList 的線程可以再次競(jìng)爭(zhēng)鎖。

總結(jié)
- synchronized 不管是加在類上還是方法上,如果作用在類上,這個(gè)類的所有對(duì)象都是同一把鎖,
- 鎖膨脹時(shí)不可以降級(jí)的
-
內(nèi)存
+關(guān)注
關(guān)注
9文章
3173瀏覽量
76118 -
代碼
+關(guān)注
關(guān)注
30文章
4941瀏覽量
73151 -
JVM
+關(guān)注
關(guān)注
0文章
161瀏覽量
12957
發(fā)布評(píng)論請(qǐng)先 登錄
MATLAB2013中Synchronized 6-Pulse Generator在哪兒
電子膨脹閥如何驅(qū)動(dòng)
電子膨脹閥的介紹
Synchronized multi-spark modul
熱力膨脹閥的分類及有什么區(qū)別_熱力膨脹閥怎么調(diào)節(jié)(工作原理及作用)
國(guó)內(nèi)智能鎖市場(chǎng)急劇膨脹,企業(yè)做好突圍準(zhǔn)備勢(shì)在必行
為何膨脹螺絲可以固定得那么牢固
Java并發(fā)編程中線程同步的常用手段synchronized用法
一文了解 Synchronized編程(源代碼)
詳細(xì)介紹synchronized和Object的關(guān)鍵方法和虛擬機(jī)實(shí)現(xiàn)原理
synchronized知識(shí)合集1
synchronized知識(shí)合集2
synchronized的原理與四種用法介紹

synchronized的鎖膨脹
評(píng)論