Java的Lock(二)

自旋锁 VS 适应性自旋锁

堵塞或者notify一个Java线程需要操作系统切换CPU状态来完成(详情请参考11408)。这种状态切换需要耗费CPU时间。如果同步代码块种的内容过于简单。状态切换消耗的时间可能比用户代码执行的时间还要长。
在许多场景中,同步资源的锁定时间很短,为了这一段时间去切换线程,线程挂起和恢复现场的花费可能会让系统得不偿失。如果机器有多个CPU,能够让两个或以上的线程同时并行执行,就可以让后面那个请求锁的线程不放弃CPU的执行时间,看看持有锁的线程是否很快释放锁。
为了让当前线程"等一下" 我们需让当前线程进行自旋,如果在自旋完成后前面同步资源已经释放了锁。那么当前线程就可以不必堵塞而是直接获取同步资源。避免线程切换的开销。这就是自旋

在这里插入图片描述
自旋锁本身就有缺点。他不能代替堵塞。自旋等待虽然避免了线程切换的开销,但是他要占用CPU时间。如果锁被占用的时间很短。自旋等待的效果就会比较好。反之,如果锁被占用的时间很长。那么自旋的线程只会白白浪费CPU资源。所以 自旋等待的时间必须要有一定的限制。如果自旋超过一定的次数(JDK默认10次 参数PreBlockSpin)没有成功获得锁 就应该suspend

自旋锁的实现原理同样也是CAS。AtomicInteger中调用unsafe进行自增操作的源码中的do-while循环就是一个自旋操作。如果修改数值失败则通过循环来执行自旋。知道修改成功

    public final int getAndAddInt(Object o, long offset, int delta) {
        int v;
        do {
            v = getIntVolatile(o, offset);
        } while (!weakCompareAndSetInt(o, offset, v, v + delta));
        return v;
    }

适应性自旋锁

自适应意味着自旋的时间(次数)不在固定,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。如果在同一个锁对象上,自旋等待刚刚陈工获得过锁。并且持有锁的线程正在进行中,那么虚拟机就会认为这次自旋也是有可能再次成功的,进而它将允许自旋等待持续相对更长的时间。如果对于某个锁 自旋很少成功。那在以后尝试获取这个锁可以忽略掉自旋,直接堵塞。避免浪费CPU。

在自旋锁中。另有三种常见的锁形式:TicketLock CLHLock和MCSLock

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值