代码分析sychronied和Mark Word的关系
代码分析sychronied和Mark Word的关系
在JDK1.6及之后的版本中,synchronized锁得到了优化,引入了自适应自旋锁、偏向锁、轻量锁。避免了一上来就加重量级锁,优化了锁在一定条件下的性能。
在hotspot虚拟机中,对象头主要包括两部分 MarkWord和Klass Pointer。
-
MarkWord 对象标记字段,默认存储的是对象的HashCode,GC的分代年龄(2bit最大表示15)和锁的标志信息等。对于32位的虚拟机MarkWord占32bit,对于64位的虚拟机MarkWord占用64字节。 Klass Pointer Class 对象的类型指针,它指向对象对应的Class对象的内存地址。大小占4字节(指针压缩的情况下为4字节,未进行指针压缩则占8字节)。32位虚拟机MarkWord分布
1.Mark Word结构
2.锁升级过程
synchronized的锁升级过程中,锁状态升级过程为:无锁状态–> 偏向锁状态—>轻量级锁状态—>重量级锁状态。
2.0.前言:
锁的标志为如下红框标志:
2.1.无锁状态
当一个对象刚开始new出来时,该对象是无锁状态。此时偏向锁位为0,锁标志位01。
import org.openjdk.jol.info.ClassLayout; /** * @Author tangjunjie * @Date 2022/8/3 9:54 * @PackageName:面试 * @ClassName: Test * @Description: TODO * @Version 1.0 */ public class Test { public static void main(String[] args) { Test test = new Test(); System.out.println(ClassLayout.parseInstance(test).toPrintable()); } }
2.2.升级为偏向锁状态
如果有线程上锁:指的就是把markword的线程ID改为自己线程ID的过程。
public class Test2 { public static void main(String[] args) { Test test = new Test(); new Thread(()->{ synchronized(test){ System.out.println(ClassLayout.parseInstance(test).toPrintable()); } }).start(); } }
2.3.升级为轻量级锁状态
如果有线程竞争:撤销偏向锁,升级轻量级锁。线程在自己的线程栈生成LockRecord,用CAS操作将markword设置为指向自己这个线程的LockRecord的指针,设置成功者得到锁。
public class Test3 { public static void main(String[] args) throws InterruptedException { Test test = new Test(); Thread thread = new Thread(()->{ synchronized (test) { System.out.println(ClassLayout.parseInstance(test).toPrintable()); } }); thread.start(); //等待thread thread.join(); synchronized (test) { System.out.println(ClassLayout.parseInstance(test).toPrintable()); } } }
2.4.升级为重量级锁状态
如果竞争加剧 竞争加剧:有线程超过10次自旋, -XX:PreBlockSpin,或者自旋线程数超过CPU核树的一半,1.6之后,加入自适应自旋adapative self spinning,JVM自己控制; 升级重量级锁: 向操作系统升级资源,等待操作系统的调度,然后再映射会用户空间;
public class Test3 { public static void main(String[] args) throws InterruptedException { Test test = new Test(); Thread thread = new Thread(()->{ synchronized (test) { System.out.println(ClassLayout.parseInstance(test).toPrintable()); } }); thread.start(); //等待thread //thread.join(); synchronized (test) { System.out.println(ClassLayout.parseInstance(test).toPrintable()); } } }
上一篇:
通过多线程提高代码的执行效率例子
下一篇:
数据库与redis缓存一致性问题