多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] <br/> > ### `Synchronized`同步类型 * 对于普通同步方法,锁是当前实例对象。 * 对于静态同步方法,锁是当前类的`Class`对象。 * 对于同步方法块,锁是`Synchonized`括号里配置的对象。 <br/> > ### `Synchronized`底层实现 * `JVM`基于进入和退出`Monitor`对象来实现方法同步和代码块同步,但两者的实现细节不一样。代码块同步是使用`monitorenter`和`monitorexit`指令实现的。 `monitorenter`指令是在编译后插入到同步代码块的开始位置,而`monitorexit`是插入到方法结束处和异常处,任何对象都有一个`monitor`与之关联,当且一个`monitor`被持有后,它将处于锁定状态。线程执行到`monitorenter`指令时,将会尝试获取对象所对应的`monitor`的所有权,即尝试获得对象的锁。 * `synchronized`用的锁是存在`Java`对象头里的`Mark Word` <br/> > ### `Java`对象头 * 如果对象是数组类型,则虚拟机用3个字宽(`Word`)存储对象头,如果对象是非数组类型,则用2字宽存储对象头。数组对象相对于普通对象多了一个字宽记录数组长度。 ![](https://i.loli.net/2019/03/10/5c84ba6634f78.png) <br/> > ### `Java1.6`之后锁的升级 * **偏向锁**,偏向锁使用了一种等到竞争出现才释放锁的机制,所以当其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁。偏向锁的锁记录存储在对象头中。 ![](https://i.loli.net/2019/03/10/5c84d33dc9a79.png) * **轻量级锁**,线程在执行同步块之前,JVM会先在当前线程的栈桢中创建用于存储锁记录的空间,并将对象头中的`Mark Word`复制到锁记录中,官方称为`Displaced Mark Word`。然后线程尝试使用CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。 ![](https://i.loli.net/2019/03/10/5c84d357441ed.png) * 偏向锁、轻量级锁、重量级锁对比 ![](https://i.loli.net/2019/03/10/5c84cfda13ae7.png)