一个多核cpu的每个核都自带二级缓存,所有核都共享一个三级缓存。当把主内存的数据写入缓存时,也会顺便将附近的数据也写进去。这个写入的范围称为缓存行(大小64字节),多线程频繁修改同一个缓存行的数据会涉及到缓存同步的开销,影响执行的效率。Java提供了contended注解来保证被注释的字段和其他字段隔离开。
Java对象内存布局分为四个部分:MarkWord,类型指针(前两个合在一起叫做对象头),实例数据,对齐(使得对象的总大小是8的倍数)。
Object o = new Object(),可以使用openjdk提供的jol工具类查看其内存布局,该对象会占用16字节(对象头占12字节,对齐占4字节),如果把对象o当做sychronized的加锁对象,其本质就是在MarkWord打上标记。
sychronized锁升级流程:它的锁有四种状态,分别是无锁,偏向锁,轻量级锁,重量级锁。偏向锁会在jvm启动后四秒才会开放,他会把第一个线程当做vip,在锁的对象头中打好标记,后续有线程进行竞争时会自动升级成轻量级锁(自旋锁),并且他优先让vip获取这把锁。当自旋的线程太多时,锁会升级称为重量级锁(悲观锁),让操作系统维护线程的队列来挨个执行。
注:cas底层拿atomicinteger的incrementandget来说,他底层会调用compareandswapInt这个native方法,在底层c加加源码中,会通过汇编指令:lock cmpxchg 来保证原子性。说白了cas的最底层依旧是悲观锁。(只有cmpxchg是不能保证原子性的)
volatile在最底层的jvm,c加加代码中是通过汇编指令lock addl 来实现的。
两个线程按顺序打印的写法思路:
1.locksupport
2.transferqueue
3.对某个对象当锁,执行该对象的wait和notify
3.reentrolock配合condition