monitor 锁优化


前言

提示:本文我们来讲解下synchronized 锁的优化过程,详情请移步《深入理解java虚拟机》的第13章。
参考文章:


一、各种锁状态

1. 自旋与自适应自旋

自旋定义:
实际中当现有的处理器在执行任务时,有线程在等待时,可能只需要等待很短的时间即可,因此就让此线程不放弃处理器的执行时间,空循环一会儿,等待一下,即可获得。

自适应自旋:
JDK 1.6 后加入了自适应自旋,即JVM会根据之前等待获得资源的情况来适当的缩短或者增加甚至直接不再使用空循环的等待策略

2. 锁消除

锁消除是指虚拟机即时编译器在运行时,对一些代码上要求同步,但是检测到对象不可能逃逸出去时(基于逃逸分析技术),就会把这些数据当作栈数据对待,是线程私有的,自然也就无需加锁。

示例:

public String concatString(String s1,String s2,String s3){ return s1+s2+s;}

// javac 之后转换成如下
// jdk 1.5 之前转换成 StringBuffer 进行 apped 操作
// 1.5 之后 转换成 StringBuilder 进行 append
public String concatString(String s1,String s2,String s3){ 
   StringBuffer sb=new StringBuffer(); 
   // 由于StringBuffer 的append都有 synchronized,
   // 如果没有锁消除技术,就需要反复加锁
   sb.append(s1);
   sb.append(s2); 
   sb.append(s3);
   return sb.toString(); 
  }

由于StringBuffer 的append都有 synchronized,如果没有锁消除技术,就需要反复加锁,但是事实上,sb对象是逃逸不出这个方法的作用域的,自然也就不会被其他线程访问,因此,根本无需加锁。

3. 锁粗化

示例代码:

StringBuffer sb=new StringBuffer(); 

public String concatString(String s1,String s2,String s3){ 
   sb.append(s1);
   sb.append(s2); 
   sb.append(s3);
   return sb.toString(); 
  }

以它为例,虚拟机不必为每个append进行加锁,直接对append(s1)开始,到append(s3)结束即可。这就是锁粗化。

4 . 轻量级锁

主要作用:
轻量级锁的本意是在没有多线程竞争的前提下,使用CAS操作 减少传统的重量级锁使用操作系统互斥量产生的性能消耗。

4.1 锁状态的标志位

在这里插入图片描述

4.2 上锁过程

简单地介绍了对象的内存布局后,我们把话题返回到轻量级锁的执行过程上。在代码进 入同步块的时候,如果此同步对象没有被锁定(锁标志位为“01”状态),虚拟机首先将在当 前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储锁对象目前的Mark Word的拷贝(官方把这份拷贝加了一个Displaced前缀,即Displaced Mark Word),此时还没有进行拷贝操作,这只是栈和堆分配情况。下面马上就会提到指针应用即获取轻量级锁的过程。这时候线 程堆栈与对象头的状态如图:
在这里插入图片描述
然后,虚拟机将使用CAS操作尝试将对象的Mark Word更新为指向Lock Record的指针。 如果这个更新动作成功了,那么这个线程就拥有了该对象的锁,并且对象Mark Word的锁标 志位(Mark Word的最后2bit)将转变为“00”,即表示此对象处于轻量级锁定状态,这时候线 程堆栈与对象头的状态如图:
在这里插入图片描述

4.3 解锁

它的解锁过程也是通过CAS操作来进行的,如果对 象的Mark Word仍然指向着线程的锁记录,那就用CAS操作把对象当前的Mark Word和线程中 复制的Displaced Mark Word替换回来,如果替换成功,整个同步过程就完成了。如果替换失 败,说明有其他线程尝试过获取该锁,那就要在释放锁的同时,唤醒被挂起的线程。

5. 偏向锁

5.1 主要作用

如果说轻量级锁是在无竞争的情况下使用CAS操作去消 除同步使用的互斥量,那偏向锁就是在无竞争的情况下把整个同步都消除掉。

5.2 怎么工作

当锁对象第一次被线程获取的时候, 虚拟机将会把对象头中的标志位设为“01”,即偏向模式。同时使用CAS操作把获取到这个锁 的线程的ID记录在对象的Mark Word之中,如果CAS操作成功,持有偏向锁的线程以后每次 进入这个锁相关的同步块时,虚拟机都可以不再进行任何同步操作。
当有另外一个线程去尝试获取这个锁时,偏向模式就宣告结束。

二、锁优化的过程

锁的只能升级,不能降级:
先由无锁升级为偏向锁,偏向锁对于整个操作过程没有加锁。偏向锁失败后,升级为轻量级锁,轻量级锁是真正的要获取锁的。轻量级锁能够提升程序性能的依据是“对绝大部分的锁,在整个同步周期内都不存在竞争”,注意这是经验数据。需要了解的是,轻量级锁所适应的场景是线程交替执行同步块的场合,如果存在同一时间访问同一锁的场合,就会导致轻量级锁膨胀为重量级锁。轻量级锁失败后,虚拟机为了避免线程真实地在操作系统层面挂起,还会进行一项称为自旋锁的优化手段。这是基于在大多数情况下,线程持有锁的时间都不会太长,如果直接挂起操作系统层面的线程可能会得不偿失,毕竟操作系统实现线程之间的切换时需要从用户态转换到核心态,这个状态之间的转换需要相对比较长的时间,时间成本相对较高,因此自旋锁会假设在不久将来,当前的线程可以获得锁,因此虚拟机会让当前想要获取锁的线程做几个空循环(这也是称为自旋的原因),一般不会太久,可能是50个循环或100循环,在经过若干次循环后,如果得到锁,就顺利进入临界区。如果还不能获得锁,那就会将线程在操作系统层面挂起,这就是自旋锁的优化方式,这种方式确实也是可以提升效率的。最后没办法也就只能升级为重量级锁了。


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值