Java并发编程基础-锁-synchronized状态变换

      synchoronized在Jdk1.6以前一直被称为重量锁,性能较差,不多被推荐使用。synchoronized在Jdk1.6中进行了大量优化,性能与JUC中的各类锁无差,也被逐渐的被大众所接受。java

      synchoronized将锁状态记录在了对象头的MarkWord中,包含4种锁状态:无锁、偏向锁、轻量锁和重量锁,锁状态只能升级不能降级,即 无锁-->偏向锁-->轻量锁-->重量锁,目的是提升获取锁和释放锁的效率,对象几种状态的获取和释放以下:编程

  1. 偏向锁
          大多数状况下,锁不存在多线程竞争,而老是由同一线程得到,为了让线程得到锁的代价更低(消除了同步)而引入了偏向锁。当对象第一次被线程获取的时候,会把MarkWord中的偏向标识位设为01(偏向锁状态),同时使用CAS操做将该线程的ID记录在MarkWord中,若是CAS操做成功,则该线程每次进入到这个锁相关的同步块时,虚拟机均可以不进行任何同步操做。
          当有另外的线程获取这个锁时,偏向模式就结束了,根据锁对象目前是否处于锁定的状态,会恢复到无锁状态(01)或者变为轻量锁状态(00),借用《Java并发编程艺术》的一张图,以下所示:


     
  2. 轻量锁
          线程在执行同步块以前,JVM会先在当前线程栈帧中建立用于存储锁记录的空间,并将对象头中的MarkWord复制到锁记录中,官方称为Displaced Mark Word。而后线程尝试使用CAS操做将对象头中的MarkWord替换为指向锁记录的指针,若是成功,当前线程得到锁,若是失败,表示有其余线程竞争锁,当前线程开始自旋,若是自旋完成必定次数(多是50次、100次,能够经过启动参数配置自旋次数)当前线程尚未获取到锁,那么锁会开始膨胀,进化为重量锁。
          轻量锁解决时,使用CAS操做将Displace Mark Word 替换会对象头,若是成功,则表示没有竞争,若是失败(已经有线程将锁的状态修改成重量锁),则释放锁并唤醒等待线程,借用《Java并发编程艺术》的一张图,以下所示:


     
  3. 重量锁
          由上面的轻量锁升级而来,一旦升级到重量锁,那么其余线程获取锁,都会被阻塞,等待释放锁。当持有锁的线程释放锁并唤醒等待线程时,等待的线程就会开始新一轮的竞争。

理解:多线程

  • 当单个线程进入同步块,使用偏向锁,成本低,不须要使用CAS操做
  • 当两个线程依次进入同步块,使用轻量锁,单线程自旋也不会形成太多的CPU损耗
  • 当两个或多个线程进入同步快,使用重量锁,让获取锁的线程以外的线程进行阻塞等待唤醒,效率更高。

PS:使用openjdk的JOL(Java Object Layout)工具能够观察各类线程竞争锁时,Java对象头的状态。并发

参考书籍及网址:工具

  • 《Java并发编程艺术》

PS:研究基于MAC+Idea+JDK1.8 64位性能

Keep Calm and Carry on!优化

相关文章
相关标签/搜索