参考之前写的博客:
Java 并发编程(三):synchronized、volatile 详解
java对象结构
梳理一下整体结构:
1、synchronized关键字(锁:阻塞式、重量级)、对象锁机制monitor;
2、CAS(锁:乐观、非阻塞、无锁)、以及存在的三个问题;
3、Java对象头结构:
- 包含:MarkWord、Klass Word、数组长度、对象体、对齐字;
- Klass Word:JVM通过这个指针确定对象是哪个类的实例。
- MarkWord中锁的四种状态:无锁01、偏向锁01、轻量级锁00、重量级锁10;
- 偏向锁:不需要进行CAS操作来加锁和解锁;
- 轻量级锁:使用CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁;
- 锁的升级过程:
- 初期锁对象刚创建时,还没有任何线程来竞争,对象的Mark Word是下图的第一种情形,这偏向锁标识位是0,锁状态01,说明该对象处于无锁状态(无线程竞争它)。
- 当有一个线程来竞争锁时,先用偏向锁,表示锁对象偏爱这个线程,这个线程要执行这个锁关联的任何代码,不需要再做任何检查和切换,这种竞争不激烈的情况下(准确的说:只有一个线程、没有竞争的情况下),效率非常高。这时Mark Word会记录自己偏爱的线程的ID,把该线程当做自己的熟人。如下图第二种情形。
- 当有两个线程开始竞争这个锁对象,情况发生变化了,不再是偏向(独占)锁了,锁会升级为轻量级锁,两个线程公平竞争,哪个线程先占有锁对象并执行代码,锁对象的Mark Word就执行哪个线程的栈帧中的锁记录。如下图第三种情形。
- 如果竞争的这个锁对象的线程更多,导致了更多的切换和等待,JVM会把该锁对象的锁升级为重量级锁,这个就叫做同步锁,这个锁对象Mark Word再次发生变化,会指向一个监视器对象,这个监视器对象用集合的形式,来登记和管理排队的线程。如下图第四种情形。
4、volatile关键字(锁:非阻塞、轻量级):
- 涉及JMM、happens-before,三大性质:原子、可见、一致;
- volatile的内存语义实现:内存屏障(4种类型);
-
volatile写是在前面和后面分别插入内存屏障,而volatile读操作是在后面插入两个内存屏障;