锁状态的“可视化”实践
![](https://img-blog.csdnimg.cn/889aadd6605143b2a58d56352b45a8f4.png)
-
通过工具查看对象的内存布局
MAVEN引入
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.10</version> <!— 这里不同的版本打印出来的效果不一样,0.10 和 0.16 布局的输出格式有差异 -->
</dependency>
package cn.ly.test;
import org.openjdk.jol.info.ClassLayout;
public class JavaObjLayout {
int[] aa = new int[3];
public static void main(String[] args) {
A a = new A();
B b = new B();
C c = new C();
int[] aa = new int[3];
//查看对象内部信息`
System.out.println(ClassLayout.
parseInstance(a).toPrintable());
System.out.println(ClassLayout.
parseInstance(b).toPrintable());
System.out.println(ClassLayout.
parseInstance(c).toPrintable());
System.out.println(ClassLayout.
parseInstance(aa).toPrintable());
}
static class A {
}
static class B {
private long s;
}
static class C {
private int a;
private long d;
}
}
################################################################################################################################################################################
# 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
cn.ly.test.JavaObjLayout$A 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) 44 c1 00 f8 (01000100 11000001 00000000 11111000) (-134168252)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
cn.ly.test.JavaObjLayout$B 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 c1 00 f8 (10000011 11000001 00000000 11111000) (-134168189)
12 4 (alignment/padding gap)
16 8 long B.s 0
Instance size: 24 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total
cn.ly.test.JavaObjLayout$C 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) c1 c1 00 f8 (11000001 11000001 00000000 11111000) (-134168127)
12 4 int C.a 0
16 8 long C.d 0
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
[I 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) 6d 01 00 f8 (01101101 00000001 00000000 11111000) (-134217363)
12 4 (object header) 03 00 00 00 (00000011 00000000 00000000 00000000) (3)
16 12 int [I.<elements> N/A
28 4 (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
################################################################################################################################################################################
注意点:
-
jdk6默认开启偏向锁,但是是输入延时开启,也就是说,程序刚启动创建的对象是不会开启偏向锁的,几秒后后创建的对象才会开启偏向锁的
//关闭延迟开启偏向锁
-XX:BiasedLockingStartupDelay=0
//禁止偏向锁
-XX:-UseBiasedLocking
//启用偏向锁
-XX:+UseBiasedLocking
-
Jol layout 结果查看需要注意顺序
![](https://img-blog.csdnimg.cn/1dd66878cc1d4136936c1e582de73581.png)
对象头看锁升级过程:
![](https://img-blog.csdnimg.cn/b81267a17a1547be996982105c88ed39.jpeg)
一、无锁状态和偏向锁状态
-
JVM的启动参数默认值。偏向锁相关的不做任何设置。这意味着默认会有几秒的锁偏向的延迟。
-
代码示例,及结果
public static void main(String[] args) throws InterruptedException {
Object obj1 = new Object();
// 由于偏向锁生效是有延迟的(JVM启动后相对时间),所以这里采用这种方式来演示延迟
// 在偏向锁生效前先创建好一个对象 obj1 ,此时对象头默认是无锁状态:001
TimeUnit.SECONDS.sleep(5);
// sleep的目的是为了使"延迟的偏向锁"变得生效
System.out.println(ClassLayout.
parseInstance(obj1).toPrintable());
// JVM偏向锁延迟生效以后,再创建对象Obj2这个时候会发现,默认对象的头标记就是偏向锁 101
Object obj2 = new Object();
System.out.println(ClassLayout.
parseInstance(obj2).toPrintable());
}
################################################################################################################################################################################
# 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
java.lang.Object 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) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
java.lang.Object 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) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
################################################################################################################################################################################
注意结果:
![](https://img-blog.csdnimg.cn/900c6e3c6d4d435a8d7d3e8a48000b73.png)
二、无锁膨胀为轻量级锁
-
JVM参数不做任何调整。即存在偏向锁的延迟.
-
代码示例及结果
/**
* 轻量级锁
*/
public static void lightLock() throws InterruptedException {
Object obj3 = new Object();
System.out.println("无锁状态下的对象头markword标记:\n" + ClassLayout.
parseInstance(obj3).toPrintable());
System.out.println("------------------------------------------------------------------------------------------------------");
Thread t1 = new Thread(()->{
synchronized(obj3){
System.out.println("线程t1获得锁obj3");
System.out.println("偏向锁延迟生效时间内,无锁状态-膨胀为:轻量锁 ,其对象头markword标记:\n" + ClassLayout.
parseInstance(obj3).toPrintable());
}
});
t1.start();
t1.join();
}
################################################################################################################################################################################
无锁状态下的对象头markword标记:
java.lang.Object 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) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
------------------------------------------------------------------------------------------------------
线程t1获得锁obj3
偏向锁延迟生效时间内,无锁状态-膨胀为:轻量锁 ,其对象头markword标记:
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 08 19 60 08 (00001000 00011001 01100000 00001000) (140515592)
4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
################################################################################################################################################################################
![](https://img-blog.csdnimg.cn/f13d2ea890fa4a4b8642c37f530cc731.png)
三、偏向锁和轻量锁升级
-
JVM参数不做任何调整。即存在偏向锁的延迟.(代码中通过sleep来达到让延迟到期从而偏向生效来演示)
-
代码和结果如下:
/**
* 偏向锁-轻量级锁,在偏向生效以后
*/
public static void lightLockAfterBiasedLockingEffective() throws InterruptedException {
// 由于偏向锁生效是有延迟的(JVM启动后相对时间),所以这里采用这种方式来演示延迟
TimeUnit.SECONDS.sleep(5);
Object obj4 = new Object();
System.out.println("JVM偏向锁已经生效:偏向锁状态下的对象头markword标记:\n" + ClassLayout.
parseInstance(obj4).toPrintable());
System.out.println("------------------------------------------------------------------------------------------------------");
Thread t2 = new Thread(()->{
synchronized(obj4){
System.out.println("线程t2获得锁obj4");
System.out.println("偏向锁延迟生效后,线程t2 打印obj4 对象偏向锁状态,其对象头markword标记:\n" + ClassLayout.
parseInstance(obj4).toPrintable());
}
});
t2.start();
t2.join();
TimeUnit.SECONDS.sleep(2);
System.out.println("------------------------------------------------------------------------------------------------------");
Thread t3 = new Thread(()->{
synchronized(obj4){
System.out.println("线程t3获得锁obj4");
System.out.println("偏向锁延迟生效后,偏向锁状态-膨胀为:轻量锁 ,其对象头markword标记:\n" + ClassLayout.
parseInstance(obj4).toPrintable());
}
});
t3.start();
t3.join();
}
################################################################################################################################################################################
JVM偏向锁已经生效:偏向锁状态下的对象头markword标记:
java.lang.Object 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) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
------------------------------------------------------------------------------------------------------
t2 内存地址:31874192952,十六进制位:76bd99638,二进制位:11101101011110110011001011000111000
线程t2获得锁obj4
偏向锁延迟生效后,线程t2 打印obj4 对象偏向锁状态,其对象头markword标记:
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 48 95 c8 (00000101 01001000 10010101 11001000) (-929740795)
4 4 (object header) d3 7f 00 00 (11010011 01111111 00000000 00000000) (32723)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
t2 id:14,二进制位:1110
------------------------------------------------------------------------------------------------------
线程t3获得锁obj4
偏向锁延迟生效后,偏向锁状态-膨胀为:轻量锁 ,其对象头markword标记:
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 08 b9 cc 0e (00001000 10111001 11001100 00001110) (248297736)
4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
################################################################################################################################################################################
![](https://img-blog.csdnimg.cn/03eb872523774e578a2214e4440ba2c9.png)
![](https://img-blog.csdnimg.cn/ec9495a23bcf4a7c8e1f430276bab0a7.png)
三、升级到重量级锁
-
JVM参数不做任何调整。即存在偏向锁的延迟.(代码中通过sleep来达到让延迟到期从而偏向生效来演示)
-
代码和结果如下:
public static void weightAfterBiasedLockingEffective() throws InterruptedException {
// 由于偏向锁生效是有延迟的(JVM启动后相对时间),所以这里采用这种方式来演示延迟
TimeUnit.SECONDS.sleep(5);
Object obj5 = new Object();
System.out.println("JVM偏向锁已经生效:偏向锁状态下的对象头markword标记:\n" + ClassLayout.
parseInstance(obj5).toPrintable());
System.out.println("------------------------------------------------------------------------------------------------------");
Thread t2 = new Thread(()->{
synchronized(obj5){
System.out.println("线程t2获得锁obj4");
System.out.println("偏向锁延迟生效后,线程t2 打印obj5 对象偏向锁状态,其对象头markword标记:\n" + ClassLayout.
parseInstance(obj5).toPrintable());
long tid = Thread.currentThread().getId();
System.out.println("t2 id:"+ tid + ",二进制位:" + Long.toBinaryString(tid));
}
});
t2.start();
long t2Addr = VM.current().addressOf(t2);
System.out.println("t2 内存地址:"+ t2Addr + ",十六进制位:" + Long.toHexString(t2Addr)+ ",二进制位:" + Long.toBinaryString(t2Addr));
t2.join();
System.out.println("------------------------------------------------------------------------------------------------------");
TimeUnit.MILLISECONDS.sleep(500);
Thread t3 = new Thread(()->{
synchronized(obj5){
System.out.println("[线程t3] 获得锁obj5");
System.out.println("偏向锁延迟生效后,偏向锁状态-膨胀为:??? ,其对象头markword标记:\n" + ClassLayout.
parseInstance(obj5).toPrintable());
}
});
t3.start();
Thread t4 = new Thread(()->{
synchronized(obj5){
System.out.println("[线程t4] 获得锁obj5");
System.out.println("偏向锁延迟生效后,偏向锁状态-膨胀为:??? ,其对象头markword标记:\n" + ClassLayout.
parseInstance(obj5).toPrintable());
}
});
t4.start();
}
备注:升级重量级锁的过程稍微复杂一些,会根据线程的调度情况和JVM运行时的情况不一样产生三种不一样的结果。
以下是多次跑代码后得到的3种不一样的结果
##########################################################################情况一######################################################################################################
JVM偏向锁已经生效:偏向锁状态下的对象头markword标记:
java.lang.Object 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) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
------------------------------------------------------------------------------------------------------
t2 内存地址:31874198304,十六进制位:76bd9ab20,二进制位:11101101011110110011010101100100000
线程t2获得锁obj4
偏向锁延迟生效后,线程t2 打印obj5 对象偏向锁状态,其对象头markword标记:
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 c8 aa dd (00000101 11001000 10101010 11011101) (-576010235)
4 4 (object header) c4 7f 00 00 (11000100 01111111 00000000 00000000) (32708)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
t2 id:14,二进制位:1110
------------------------------------------------------------------------------------------------------
[线程t3] 获得锁obj5
偏向锁延迟生效后,偏向锁状态-膨胀为:重量级锁 ,其对象头markword标记:
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 7a 0c 81 dc (01111010 00001100 10000001 11011100) (-595522438)
4 4 (object header) c4 7f 00 00 (11000100 01111111 00000000 00000000) (32708)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
[线程t4] 获得锁obj5
偏向锁延迟生效后,偏向锁状态-膨胀为:重量级锁 ,其对象头markword标记:
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 7a 0c 81 dc (01111010 00001100 10000001 11011100) (-595522438)
4 4 (object header) c4 7f 00 00 (11000100 01111111 00000000 00000000) (32708)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
################################################################################################################################################################################
##########################################################################情况二############################################################################################
JVM偏向锁已经生效:偏向锁状态下的对象头markword标记:
java.lang.Object 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) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
------------------------------------------------------------------------------------------------------
t2 内存地址:31874198752,十六进制位:76bd9ace0,二进制位:11101101011110110011010110011100000
线程t2获得锁obj4
偏向锁延迟生效后,线程t2 打印obj5 对象偏向锁状态,其对象头markword标记:
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 00 91 86 (00000101 00000000 10010001 10000110) (-2037317627)
4 4 (object header) ed 7f 00 00 (11101101 01111111 00000000 00000000) (32749)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
t2 id:14,二进制位:1110
------------------------------------------------------------------------------------------------------
[线程t3] 获得锁obj5
偏向锁延迟生效后,偏向锁状态-保持:偏向锁 ,其对象头markword标记:
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 00 91 86 (00000101 00000000 10010001 10000110) (-2037317627)
4 4 (object header) ed 7f 00 00 (11101101 01111111 00000000 00000000) (32749)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
[线程t4] 获得锁obj5
偏向锁延迟生效后,偏向锁状态-膨胀为:重量级锁 ,其对象头markword标记:
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 0a 9c 80 88 (00001010 10011100 10000000 10001000) (-2004837366)
4 4 (object header) ed 7f 00 00 (11101101 01111111 00000000 00000000) (32749)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
################################################################################################################################################################################
##########################################################################情况三############################################################################################
JVM偏向锁已经生效:偏向锁状态下的对象头markword标记:
java.lang.Object 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) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
------------------------------------------------------------------------------------------------------
t2 内存地址:31874198880,十六进制位:76bd9ad60,二进制位:11101101011110110011010110101100000
线程t2获得锁obj4
偏向锁延迟生效后,线程t2 打印obj5 对象偏向锁状态,其对象头markword标记:
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 f8 8e cd (00000101 11111000 10001110 11001101) (-846268411)
4 4 (object header) c9 7f 00 00 (11001001 01111111 00000000 00000000) (32713)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
t2 id:14,二进制位:1110
------------------------------------------------------------------------------------------------------
[线程t3] 获得锁obj5
偏向锁延迟生效后,偏向锁状态-膨胀为:轻量级锁 ,其对象头markword标记:
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 08 09 8d 0e (00001000 00001001 10001101 00001110) (244123912)
4 4 (object header) c9 7f 00 00 (11001001 01111111 00000000 00000000) (32713)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
[线程t4] 获得锁obj5
偏向锁延迟生效后,偏向(轻量)锁状态-膨胀为:重量级锁 ,其对象头markword标记:
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 0a 2c 01 cc (00001010 00101100 00000001 11001100) (-872338422)
4 4 (object header) c9 7f 00 00 (11001001 01111111 00000000 00000000) (32713)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
################################################################################################################################################################################
![](https://img-blog.csdnimg.cn/1220581aff8243429ac68185ca1872c0.png)
![](https://img-blog.csdnimg.cn/333adc3b2ea94191ad651698d55cd9a7.png)
![](https://img-blog.csdnimg.cn/0e899725564447f5a6504b663f121fc9.png)