關(guān)于 synchronized 鎖優(yōu)化
??眾所周知,讓開發(fā)者簡(jiǎn)單輕松的編寫保證線程安全的代碼,一直是現(xiàn)代編程語(yǔ)言所最求的,Java 也不例外。Java 語(yǔ)言引入的?synchronized?關(guān)鍵字,無(wú)不彰顯它在此方面的勃勃雄心。但理想豐滿現(xiàn)實(shí)骨感,早期的 Java 版本里,對(duì)于此關(guān)鍵字的實(shí)現(xiàn)太過(guò)厚重,導(dǎo)致線程同步的性能遠(yuǎn)不如預(yù)期。Java HotSpot? VM 經(jīng)過(guò)多個(gè)版本的迭代,利用鎖膨脹思想,盡量延遲使用重量級(jí)鎖的手段來(lái)提升?synchronized?原語(yǔ)的性能。
對(duì)象存儲(chǔ)
對(duì)象結(jié)構(gòu)
對(duì)象
對(duì)象在內(nèi)存中的結(jié)構(gòu) (64位 JVM) 對(duì)象頭 object header 成員變量 object field 對(duì)齊/填充(可選) alignment/padding gap (optional) 對(duì)象數(shù)組
對(duì)象數(shù)組在內(nèi)存中的結(jié)構(gòu) (64位 JVM) 對(duì)象頭 object header 數(shù)組元素字節(jié)序列 elements bytes 對(duì)齊/填充(可選) alignment/padding gap (optional)
??由于對(duì)象在內(nèi)存以?8 字節(jié)?為最小單位,單個(gè)對(duì)象占用內(nèi)存字節(jié)不是 8 的倍數(shù)時(shí),需要增加留空字節(jié)湊成倍數(shù),此時(shí)留空的字節(jié)被稱為?對(duì)象對(duì)齊(object alignment)。單個(gè)對(duì)象內(nèi)部的成員變量所占字節(jié)不滿 4 的倍數(shù)時(shí),也需增加留空字節(jié)湊成倍數(shù),此時(shí)的留空字節(jié)被稱為?填充間隙(padding gap)。
對(duì)象頭結(jié)構(gòu)
對(duì)象
對(duì)象的 Object Hearder 結(jié)構(gòu) (64位 JVM) Mark Word (64 位) Klass Word(壓縮 32位,不壓縮 64位)1 對(duì)齊/填充(可選) alignment/padding gap (optional) 對(duì)象數(shù)組
對(duì)象數(shù)組的 Object Hearder 結(jié)構(gòu) (64位 JVM) Mark Word (64 位) Klass Word(壓縮 32 位,不壓縮 64 位) 數(shù)組長(zhǎng)度(32 位) 對(duì)齊/填充(可選) alignment/padding gap (optional)
Mark Word 結(jié)構(gòu)
??Mark Word,為運(yùn)行時(shí)對(duì)象的標(biāo)記字,字在 32 位系統(tǒng)中占用 32 bit,64 位操作系統(tǒng)占用 64 bit。其記錄著對(duì)象運(yùn)行時(shí)的數(shù)據(jù),包括?identity_hashcode、GC 分代年齡、鎖狀態(tài)?等信息。以下引用自 JDK8 HotSpot 源碼?markOop.hpp?中,關(guān)于 Mark Word 結(jié)構(gòu)信息的描述:
// 32 bits:
// --------
// hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object)
// JavaThread*:23 epoch:2 age:4 biased_lock:1 lock:2 (biased object)
// size:32 ------------------------------------------>| (CMS free block)
// PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)
//
// 64 bits:
// --------
// unused:25 hash:31 -->| unused:1 age:4 biased_lock:1 lock:2 (normal object)
// JavaThread*:54 epoch:2 unused:1 age:4 biased_lock:1 lock:2 (biased object)
// PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
// size:64 ----------------------------------------------------->| (CMS free block)
//
// unused:25 hash:31 -->| cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && normal object)
// JavaThread*:54 epoch:2 cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && biased object)
// narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)
// unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block)
??為了節(jié)省內(nèi)存空間,64 位的 JVM 采取壓縮普通對(duì)象指針 (COOPs,即 Compressed Ordinary Object Pointer)?2?技術(shù),把對(duì)象指針由原來(lái)的 64 bit 壓縮成 32 bit,進(jìn)而省了一半的內(nèi)存空間。
??我們著重關(guān)注 64 位 JVM 的鎖的幾種狀態(tài),也就是通過(guò)上面的?biased_lock、lock?兩個(gè)標(biāo)志位的排列組合得到:
| biased_lock | lock | 狀態(tài) |
|---|---|---|
| 0 | 01 | 無(wú)鎖 normal object |
| 1 | 01 | 偏向鎖 biased object |
| 0 | 00 | 輕量級(jí)鎖 lightweight/thin object |
| 0 | 10 | 重量級(jí)鎖 heavyweight/fat object |
| 0 | 11 | GC 標(biāo)記 |
鎖的種類
??根據(jù) Mark Word 中的鎖狀態(tài),我們分別來(lái)介紹下。
重量級(jí)鎖
??利用系統(tǒng)級(jí)別的互斥量(mutex)實(shí)現(xiàn)同步臨界區(qū),由于系統(tǒng)級(jí)調(diào)用,開銷大,故稱其位重量級(jí)鎖。
??在下一節(jié)關(guān)于鎖的狀態(tài)改變圖中,會(huì)發(fā)現(xiàn)一個(gè)?重量級(jí)監(jiān)視器指針,由于它覆蓋(官方稱為?Displaced)了原本的 Mark Word,故它所指向的是復(fù)雜的數(shù)據(jù)結(jié)構(gòu)?ObjectMonitor?就包含有用來(lái)存儲(chǔ)備份的 Mark Word 信息。除此之外,該數(shù)據(jù)結(jié)構(gòu)還包含鎖的等待列表等信息,詳細(xì)可參考?Monitor Object 設(shè)計(jì)模式。
優(yōu)點(diǎn):持有鎖時(shí)間長(zhǎng)、競(jìng)爭(zhēng)激烈時(shí),其他等待的線程會(huì)讓出 CPU 進(jìn)入等待列表
缺點(diǎn):系統(tǒng)級(jí)調(diào)用,開銷大
自旋鎖
??利用循環(huán)的方式來(lái)實(shí)現(xiàn)線程等待(忙等),等待期間內(nèi)不讓出 CPU 執(zhí)行時(shí)間、免去系統(tǒng)級(jí)線程切換開銷。
優(yōu)點(diǎn):避免線程切換
缺點(diǎn):等待期間占用 CPU 資源
輕量級(jí)鎖
??采用原子性的?CAS?進(jìn)行加解鎖操作,加鎖失敗時(shí)自旋等待,成功則將 Mark Word 覆蓋成指向線程棧中的?Lock Record?指針,此記錄中同樣含有原 Mark Word 記錄的備份信息。CAS 調(diào)用不需系統(tǒng)級(jí)別調(diào)用,故稱為輕量級(jí)鎖。
優(yōu)點(diǎn):無(wú)需系統(tǒng)級(jí)調(diào)用,性能好于重量級(jí)鎖
缺點(diǎn):每次加解鎖都需要一次 CAS 操作,采用自旋忙等,在競(jìng)爭(zhēng)激烈、持有鎖時(shí)間長(zhǎng)會(huì)加重 CPU 負(fù)荷,會(huì)轉(zhuǎn)到重量級(jí)鎖。
偏向鎖
??給當(dāng)前鎖標(biāo)記所屬線程,使得所屬線程進(jìn)入同步臨界區(qū)不用做任何特殊處理,只是簡(jiǎn)單的使用 CAS 操作將所屬線程 ID 記錄到 Mark Word 中,同一線程再次加解鎖時(shí)無(wú)需 CAS 操作。
優(yōu)點(diǎn):只需初始化時(shí)進(jìn)行一次 CAS 操作,之后加解鎖都無(wú)需 CAS 操作
缺點(diǎn):只能單線程無(wú)競(jìng)爭(zhēng)時(shí)使用,一旦有其他線程就必須撤銷轉(zhuǎn)到輕量級(jí)。
鎖轉(zhuǎn)態(tài)轉(zhuǎn)移
??在給新建的對(duì)象分配內(nèi)存時(shí),其對(duì)象頭信息會(huì)按照下圖所示的進(jìn)行分配,同時(shí)隨著線程的競(jìng)爭(zhēng)發(fā)送鎖狀態(tài)的轉(zhuǎn)化:

