Java对象头Markword的结构
其中,最低2位是10代表重量级锁,00代表轻量级锁,001代表无锁,101代表偏向锁。
synchronized锁在1.6的时候做了优化,当仅有一个线程竞争锁的时候,锁处于偏向锁的状态,当多个线程锁竞争不激烈的时候,锁会升级成轻量级锁,当竞争特别激烈以后,就升级成重量级锁了。
问题是,锁升级成重量级锁以后,还能不能降级程轻量级锁或者偏向锁?
打印对象头信息
添加依赖:
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
用下面一个api就够了:
ClassLayout.parseInstance(object).toPrintable();
测试代码
public class SynchronizedTest {
private static Object lock = new Object();
public static void main(String[] args)throws Exception {
lockUpgradeTest();
}
public static void lockUpgradeTest()throws Exception {
System.out.println("业务低谷期。。。。。");
// 偏向锁
biz();
System.out.println("业务高峰期开始。。。。。");
CountDownLatch startLatch = new CountDownLatch(1);
CountDownLatch stopLatch = new CountDownLatch(10);
for(int i=0; i<10; i++){
new Thread(()->{
try{startLatch.await();}catch(Exception e){}
// 大量锁竞争,升级成重量级锁
biz();
stopLatch.countDown();
}).start();
}
startLatch.countDown();
stopLatch.await();
System.out.println("业务高峰期结束");
// 过了一段时间,系统的访问量降下来了
try{Thread.sleep(3000);}catch(Exception e){}
// 此时的锁变成了轻量级锁
biz();
// 退出同步代码块变成了无锁
System.out.println("退出同步代码块以后:");
System.out.println(Thread.currentThread().getName() + ":" + ClassLayout.parseInstance(lock).toPrintable());
}
public static void biz(){
synchronized (lock){
System.out.println(Thread.currentThread().getName() + ":" + ClassLayout.parseInstance(lock).toPrintable());
try{Thread.sleep(1);}catch(Exception e){}
}
}
输出结果如下:
业务低谷期。。。。。
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 f0 34 a8 (00000101 11110000 00110100 10101000) (-1472925691)
4 4 (object header) 31 02 00 00 (00110001 00000010 00000000 00000000) (561)
8 4 (object header) 00 10 00 00 (00000000 00010000 00000000 00000000) (4096)
12 4 (loss due to the next object alignment)
业务高峰期开始。。。。
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 82 ff f7 d5 (10000010 11111111 11110111 11010101) (-705167486)
4 4 (object header) 31 02 00 00 (00110001 00000010 00000000 00000000) (561)
8 4 (object header) 00 10 00 00 (00000000 00010000 00000000 00000000) (4096)
12 4 (loss due to the next object alignment)
业务高峰期结束
main:java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) a8 f5 0f 24 (10101000 11110101 00001111 00100100) (605025704)
4 4 (object header) 99 00 00 00 (10011001 00000000 00000000 00000000) (153)
8 4 (object header) 00 10 00 00 (00000000 00010000 00000000 00000000) (4096)
12 4 (loss due to the next object alignment)
退出同步代码块以后:
main: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) 00 10 00 00 (00000000 00010000 00000000 00000000) (4096)
这就显然就发生了重量级锁(010)到轻量级锁(000)的转换。
ps:以上测试基于jdk11,如果是jdk8,请添加jvm启动参数:-XX:BiasedLockingStartupDelay=0
C:\Users\Administrator>java -version
java version "11.0.18" 2023-01-17 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.18+9-LTS-195)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.18+9-LTS-195, mixed mode)