Synchronized锁原理

Synchronized锁原理

前情提要

  1. 对于普通同步方法,锁是当前实例对象。

  2. 对于静态同步方法,锁是当前类的Class对象。

  3. 对于同步方法块,锁是Synchonized括号里配置的对象。

Synchonized在JVM里的实现原理,

JVM基于进入和退出Monitor对 象来实现方法同步和代码块同步

Monitor是有monitorenter和monitorexit指令的,线程每次执行到monitorenter,都会尝试获取对象的monitor,也就是对象的锁

锁的升级

Java对象头里的Mark Word里默认存储对象的HashCode、分代年龄和锁标记位。

无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级

1. 偏向锁

为什么有偏向锁概念?

为了减少获得锁和释放锁带来的性能消耗.

那下面来从减少消耗入手来讲

大多数情况下,锁不仅不存在多线程竞争,而且总是由同 一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁

你可以理解可重入锁,当进入拿到了锁再进入其它的就方便了,这里只是比喻。。不等同

哪些措施减少消耗的(线程ID的检查)

当一个线程访问同步块并 获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,下次进入直接测试有无ID记录,有就简单了直接盘它!

没有的话,先看看这是不是偏向锁,不是就用CAS竞争锁然后记录线程ID,是的话就用CAS直接记录自己的线程ID,

1.1 偏向锁的撤销

只要有其它线程竞争偏向锁,就会释放锁,具体流程如下:

线程1拿到偏向锁在执行,线程2来执行同步方法,先检查ID,没有,检查发现是偏向锁,CAS记录自己的线程ID,但在记录之前需要暂停线程1,然后把线程ID设置为空,然后就可以设置自己的了

1.2 偏向锁的意义

偏向锁,它的目的是消除数据在无竞争的情况下的同步原语,进一步提高程序的运行性能,不用CAS

2. 轻量级锁

2.1 加锁

  1. 线程在执行同步块之前,JVM会先在当前线程的栈桢中创建用于存储锁记录的空间

  2. 拿到锁记录指针。将对象头中的Mark Word复制到锁记录中,CAS替换那个markword

  3. 如果成功,当前线程获得锁,

  4. 如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁

2.2 解锁

  1. 轻量级解锁时,会使用原子的CAS操作将Displaced Mark Word替换回到对象头

  2. 如果成功,则表示没有竞争发生。

  3. 如果失败,表示当前锁存在竞争,锁就会膨胀成重量级锁

2.3 轻量锁的意义

轻量级锁是在无竞争的情况下使用CAS操作去消除同步使用的互斥量

3.锁的对比

优点 缺点 使用场景
偏向锁 加锁和解锁无消耗,争取不用CAS 竞争锁的情况会有撤销锁的消耗 适用单线程
轻量级锁 竞争的线程不会阻塞,利用CAS CAS会自旋消耗CPU 追求响应时间
重量级锁 不会消耗CPU,直接阻塞对方 线程会阻塞 追求吞吐量,不在乎时间和交互
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章