狀態(tài)轉(zhuǎn)步驟
??具體鎖轉(zhuǎn)移的過(guò)程如下:
如果偏向鎖機(jī)制是啟用,那么新建的對(duì)象被初始化成匿名的偏向鎖。之所以是匿名,是因?yàn)榇藭r(shí)并沒(méi)有具體偏向的線程 ID。
使用虛擬機(jī)參數(shù)?
-XX:-UseBiasedLocking?可以關(guān)閉偏向鎖,默認(rèn)是啟用的。由于虛擬機(jī)參數(shù)?
-XX:BiasedLockingStartupDelay?默認(rèn) 4 秒,偏向鎖機(jī)制會(huì)延遲 4 秒生效,測(cè)試時(shí)可以將其設(shè)置為 0 秒,防止偏向鎖設(shè)置不生效。調(diào)用對(duì)象默認(rèn)的?
hashCode()、?System.identityHashCode(obj)?方法會(huì)使偏向鎖膨脹為輕量級(jí)鎖?3。原因?yàn)樯傻?identity_hashcode?需要被記錄到 Mark Word 中,而偏向鎖結(jié)構(gòu)沒(méi)有設(shè)計(jì)存儲(chǔ)備份 Mark Word 的指針,類似輕量級(jí)鎖的?lock record pointer、重量級(jí)鎖的?heavyweight monitor pointer。當(dāng)有單個(gè)線程嘗試獲取該對(duì)象鎖時(shí),將把此線程的 ID 寫入 Mark Word,完成加鎖操作。
當(dāng)此單線程解鎖時(shí),一直不存在其他線程來(lái)競(jìng)爭(zhēng)時(shí),此時(shí)重偏向 (rebias) 匿名偏向鎖,即無(wú)線程 ID 的偏向鎖。
一旦有其他線程時(shí)(不管有無(wú)競(jìng)爭(zhēng)),就撤銷偏向 (revoke bias) 轉(zhuǎn)為輕量級(jí)鎖。
其他線程 CAS 操作將自己的線程號(hào) ID 放入 Mark Word 會(huì)失敗,此線程會(huì)執(zhí)行撤銷偏向,在原偏向鎖持有線程到達(dá)安全點(diǎn)后暫停原線程,檢查原線程是否還持有鎖。如果已釋放鎖,將鎖狀態(tài)修改為普通無(wú)鎖狀態(tài);如果未釋放鎖,拷貝 Mark Word 到原偏向鎖線程的鎖記錄中,修改鎖狀態(tài)標(biāo)志位為輕量級(jí),把指向原偏向鎖線程的鎖記錄的指針存入 Mark Word 中,喚醒原持有偏向鎖線程。
原持有偏向鎖線程繼續(xù)從安全點(diǎn)之后運(yùn)行,解鎖時(shí)判斷對(duì)象頭的鎖記錄指針是否指向當(dāng)前線程鎖記錄、且鎖記錄的備份 Mark Word 與現(xiàn)有對(duì)象頭里的 Mark Word 一致,如果都一致說(shuō)明沒(méi)有其他線程等待此鎖,如果不一致說(shuō)明有其他線程等待,釋放鎖之后需要換線掛起的那些線程。
輕量級(jí)鎖狀態(tài)時(shí),如果競(jìng)爭(zhēng)激烈(等待線程多)、原線程持鎖時(shí)間長(zhǎng)(即其他線程自旋次數(shù)多、等待時(shí)間長(zhǎng))就會(huì)膨脹為重量級(jí)鎖。
輕量級(jí)、重量級(jí)鎖解鎖后轉(zhuǎn)為普通無(wú)鎖狀態(tài),即后三位為?
001。當(dāng)然,在重量級(jí)鎖狀態(tài)時(shí),如果競(jìng)爭(zhēng)轉(zhuǎn)為不激烈時(shí),鎖會(huì)降級(jí)為輕量級(jí)狀態(tài)。
狀態(tài)轉(zhuǎn)移驗(yàn)證源代碼
代碼依賴
junit
junit
4.12
test
org.openjdk.jol
jol-cli
0.10
代碼結(jié)構(gòu)
project
└── src
│ └── test
│ │ └── java
│ │ │ └── org
│ │ │ │ └── reion
│ │ │ │ │ └── LockTest.java
│ └── main
│ │ └── resources
│ │ └── java
│ │ │ └── org
│ │ │ │ └── reion
│ │ │ │ │ └── Student.java
代碼清單
Student.java
package org.reion;
/**
* 學(xué)生
*/
public class Student {
// 名
String firstName;
// 姓
String lastName;
}LockTest.java
package org.reion;
import org.junit.Before;
import org.junit.Test;
import java.util.Random;
import org.openjdk.jol.info.ClassLayout;
import static java.lang.System.out;
public class OopTest {
public static final String LINE_SEPARATOR = "\n<<============= %s ==============>>";
Student stu1;
@Before
public void before() {
stu1 = new Student();
}
// 具體測(cè)試方法在下面單個(gè)列出,此處省略
}
偏向鎖
測(cè)試方法
/**
* 該方法驗(yàn)證對(duì)象初始化后,由單個(gè)線程持有時(shí)的偏向鎖形態(tài)。
*/
@Test
public void testBiasedLock() throws InterruptedException {
// 確保代碼運(yùn)行時(shí),已經(jīng)啟用偏向鎖機(jī)制,有兩種方式:
// ① 偏向鎖機(jī)制默認(rèn)延遲 4 秒啟動(dòng),故休眠 5 秒
Thread.sleep(5000);
// stu1 之所以重新賦值,因?yàn)?before 里舊對(duì)象由于偏向鎖延遲啟動(dòng)機(jī)制,生成不可偏向的對(duì)象
stu1 = new Student();
// ② 添加虛擬機(jī)參數(shù),把默認(rèn)延遲修改為 0 秒,虛擬機(jī)啟動(dòng)立馬啟用偏向鎖機(jī)制
// -XX:BiasedLockingStartupDelay=0
//【未加鎖,可偏向】
out.println(String.format(LINE_SEPARATOR, "未加鎖,可偏向"));
out.println(ClassLayout.parseInstance(stu1).toPrintable());
//【偏向鎖】
synchronized (stu1) {
out.println(String.format(LINE_SEPARATOR, "偏向鎖"));
out.println(ClassLayout.parseInstance(stu1).toPrintable());
}
//【未加鎖,可偏向】
out.println(String.format(LINE_SEPARATOR, "未加鎖,可偏向"));
out.println(ClassLayout.parseInstance(stu1).toPrintable());
}輸出結(jié)果
<<============= 未加鎖,可偏向 ==============>>
# WARNING: Unable to attach Serviceability Agent. You can try again with escalated privileges. Two options: a) use -Djol.tryWithSudo=true to try with sudo; b) echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
<<============= 偏向鎖 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 a8 00 b9 (00000101 10101000 00000000 10111001) (-1191139323)
4 4 (object header) e1 7f 00 00 (11100001 01111111 00000000 00000000) (32737)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
<<============= 未加鎖,可偏向 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 a8 00 b9 (00000101 10101000 00000000 10111001) (-1191139323)
4 4 (object header) e1 7f 00 00 (11100001 01111111 00000000 00000000) (32737)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
注意:?由于 JVM 為?小端法(Little Endian)?故低字節(jié)在前,高字節(jié)在后。
因此:
打印結(jié)果中 object header 中 64 位 Mark Word 字節(jié)序列應(yīng)該為
00 00 7f e1 b9 00 a8 05
輕量級(jí)鎖
測(cè)試方法
/**
* 該方法驗(yàn)證調(diào)用默認(rèn) hashCode 或 System.identityHashCode 時(shí),變?yōu)檩p量級(jí)鎖的形態(tài)
*/
@Test
public void testThinLock() {
// 調(diào)用 System.identityHashCode(stu1) 使對(duì)象 stu1 禁用偏向鎖
// TIPS:
// 讓對(duì)象能夠利用上偏向鎖機(jī)制,應(yīng)該重載對(duì)象的 hashCode 方法,
// 避免 identityHashCode 方法調(diào)用,直接膨脹為輕量級(jí)鎖
out.println(String.format(LINE_SEPARATOR, "System.identityHashCode 方法調(diào)用"));
out.println(Integer.toHexString(stu1.hashCode()));
//【未加鎖,不可偏向】
out.println(String.format(LINE_SEPARATOR, "未加鎖,不可偏向"));
out.println(ClassLayout.parseInstance(stu1).toPrintable());
//【輕量級(jí)鎖】
synchronized (stu1) {
out.println(String.format(LINE_SEPARATOR, "輕量鎖"));
out.println(ClassLayout.parseInstance(stu1).toPrintable());
}
//【未加鎖,不可偏向】
out.println(String.format(LINE_SEPARATOR, "未加鎖,不可偏向"));
out.println(ClassLayout.parseInstance(stu1).toPrintable());
}輸出結(jié)果
<<============= System.identityHashCode 方法調(diào)用 ==============>>
6aa8ceb6
<<============= 未加鎖,不可偏向 ==============>>
# WARNING: Unable to attach Serviceability Agent. You can try again with escalated privileges. Two options: a) use -Djol.tryWithSudo=true to try with sudo; b) echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 b6 ce a8 (00000001 10110110 11001110 10101000) (-1462847999)
4 4 (object header) 6a 00 00 00 (01101010 00000000 00000000 00000000) (106)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
<<============= 輕量鎖 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 88 18 94 01 (10001000 00011000 10010100 00000001) (26482824)
4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
<<============= 未加鎖,不可偏向 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 b6 ce a8 (00000001 10110110 11001110 10101000) (-1462847999)
4 4 (object header) 6a 00 00 00 (01101010 00000000 00000000 00000000) (106)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
偏向鎖 -> 輕量級(jí)鎖
測(cè)試方法
/**
* 該方法驗(yàn)證第二個(gè)線程出現(xiàn)時(shí)(此時(shí)第二線程已經(jīng)在第一個(gè)線程解鎖后才執(zhí)行,故無(wú)競(jìng)爭(zhēng)),會(huì)撤銷偏向,變?yōu)檩p量級(jí)鎖的形態(tài)。
*/
@Test
public void testBias2ThinLock() throws InterruptedException {
// 調(diào)用偏向鎖方法,生成可偏向的 stu1 對(duì)象
testBiasedLock();
// 生成新線程,申請(qǐng)對(duì)象 stu1 鎖
out.println("當(dāng)前線程:" + Thread.currentThread());
Runnable runnable = () -> {
out.println("\n進(jìn)入線程:" + Thread.currentThread());
out.println(String.format(LINE_SEPARATOR, "未請(qǐng)求鎖,可偏向"));
out.println(ClassLayout.parseInstance(stu1).toPrintable());
//【偏向鎖 -膨脹-> 輕量級(jí)鎖】
synchronized (stu1) {
out.println(String.format(LINE_SEPARATOR, "已加鎖,膨脹為輕量級(jí)鎖"));
out.println(ClassLayout.parseInstance(stu1).toPrintable());
}
//【未加鎖,不可偏向】
out.println(String.format(LINE_SEPARATOR, "未加鎖,不可偏向"));
out.println(ClassLayout.parseInstance(stu1).toPrintable());
out.println("\n退出線程:" + Thread.currentThread());
};
Thread thread = new Thread(runnable);
thread.start();
thread.join();
}輸出結(jié)果
當(dāng)前線程:Thread[main,5,main]
進(jìn)入線程:Thread[Thread-1,5,main]
<<============= 未請(qǐng)求鎖,可偏向 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 d0 00 be (00000101 11010000 00000000 10111110) (-1107243003)
4 4 (object header) fb 7f 00 00 (11111011 01111111 00000000 00000000) (32763)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
<<============= 已加鎖,膨脹為輕量級(jí)鎖 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 08 c9 3e 06 (00001000 11001001 00111110 00000110) (104777992)
4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
<<============= 未加鎖,不可偏向 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
輕量級(jí)鎖維持
測(cè)試方法
/**
* 該方法驗(yàn)證低競(jìng)爭(zhēng)度時(shí),輕量級(jí)鎖能一直維持此狀態(tài),從而提高運(yùn)行效率
*/
@Test
public void testLowContentionThinLock() throws InterruptedException {
// 調(diào)用 testBias2ThinLock,使 stu1 經(jīng)歷 偏向鎖 -> 輕量鎖 過(guò)程
// 最終使 stu1 成為 未加鎖不可偏
testBias2ThinLock();
Runnable runnable = () -> {
Thread current = Thread.currentThread();
out.println("\n進(jìn)入線程:" + current);
//【輕量級(jí)鎖】
for (int i = 0; i<2; i++) {
try {
// 400 毫秒內(nèi)的隨機(jī)休眠時(shí)間,模擬低對(duì)象鎖競(jìng)爭(zhēng)
Thread.sleep(new Random().nextInt(400));
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (stu1) {
out.println(String.format(LINE_SEPARATOR, current + " ROUND-" + i) + "\n" + ClassLayout.parseInstance(stu1).toPrintable());
}
}
out.println("\n退出線程:" + Thread.currentThread());
};
Thread t1 = new Thread(runnable);
Thread t2 = new Thread(runnable);
t1.start();
t2.start();
t1.join();
t2.join();
// 結(jié)束競(jìng)爭(zhēng)后對(duì)象狀態(tài)
out.println(String.format(LINE_SEPARATOR, Thread.currentThread()) + "\n" + ClassLayout.parseInstance(stu1).toPrintable());
}輸出結(jié)果
進(jìn)入線程:Thread[Thread-2,5,main]
進(jìn)入線程:Thread[Thread-3,5,main]
<<============= Thread[Thread-3,5,main] ROUND-0 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) f8 98 1e 11 (11111000 10011000 00011110 00010001) (287217912)
4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
8 4 (object header) 83 02 01 f8 (10000011 00000010 00000001 11111000) (-134151549)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
<<============= Thread[Thread-3,5,main] ROUND-1 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) f8 98 1e 11 (11111000 10011000 00011110 00010001) (287217912)
4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
8 4 (object header) 83 02 01 f8 (10000011 00000010 00000001 11111000) (-134151549)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
退出線程:Thread[Thread-3,5,main]
<<============= Thread[Thread-2,5,main] ROUND-0 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) f8 68 0e 11 (11111000 01101000 00001110 00010001) (286157048)
4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
8 4 (object header) 83 02 01 f8 (10000011 00000010 00000001 11111000) (-134151549)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
<<============= Thread[Thread-2,5,main] ROUND-1 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) f8 68 0e 11 (11111000 01101000 00001110 00010001) (286157048)
4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
8 4 (object header) 83 02 01 f8 (10000011 00000010 00000001 11111000) (-134151549)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
退出線程:Thread[Thread-2,5,main]
<<============= Thread[main,5,main] ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 83 02 01 f8 (10000011 00000010 00000001 11111000) (-134151549)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
輕量級(jí)鎖 -> 重量級(jí)鎖 (高頻型)
測(cè)試方法
/**
* 該方法驗(yàn)證競(jìng)爭(zhēng)變激烈(請(qǐng)求鎖頻率快)后,鎖由輕量級(jí)膨脹為重量級(jí)的過(guò)程。
*/
@Test
public void testHighContentionThin2FatLock() throws InterruptedException {
// 調(diào)用 testBias2ThinLock,使 stu1 經(jīng)歷 偏向鎖 -> 輕量鎖 過(guò)程
// 最終使 stu1 成為 未加鎖不可偏
testBias2ThinLock();
Runnable runnable = () -> {
Thread current = Thread.currentThread();
out.println("\n進(jìn)入線程:" + current);
//【輕量級(jí)鎖】
for (int i = 0; i < 2; i++) {
try {
// 5 毫秒內(nèi)的隨機(jī)休眠時(shí)間,模擬高對(duì)象鎖競(jìng)爭(zhēng)
Thread.sleep(new Random().nextInt(5));
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (stu1) {
out.println(String.format(LINE_SEPARATOR, current + " ROUND-" + i) + "\n" + ClassLayout.parseInstance(stu1).toPrintable());
}
}
out.println("\n退出線程:" + Thread.currentThread());
};
Thread t1 = new Thread(runnable);
Thread t2 = new Thread(runnable);
t1.start();
t2.start();
t1.join();
t2.join();
// 結(jié)束競(jìng)爭(zhēng)后對(duì)象狀態(tài)
out.println(String.format(LINE_SEPARATOR, Thread.currentThread()) + "\n" + ClassLayout.parseInstance(stu1).toPrintable());
}輸出結(jié)果
<<============= 未加鎖,不可偏向 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
退出線程:Thread[Thread-1,5,main]
進(jìn)入線程:Thread[Thread-2,5,main]
進(jìn)入線程:Thread[Thread-3,5,main]
<<============= Thread[Thread-2,5,main] ROUND-0 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) da d3 02 e4 (11011010 11010011 00000010 11100100) (-469576742)
4 4 (object header) 9a 7f 00 00 (10011010 01111111 00000000 00000000) (32666)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
<<============= Thread[Thread-3,5,main] ROUND-0 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) da d3 02 e4 (11011010 11010011 00000010 11100100) (-469576742)
4 4 (object header) 9a 7f 00 00 (10011010 01111111 00000000 00000000) (32666)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
<<============= Thread[Thread-2,5,main] ROUND-1 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) da d3 02 e4 (11011010 11010011 00000010 11100100) (-469576742)
4 4 (object header) 9a 7f 00 00 (10011010 01111111 00000000 00000000) (32666)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
退出線程:Thread[Thread-2,5,main]
<<============= Thread[Thread-3,5,main] ROUND-1 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) da d3 02 e4 (11011010 11010011 00000010 11100100) (-469576742)
4 4 (object header) 9a 7f 00 00 (10011010 01111111 00000000 00000000) (32666)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
退出線程:Thread[Thread-3,5,main]
<<============= Thread[main,5,main] ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) da d3 02 e4 (11011010 11010011 00000010 11100100) (-469576742)
4 4 (object header) 9a 7f 00 00 (10011010 01111111 00000000 00000000) (32666)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
輕量級(jí)鎖 -> 重量級(jí)鎖 (長(zhǎng)時(shí)型)
測(cè)試方法
/**
* 該方法驗(yàn)證持鎖時(shí)間長(zhǎng)(等待線程自旋過(guò)多),鎖由輕量級(jí)膨脹為重量級(jí)的過(guò)程。
*/
@Test
public void testLongContentionThin2FatLock() throws InterruptedException {
// 調(diào)用 testBias2ThinLock,使 stu1 經(jīng)歷 偏向鎖 -> 輕量鎖 過(guò)程
// 最終使 stu1 成為 未加鎖不可偏
testBias2ThinLock();
// 長(zhǎng)期持有對(duì)象鎖,在另一個(gè)線程開始競(jìng)爭(zhēng)時(shí),觀察鎖膨脹過(guò)程
Runnable runnable = () -> {
Thread current = Thread.currentThread();
out.println("\n進(jìn)入線程:" + current);
//【輕量級(jí)鎖】
synchronized (stu1) {
int counter = 0;
while (counter < 5) {
counter++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
out.println(String.format(LINE_SEPARATOR, current + " 鎖內(nèi)") + "\n" + ClassLayout.parseInstance(stu1).toPrintable());
}
}
out.println("\n退出線程:" + current);
};
// 睡眠 2.5 秒后,開始競(jìng)爭(zhēng)鎖
Runnable runnable2 = () -> {
Thread current = Thread.currentThread();
out.println("\n進(jìn)入線程:" + current);
//【輕量級(jí)鎖】
try {
out.println(String.format(LINE_SEPARATOR, current + "睡眠...") + "\n\n");
Thread.sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 2.5 秒后參與競(jìng)爭(zhēng)
out.println(String.format(LINE_SEPARATOR, current + "參與競(jìng)爭(zhēng)...") + "\n\n");
synchronized (stu1) {
out.println(String.format(LINE_SEPARATOR, current) + "\n" + ClassLayout.parseInstance(stu1).toPrintable());
}
};
Thread t1 = new Thread(runnable);
Thread t2 = new Thread(runnable2);
t1.start();
t2.start();
t1.join();
t2.join();
}輸出結(jié)果
進(jìn)入線程:Thread[Thread-2,5,main]
進(jìn)入線程:Thread[Thread-3,5,main]
<<============= Thread[Thread-3,5,main]睡眠... ==============>>
<<============= Thread[Thread-2,5,main] 鎖內(nèi) ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) f0 98 a9 0c (11110000 10011000 10101001 00001100) (212441328)
4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
<<============= Thread[Thread-2,5,main] 鎖內(nèi) ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) f0 98 a9 0c (11110000 10011000 10101001 00001100) (212441328)
4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
<<============= Thread[Thread-3,5,main]參與競(jìng)爭(zhēng)... ==============>>
<<============= Thread[Thread-2,5,main] 鎖內(nèi) ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 8a 3c 01 5d (10001010 00111100 00000001 01011101) (1560362122)
4 4 (object header) d2 7f 00 00 (11010010 01111111 00000000 00000000) (32722)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
<<============= Thread[Thread-2,5,main] 鎖內(nèi) ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 8a 3c 01 5d (10001010 00111100 00000001 01011101) (1560362122)
4 4 (object header) d2 7f 00 00 (11010010 01111111 00000000 00000000) (32722)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
<<============= Thread[Thread-2,5,main] 鎖內(nèi) ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 8a 3c 01 5d (10001010 00111100 00000001 01011101) (1560362122)
4 4 (object header) d2 7f 00 00 (11010010 01111111 00000000 00000000) (32722)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
退出線程:Thread[Thread-2,5,main]
<<============= Thread[Thread-3,5,main] ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 8a 3c 01 5d (10001010 00111100 00000001 01011101) (1560362122)
4 4 (object header) d2 7f 00 00 (11010010 01111111 00000000 00000000) (32722)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
輕量級(jí)鎖 -> 重量級(jí)鎖 -> 輕量級(jí)鎖
測(cè)試方法
/**
* 該方法驗(yàn)證競(jìng)爭(zhēng)由強(qiáng)轉(zhuǎn)弱后,鎖由輕量級(jí)膨脹為重量級(jí)后又降級(jí)為輕量級(jí)的過(guò)程。
*/
@Test
public void testHighContentionThin2FatThenDeflate2ThinLock() throws InterruptedException {
// 調(diào)用 testBias2ThinLock,使 stu1 經(jīng)歷 偏向鎖 -> 輕量鎖 過(guò)程
// 最終使 stu1 成為 未加鎖不可偏
testBias2ThinLock();
Runnable runnable = () -> {
Thread current = Thread.currentThread();
out.println("\n進(jìn)入線程:" + current);
// 隨機(jī)產(chǎn)生 10 之內(nèi)的循環(huán)追加數(shù),模擬雙線程中,一個(gè)線程完成后,剩下的線程單獨(dú)執(zhí)行時(shí)鎖降級(jí)
int maxRound = new Random().nextInt(10);
//【輕量級(jí)鎖】
for (int i = 0; i < 5 + maxRound; i++) {
try {
// 5 毫秒內(nèi)的隨機(jī)休眠時(shí)間,模擬高對(duì)象鎖競(jìng)爭(zhēng)
Thread.sleep(new Random().nextInt(5));
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (stu1) {
out.println(String.format(LINE_SEPARATOR, current + " ROUND-" + i) + "\n" + ClassLayout.parseInstance(stu1).toPrintable());
}
out.println(String.format(LINE_SEPARATOR, current + " ROUND-" + i) + "\n" + ClassLayout.parseInstance(stu1).toPrintable());
}
out.println("\n退出線程:" + Thread.currentThread());
};
Thread t1 = new Thread(runnable);
Thread t2 = new Thread(runnable);
t1.start();
t2.start();
t1.join();
t2.join();
// 結(jié)束競(jìng)爭(zhēng)后對(duì)象狀態(tài)
out.println(String.format(LINE_SEPARATOR, Thread.currentThread()) + "\n" + ClassLayout.parseInstance(stu1).toPrintable());
}輸出結(jié)果
進(jìn)入線程:Thread[Thread-2,5,main]
進(jìn)入線程:Thread[Thread-3,5,main]
<<============= Thread[Thread-2,5,main] ROUND-0 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) f0 a8 25 0f (11110000 10101000 00100101 00001111) (254126320)
4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
<<============= Thread[Thread-2,5,main] ROUND-0 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
<<============= Thread[Thread-3,5,main] ROUND-0 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) f0 d8 35 0f (11110000 11011000 00110101 00001111) (255187184)
4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
<<============= Thread[Thread-3,5,main] ROUND-1 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 5a d1 82 44 (01011010 11010001 10000010 01000100) (1149423962)
4 4 (object header) dd 7f 00 00 (11011101 01111111 00000000 00000000) (32733)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
<<============= Thread[Thread-2,5,main] ROUND-1 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 5a d1 82 44 (01011010 11010001 10000010 01000100) (1149423962)
4 4 (object header) dd 7f 00 00 (11011101 01111111 00000000 00000000) (32733)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
【【【【【【【【中間打印省略】】】】】】】】】
退出線程:Thread[Thread-3,5,main]
<<============= Thread[Thread-2,5,main] ROUND-8 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) f0 a8 25 0f (11110000 10101000 00100101 00001111) (254126320)
4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
<<============= Thread[Thread-2,5,main] ROUND-8 ==============>>
org.reion.Student object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) b4 02 01 f8 (10110100 00000010 00000001 11111000) (-134151500)
12 4 java.lang.String Student.firstName null
16 4 java.lang.String Student.lastName null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
退出線程:Thread[Thread-2,5,main]
參考資料
Synchronization?Created by Christian Wimmer, last modified on Apr 29, 2008
Compressed Ordinary Object Pointer
markOop.hpp
What is in java object header
腳注
壓縮的類指針 (Compressed Class Pointer),使用虛擬機(jī)參數(shù)?
-XX:-UseCompressedClassPointers?關(guān)閉壓縮,默認(rèn)開啟。壓縮的普通對(duì)象指針 (Compressed Ordinary Object Pointer),使用虛擬機(jī)參數(shù)?
-XX:-UseCompressedOops?關(guān)閉壓縮,默認(rèn)開啟。How does the default hashCode() work??
source:https://reionchan.github.io/2020/08/26/about-synchronized-lock-optimization/

喜歡,在看
