jvm synchronized底层设计与优化

通常来讲synchronized被当做重量级锁来使用,但其实它并不是一味地阻塞当前线程,而是通过锁升级等方式进行了很多的优化。

一 重量级锁(互斥同步或悲观锁)

最原始的,也是synchronized与生俱来的同步方式。
使用synchronized可以指定一个锁对象,如果没有指定对象就是用当前对象的实例(非static的普通方法)或者当前对象的class对象(被static修饰的方法)作为被指定的锁对象。锁对象的锁信息放在锁对象的头信息里,由于考虑到提高虚拟机空间使用效率等原因,这部分空间会根据不同的锁状态储存不同的锁信息。如下图所示。标志位、储存内容都在对象头信息中一个叫MarkWord的地方。

储存内容标志位
分代年龄、哈希码、偏向锁开启位01(未锁定)
轻量级锁记录指针00(轻量级锁定)
重量级锁记录指针10(重量及锁定)
无记录11(gc)
偏向线程ID、epoch、分代年龄、偏向锁开启位01(可偏向)

执行synchronized代码时,先尝试获取锁对象的锁,如果当前对象锁的计数器是0(表示当前无线程竞争)或者计数器不为0单线程是同一个线程(同一个线程重入锁),则当前线程获取锁,将锁计数器加一;若释放锁则减一;若获取对象失败则当前线程阻塞等待,直到另一个线程释放。

二 轻量级锁(乐观锁)

jdk1.6之后加入的新型锁机制,由于大多数时候是非并发状态,此时重量级锁消耗资源高且无用,因此加入了轻量级锁。
加锁过程如下:若尚未被锁定(状态为01)则在当前线程的栈频中创建一个Lock Record的锁空间,用于copy锁信息,copy完成后,使用cas操作,将MarkWord中的储存内容换成指针(指针执行栈频中Lock Record位置),再将MarkWord的标志位变为00。若cas操作失败,则查看是否MarkWord中指针是否已经指向本线程的栈频,若是,则线程已经持有此对象的锁,若否,则线程被抢占,进入阻塞状态。
解锁过程如下:同样使用cas操作,若指针依然指向本线程栈频,则将Lock Record中的信息复制到MarkWord中。若cas失败则存在其他并发线程,需释放锁的同时唤醒被阻塞的线程。
轻量级锁适用于基本上不存在竞争的情况。一旦存在竞争不仅导致当前线程进入阻塞状态,并且还有额外的cas开销。

三 偏向锁

jdk1.6之后加入的新型锁机制,如果说轻量级锁防止了非并发情况下的阻塞操作,那么偏向锁就是去掉了单线程操作下cas操作。偏向锁很适合初始化时,在循环中重复访问的需加锁的代码。如创建ConcurrentHashMap后循环add操作。
所谓偏向锁,就是加锁代码在第一次被线程访问时在MarkWord中记录下线程id,如果以后还是这个线程在没有并发的情况下访问了,就可以进入代码块,如果有其他线程进入代码块,会触发锁升级即,偏向锁变为轻量级锁。偏向锁关闭后不会再进入。
下图是偏向锁、轻量级锁、重量级锁转换模式。
偏向锁、轻量级锁、重量级锁转换模式

四 自旋锁与自适应锁

jdk1.4.2之后引入的锁机制,在轻量级锁晋升到重量级锁时可以加入自旋锁或者自适应锁。
由于阻塞操作占用时间较长,有时甚至比同步代码更加耗费资源,所以使用多次循环使用cas尝试获取锁的方式,来减少并发状况下阻塞的发生。如果成功获取则跳出循环,进入普通轻量级锁模式;如果失败则继续循环,直到次数用尽,阻塞当前线程。
自旋锁循环次数默认是10次。但jdk1.6开始,循环锁升级为自适应锁,循环次数由虚拟机掌控。如果上次自旋获取同步代码的锁的时间较短,这次自旋时间就会延长,因为虚拟机认为这段代码执行很快,使用自旋很容易获取到锁;相反,就会缩短自旋时间,甚至会取消自旋,以节省消耗。

五 锁粗化与锁消除

锁粗化,当synchronized代码块被写在一个循环里,重复的被不停加锁解锁,会让性能受损,虚拟机会将锁范围粗化到循环体外边。
锁消除,当synchronized代码块被用于一个根本不会发生并发的地方,比如在一个方法里创建StringBuffer并使用append方法。虚拟机运行时会启用逃逸分析,消除锁。
锁粗化与锁消除体现了虚拟机强大的一面,但不应该是程序员写出低质量代码的借口。如上述情况应使用非并发的StringBuider,而并非并发类StringBuffer。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值