synchronized是非公平锁,允许插队。
在无锁状态下的一个对象堆内存的布局:
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.10</version>
</dependency>
public class ClassLayoutDemo {
public static void main(String[] args) {
ClassLayoutDemo classLayoutDemo = new ClassLayoutDemo();
System.out.println(ClassLayout.parseInstance(classLayoutDemo).toPrintable());
}
}
打印出来-------------------
com.heimen.cn.test.ClassLayoutDemo 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) 05 c1 00 f8 (00000101 11000001 00000000 11111000) (-134168315)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
截取重要的一部分:
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)
16进制:
00 00 00 00 00 00 00 01
64位(2进制):
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000 0 01(无锁状态)
为啥把01移到右边,是【大端存储和小端存储】的问题,以后研究一下。
然后加个锁:
public static void main(String[] args) {
ClassLayoutDemo classLayoutDemo = new ClassLayoutDemo();
synchronized (classLayoutDemo){
System.out.println("locking...");
System.out.println(ClassLayout.parseInstance(classLayoutDemo).toPrintable());
}
}
输出结果:(轻量级锁)
轻量级锁是多次CAS(自旋锁),因为线程获取锁之后从执行到释放时间很短,如果直接用重量级锁,还是有很多开销,所以让锁自旋一次或多次就可以获取锁,就没有必要升级到重量级锁进行阻塞,也就是在相对来说自旋的次数比较少的情况下获取到锁的这样的性能是比重量级锁总体上性能更加占优势。
com.heimen.cn.test.ClassLayoutDemo object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) d0 d8 78 08 (11010000 11011000 01111000 00001000) (142137552)
4 4 (object header) 00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
8 4 (object header) 05 c1 00 f8 (00000101 11000001 00000000 11111000) (-134168315)
12 4 (loss due to the next object alignment)
重量级锁: 每一个对象里都有一个对象监视器,重量级锁的实现是通过这个对象监视器来实现的,
public class LockDemo {
public static void main(String[] args) {
LockDemo lockDemo = new LockDemo();
Thread t1 = new Thread(()->{
synchronized (lockDemo){
System.out.println("t1抢占到锁");
System.out.println(ClassLayout.parseInstance(lockDemo).toPrintable());
}
});
t1.start();
synchronized (lockDemo){
System.out.println("Main抢占到锁");
System.out.println(ClassLayout.parseInstance(lockDemo).toPrintable());
}
}
}
输出:
Main抢占到锁
com.heimen.cn.test.LockDemo object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 0a 98 af b1 (00001010 10011000 10101111 10110001) (-1313892342)
4 4 (object header) 86 7f 00 00 (10000110 01111111 00000000 00000000) (32646)
8 4 (object header) 05 c1 00 f8 (00000101 11000001 00000000 11111000) (-134168315)
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抢占到锁
com.heimen.cn.test.LockDemo object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 0a 98 af b1 (00001010 10011000 10101111 10110001) (-1313892342)
4 4 (object header) 86 7f 00 00 (10000110 01111111 00000000 00000000) (32646)
8 4 (object header) 05 c1 00 f8 (00000101 11000001 00000000 11111000) (-134168315)
12 4 (loss due to the next object alignment)
看到是 010 重量级锁的标记。如果在t1.start();后加上Thread.sleep(10000),就不会是重量级锁了,就会是 000 (轻量级锁)了。