Java并发编程----锁

JDK1.6 对锁的优化: 偏向锁、轻量级锁、自旋锁、适应性自旋锁、锁消除、锁粗化 等技术。

锁主要存在四中状态,依次是:

无锁状态

偏向锁状态

轻量级锁状态

重量级锁状态

锁可以升级不可降级,即 无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁是单向的。 这种策略是为了提高获得锁和释放锁的效率。

偏向锁和轻量级锁的区别

偏向锁和轻量级锁都是为了:在无多线程竞争时,减少重量级锁中使用操作系统互斥量的性能消耗。轻量级锁在无竞争时使用 CAS 代替互斥量。而偏向锁则把整个同步都消除。轻量级锁是为了在线程交替执行同步块时,提高性能,而偏向锁则是在只有一个线程执行同步块时,提高性能。

偏向锁

偏向于第一个获得它的线程,如果接下来没有其他线程获取该锁,那么偏向锁的线程就不需要同步!

目的:为了在无多线程竞争的情况下,减少不必要的轻量级锁执行,因为偏向锁只需在置换线程ID 时依赖一次 CAS 指令(一旦出现多线程竞争,就必须撤销偏向锁)

轻量级锁的获取及释放要依赖多次 CAS指令

偏向锁的加锁

当一个线程访问同步块并获取锁时, 会在锁对象的对象头和栈帧中的锁记录中存储锁偏向的线程ID, 以后该线程进入和退出同步块不需要CAS来加锁和解锁, 只需简单测试对象头的MarkWord是否存储着指向当前线程的偏向锁, 如果测试成功, 则表示线程已经获得了锁; 如果测试, 则再测试MarkWord中偏向锁的标识是否设为1(表示当前是偏向锁), 如果没有设置, 则用CAS竞争锁, 如果设置了, 则用CAS将锁对象的对象头中的偏向锁指向当前线程.

偏向锁的撤销

偏向锁等到竞争出现才释放锁 即当其他线程尝试竞争偏向锁时, 持有偏向锁的线程才会释放. 偏向锁的撤销要等到全局安全点(在这个时间点上没有正在执行的字节码).

先会暂停持有偏向锁的线程, 然后检查持有偏向锁的线程是否存活, 如果不处于活动状态, 则把锁对象的对象头设为无锁状态,若如果线程存活, 则对象头中的MarkWord和栈中的锁记录要么重新偏向于其它线程,要么恢复到无锁状态, 最后唤醒暂停的线程(释放偏向锁的线程)

锁竞争激烈的场合,偏向锁失效,因为可能每次申请锁的线程都不同,注意:偏向锁失败后,会先升级为轻量级锁。

轻量级锁

偏向锁失败会尝试使用轻量级锁(1.6之后加入)。

轻量级锁:为了在无多线程竞争时,减少重量级锁中使用操作系统互斥量的性能消耗。轻量级锁的加锁和解锁用CAS。

轻量级锁提升性能的依据:“对于绝大部分锁,在整个同步周期内都是不存在竞争的”,这是经验。如果没有竞争,轻量级锁使用 CAS 操作避免了使用互斥操作的开销。如果存在锁竞争,轻量级锁比重量级锁更慢!除了互斥量开销外,还有CAS操作。如果锁竞争激烈,那么轻量级锁会很快变为为重量级锁!

自旋锁和自适应自旋

轻量级锁失败后,还会进行自旋锁的优化,

即让线程执行一个忙循环,就叫做自旋。“让后面请求获取锁的线程等待一会,看看持有锁的线程是否很快就会释放锁”。

因为线程持有锁的时间一般都不长,而线程的挂起/恢复要转入内核态中完成,耗费时间较大(用户态转换到内核态耗费时间)。

自旋锁在 JDK1.6 之前默认是关闭的,通过–XX:+UseSpinning来开启。

JDK1.6及后,默认开启。注意:自旋等待不能完全替代阻塞,因为它还要占用cpu时间。

如果自旋超过了限定次数还没获得锁,则挂起线程。默认是10次,用户可以通过–XX:PreBlockSpin来更改。

JDK1.6 引入了自适应自旋锁。自旋的时间不固定,前一次同一个锁上的自旋时间锁拥有者的状态决定。

锁消除

指虚拟机即时编译器运行时,**若检测到共享数据不可能存在竞争,则锁消除。**可以节省无意义的请求锁时间。

锁粗化

将多次高频的锁请求合并成一个锁请求,避免短时间内大量请求、释放锁的性能损耗。

锁粗化前:

public void doSomethingMethod(){

  synchronized(lock){
      
	//A 操作...
      
  }
    
  //存在少量中间代码,但很快执行完毕
    
  synchronized(lock){
      
	//B操作...
      
  }
}

锁粗化后:

public void doSomethingMethod(){

	synchronized(lock){

	//A操作
        
	//中间代码
        
	//B操作

  }
}

锁粗化前:

for(int i=0;i<size;i++){
  synchronized(lock){
  //操作
  }
}

锁粗化后:

synchronized(lock){
  for(int i=0;i<size;i++)
  {
     //操作... 
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值