# 开启偏向锁
-XX:+UseBiasedLocking
# 关闭偏向锁延迟
-XX:BiasedLockingStartupDelay=0
# 查看所有的 JVM 参数
-XX:+PrintFlagsFinal
# 设置重偏向阈值
-XX:BiasedLockingBulkRebiasThreshold=20
# 批量重偏向距离上次批量重偏向的后重置的延迟时间
-XX:BiasedLockingDecayTime=25000
# 设置批量撤销阈值
-XX:BiasedLockingBulkRevokeThreshold=40
在 JVM 启动的时候会有很多线程在后台运行,例如 GC 线程,Finalizer 线程,VM Thread 线程等,会用到很多同步操作,所以在启动的前 4 秒默认创建的对象都不支持偏向,因为有默认参数
-XX:BiasedLockingStartupDelay=4000
public void test1(){
Object model2 = new Object();
System.out.println(ClassLayout.parseInstance(model2).toPrintable());
System.out.println("hash: -----" + model2.hashCode());
// 偏向锁
System.out.println(ClassLayout.parseInstance(model2).toPrintable());
binaryToDecimal(model2.hashCode());
}
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
hash: -----1975358023
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 47 92 bd (00000001 01000111 10010010 10111101) (-1114487039)
4 4 (object header) 75 00 00 00 (01110101 00000000 00000000 00000000) (117)
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
header中前8个字节按照平时习惯的从高位到低位的展示为:
00000000 00000000 00000000 01110101 10111101 10010010 01000111 00000001
对照上图。最后3位001,代表无锁状态
中间31位(01110101 10111101 10010010 01000111)换算成10进制,即为上图打印的hash值:1975358023
public static void main(String[] args) throws InterruptedException {
//JVM 启动 5 秒后创建对象
Thread.sleep(5000);
Object object = new Object();
System.out.println(ClassLayout.parseInstance(object).toPrintable());
//偏向锁
synchronized (object){
System.out.println(ClassLayout.parseInstance(object).toPrintable());
}
}
//匿名偏向
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
//偏向锁
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 68 01 b9 (00000101 01101000 00000001 10111001) (-1191090171)
4 4 (object header) f7 7f 00 00 (11110111 01111111 00000000 00000000) (32759)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
当一个对象已经计算过identity hash code,它就无法进入偏向锁状态;当一个对象当前正处于偏向锁状态,并且需要计算其identity hash code的话,则它的偏向锁会被撤销。
那什么时候对象会计算identity hash code呢?当然是当你调用未覆盖的Object.hashCode()方法或者System.identityHashCode(Object o)时候了。
public static void main(String[] args) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Object model2 = new Object();
System.out.println(ClassLayout.parseInstance(model2).toPrintable());
System.out.println("hash: -----" + model2.hashCode());
// System.out.println("hashcode:: "+Integer.toBinaryString(model2.hashCode()));
System.out.println("----------after hashcode----------");
System.out.println(ClassLayout.parseInstance(model2).toPrintable());
synchronized (model2){
System.out.println("---------after lock-------");
model2.hashCode();
System.out.println(ClassLayout.parseInstance(model2).toPrintable());
}
}
}
//偏向锁
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
hash: -----1911728085
----------after hashcode----------
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 d5 a7 f2 (00000001 11010101 10100111 11110010) (-223881983)
4 4 (object header) 71 00 00 00 (01110001 00000000 00000000 00000000) (113)
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
---------after lock-------
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) d0 a8 4c 04 (11010000 10101000 01001100 00000100) (72132816)
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
public static void main(String[] args) throws InterruptedException {
//JVM 启动 5 秒后创建对象
Thread.sleep(5000);
Object object = new Object();
Thread t1 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 进入偏向锁状态");
synchronized (object) {
System.out.println(ClassLayout.parseInstance(object).toPrintable());
}
});
t1.start();
t1.join();
new Thread(() -> {
synchronized (object) {
System.out.println(Thread.currentThread().getName() + " 进入轻量级锁状态");
System.out.println(ClassLayout.parseInstance(object).toPrintable());
}
}).start();
}
Thread-0 进入偏向锁状态
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 e8 18 a8 (00000101 11101000 00011000 10101000) (-1474762747)
4 4 (object header) a4 7f 00 00 (10100100 01111111 00000000 00000000) (32676)
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
Thread-2 进入轻量级锁状态
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 68 c8 0c 06 (01101000 11001000 00001100 00000110) (101501032)
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)
#重量级锁
public static void main(String[] args) throws InterruptedException {
//JVM 启动 5 秒后创建对象
Thread.sleep(5000);
Object object = new Object();
Thread t1 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 进入偏向锁状态");
synchronized (object) {
System.out.println(LocalDateTime.now()+",t1锁状态:"+ClassLayout.parseInstance(object).toPrintable());
}
});
t1.setName("t1");
t1.start();
t1.join();
Thread t2 = new Thread(() -> {
synchronized (object) {
System.out.println("t2:"+ClassLayout.parseInstance(object).toPrintable());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t2锁状态:"+ClassLayout.parseInstance(object).toPrintable());
}
});
t2.setName("t2");
t2.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread t3 = new Thread(() -> {
synchronized (object) {
System.out.println(Thread.currentThread().getName() + " 拿到锁,状态:");
System.out.println(ClassLayout.parseInstance(object).toPrintable());
}
});
t3.setName("t3");
t3.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("after all:"+ClassLayout.parseInstance(object).toPrintable());
}
输出结果
无锁->偏向锁->轻量级锁->重量级锁->无锁
t1锁状态:java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 40 99 29 (00000101 01000000 10011001 00101001) (697909253)
4 4 (object header) ef 7f 00 00 (11101111 01111111 00000000 00000000) (32751)
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:java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 40 99 29 (00000101 01000000 10011001 00101001) (697909253)
4 4 (object header) ef 7f 00 00 (11101111 01111111 00000000 00000000) (32751)
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锁状态:java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 4a 97 81 2a (01001010 10010111 10000001 00101010) (713135946)
4 4 (object header) ef 7f 00 00 (11101111 01111111 00000000 00000000) (32751)
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
t3 拿到锁,状态:
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 4a 97 81 2a (01001010 10010111 10000001 00101010) (713135946)
4 4 (object header) ef 7f 00 00 (11101111 01111111 00000000 00000000) (32751)
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
after all: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
总结一下,其实无锁->偏向锁->轻量级锁->重量级锁的转化过程中没那么复杂,注意记住:
(1)只有一个线程获取锁时,就是偏向锁。
(2)多个线程时,不存在竞争(多个线程顺序执行),轻量级锁。
(3)多个线程存在竞争时重量级锁。
很多时候,偏向锁->轻量级锁->重量级锁的转化过程,基本你只能看见开头和结尾,因为轻量级锁的自旋被优化不会长时间持续进行的,所以你看到的就是偏向锁到重量级锁的过程。