您的位置:首页 > 编程语言 > Java开发

Java SE 1.6对synchronized的优化

2017-08-23 23:40 239 查看
在多线程并发编程中Synchronized一直是元老角色,很多人称呼他为重量级锁。但随着Java SE 1.6对synchronized进行优化之后,有些情况下并不会那么重。

在Java SE 1.6中,系统引进了“偏向锁”,“轻量锁”,以及原先就有的“重量级锁”。锁的四种级别由低到高:“无锁”,“偏向锁”,“轻量锁”,“重量级锁”。这四种状态会随着竞争情况逐渐升级。但一旦升级,就不能降
4000
级,这是JVM的策略,为了提高获得锁和释放锁的效率。但这些转换对于使用锁的用户来说都是透明的。
三种锁的优缺点,适用情况:



锁的升级

如上表,偏向锁、轻量级锁、重量级锁三者各自的应用场景:

偏向锁:只有一个线程进入临界区;
轻量级锁:多个线程交替进入临界区,且快速执行结束;
重量级锁:多个线程同时进入临界区。

上述的情况一是偏向锁的适用场景,此时当Thread#1进入临界区时,JVM会将lockObject的对象头Mark Word的锁标志位设为“01”,同时会用CAS操作把Thread#1的线程ID记录到Mark Word中,此时进入偏向模式。所谓“偏向”,指的是这个锁会偏向于Thread#1,若接下来没有其他线程进入临界区,则Thread#1再出入临界区无需再执行任何同步操作。也就是说,若只有Thread#1会进入临界区,实际上只有Thread#1初次进入临界区时需要执行CAS操作,以后再出入临界区都不会有同步操作带来的开销。

然而情况一是一个比较理想的情况,更多时候Thread#2也会尝试进入临界区。若Thread#2尝试进入时Thread#1已退出临界区,即此时lockObject处于未锁定状态,这时说明偏向锁上发生了竞争(对应情况二),此时会撤销偏向,Mark Word中不再存放偏向线程ID,而是存放hashCode和GC分代年龄,同时锁标识位变为“01”(表示未锁定),这时Thread#2会获取lockObject的轻量级锁。因为此时Thread#1和Thread#2交替进入临界区,所以偏向锁无法满足需求,需要膨胀到轻量级锁。

再说轻量级锁什么时候会膨胀到重量级锁。若一直是Thread#1和Thread#2交替进入临界区,那么没有问题,轻量锁hold住。一旦在轻量级锁上发生竞争,即出现“Thread#1和Thread#2同时进入临界区”的情况,轻量级锁就hold不住了。 (根本原因是轻量级锁没有足够的空间存储额外状态,此时若不膨胀为重量级锁,则所有等待轻量锁的线程只能自旋,可能会损失很多CPU时间)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java concurrent jvm