一、为什么需要自旋锁与适应性自旋锁

1.1、自旋锁的提出背景

  由于在多处理器环境中某些资源的有限性,有时需要互斥访问,这时候就需要引入锁的概念,只有获取了锁的线程才能对资源进行访问,由于多线程的核心是CPU的时间分片,所以同一时刻只能有一个线程获取到锁。那么就面临一个问题,那么没有获取到锁的线程应该怎么办?
  通常有两种处理方式:一种是没有获取到锁的线程就一直循环等待判断该资源是否已经释放锁,这种锁叫做自旋锁,它不用将线程阻塞起来(NON-BLOCKING);还有一种处理方式就是把自己阻塞起来,等待重新调度请求,这种叫做互斥锁。
  使用自旋锁的最大的一个好处是因为自旋锁存在于linux内核中,如果持有锁的线程能够在短时间内释放锁,那么那些等待竞争锁的线程就不需要做内核态与用户态之间的切换从而进入阻塞状态。

二、自旋锁与适应性自旋锁底层原理解析

2.1、自旋锁与适应性自旋锁底层原理解析

  自旋锁早在JDK1.4 中就引入了,只是当时默认时关闭的。在JDK 1.6后默认为开启状态。自旋锁本质上与阻塞并不相同,先不考虑其对多处理器的要求,如果锁占用的时间非常的短,那么自旋锁的性能会非常的好,相反,其会带来更多的性能开销(因为在线程自旋时,始终会占用CPU的时间片,如果锁占用的时间太长,那么自旋的线程会白白消耗掉CPU资源)。因此自旋等待的时间必须要有一定的限度,如果自旋超过了限定的次数仍然没有成功获取到锁,就应该使用传统的方式去挂起线程了,在JDK定义中,自旋锁默认的自旋次数为10次,用户可以使用参数-XX:PreBlockSpin来更改。 可是现在又出现了一个问题:如果线程锁在线程自旋刚结束就释放掉了锁,那么是不是有点得不偿失。所以这时候我们需要更加聪明的锁来实现更加灵活的自旋。来提高并发的性能。(这里则需要自适应自旋锁!)
  在JDK 1.6中引入了自适应自旋锁。这就意味着自旋的时间不再固定了,而是由前一次在同一个锁上的自旋 时间及锁的拥有者的状态来决定的。如果在同一个锁对象上,自旋等待刚刚成功获取过锁,并且持有锁的线程正在运行中,那么JVM会认为该锁自旋获取到锁的可能性很大,会自动增加等待时间。比如增加到100此循环。相反,如果对于某个锁,自旋很少成功获取锁。那再以后要获取这个锁时将可能省略掉自旋过程,以避免浪费处理器资源。有了自适应自旋,JVM对程序的锁的状态预测会越来越准确,JVM也会越来越聪明。

三、自旋锁与适应性自旋锁的使用

3.1、自旋锁的实现

public class SpinLockTest {private AtomicBoolean available =new AtomicBoolean(false);public void lock(){//循环检测尝试获取锁while(!tryLock()){//doSomething...}}public boolean tryLock(){//尝试获取锁,成功返回true,失败返回falsereturn available.compareAndSet(false,true);}public void unLock(){if(!available.compareAndSet(false,true)){throw new RuntimeException("释放锁失败");}}
}

3.2、适应性自旋锁的实现

  自旋等待虽然避免了线程切换的开销,但它要占用处理器时间。如果锁被占用的时间很短,自旋等待的效果就会非常好。反之,如果锁被占用的时间很长,那么自旋的线程只会白浪费处理器资源。所以,自旋等待的时间必须要有一定的限度,如果自旋超过了限定次数(默认是10次,可以使用-XX:PreBlockSpin来更改)没有成功获得锁,就应当挂起线程。 自旋锁的实现原理同样也是CAS,AtomicInteger中调用unsafe进行自增操作的源码中的do-while循环就是一个自旋操作,如果修改数值失败则通过循环来执行自旋,直至修改成功。
   改进的自旋锁主要有TicketLock、CLHLock、MCSLock,这几种自旋锁改进方案内容比较多,实现方式参考 几种自旋锁的java实现824b2e4f1eed

四、自旋锁与适应性自旋锁中存在的问题与优化方案

   自旋锁尽可能的减少线程的阻塞,这对于锁的竞争不激烈,且占用锁时间非常短的代码块来说性能可以大幅度提升,因为自旋的消耗会小于线程阻塞挂起再唤醒的操作的消耗,这些操作会导致线程发生两次上下文切换!

   但是如果锁的竞争激烈,或者持有锁的线程需要长时间占用锁执行同步块,这时候就不适合使用自旋锁了,因为自旋锁在获取锁前一直都是占用cpu做无用功,同时有大量线程在竞争一个锁,会导致获取锁的时间很长,线程自旋的消耗大于线程阻塞挂起操作的消耗,其它需要cup的线程又不能获取到cpu,造成 cpu的浪费。所以这种情况下我们要关闭自旋锁;自旋锁时间阈值(1.6 引入了适应性自旋锁)。

   自旋锁的目的是为了占着CPU的资源不释放,等到获取到锁立即进行处理。但是如何去选择自旋的执行时间呢?如果自旋执行时间太长,会有大量的线程处于自旋状态占用CPU资源,进而会影响整体系统的性能。因此自旋的周期选的额外重要!

   JVM 对于自旋周期的选择,Jdk1.5这个限度是一定的写死的,在1.6引入了适应性自旋锁,适应性自旋锁意味着自旋的时间不在是固定的了,而是由前一次在同一个锁上的自旋时间以及锁的拥有者的状态来决定,基本认为一个线程上下文切换的时间是最佳的一个时间,同时JVM还针对当前CPU的负荷情况做了较多的优化,如果平均负载小于CPUs则一直自旋,如果有超过(CPUs/2)个线程正在自旋,则后来线程直接阻塞,如果正在自旋的线程发现Owner发生了变化则延迟自旋时间(自旋计数)或进入阻塞,如果 CPU 处于节电模式则停止自旋,自旋时间的最坏情况是CPU的存储延迟(CPU A 存储了一个数据,到CPU B得知这个数据直接的时间差),自旋时会适当放弃线程优先级之间的差异。

  • 更多细节需要完善,后面博文会持续更新更多底层细节原理

java锁结构之自旋锁与适应性自旋锁相关推荐

  1. java适应性自旋锁_深夜!小胖问我,什么是自旋锁?怎么使用?适用场景是啥?...

    自旋锁 & 非自旋锁 什么是自旋?字面意思是 "自我旋转" .在 Java 中也就是循环的意思,比如 for 循环,while 循环等等.那自旋锁顾名思义就是「线程循环地去 ...

  2. 1.6的锁优化(适应性自旋/锁粗化/锁削除/轻量级锁/偏向锁)

    高效并发是JDK 1.6的一个重要主题,HotSpot虚拟机开发团队在这个版本上花费了大量的精力去实现各种锁优化技术,如适应性自旋(Adaptive Spinning).锁削除(Lock Elimin ...

  3. 自旋锁与适应性自旋锁

    自旋锁与适应性自旋锁 概念引入 自旋锁与非自旋锁流程图 自旋锁的缺陷 自旋锁的实现原理 自适应自旋锁 概念引入 在介绍自旋锁之前,我们需要介绍一些前提知识来帮助大家理解自旋锁的概念. 阻塞或唤醒一个J ...

  4. JUC并发编程系列详解篇十四(自旋锁 VS 适应性自旋锁)

    自旋锁 由于在多处理器环境中某些资源的有限性,有时需要互斥访问(mutual exclusion),这时候就需要引入锁的概念,只有获取了锁的线程才能够对资源进行访问,由于多线程的核心是CPU的时间分片 ...

  5. 非自旋锁VS自旋锁和适应性自旋锁

    1.什么是自旋 所谓自旋,就是指当有另外一个线程来竞争锁时,这个线程会在原地循环等待,而不是把该线程给阻塞,直到那个获得锁的线程释放锁之后,这个线程就可以马上获得锁的.锁在原地循环的时候,是会消耗cp ...

  6. 锁9---自旋锁 VS 适应性自旋锁

    锁9-自旋锁 VS 适应性自旋锁 ************ 如有侵权请提示删除 *************** 文章目录 锁9---自旋锁 VS 适应性自旋锁 自旋锁 1.概念: 2.提出背景 3.自 ...

  7. java让线程空转_Java锁:悲观/乐观/阻塞/自旋/公平锁/闭锁,锁消除CAS及synchronized的三种锁级别...

    JAVA LOCK 大全 [TOC] 一.广义分类:乐观锁/悲观锁 1.1 乐观锁的实现CAS (Compare and Swap) 乐观锁适合低并发的情况,在高并发的情况下由于自旋,性能甚至可能悲观 ...

  8. java的markword_【转帖】Java工具结构与锁实现原理及MarkWord详解

    Java工具结构与锁实现原理及MarkWord详解 https://www.pianshen.com/article/2382167638/ 我们都知道,Java工具存储在堆(Heap)内存.那么一个 ...

  9. Java对象结构与锁实现原理及MarkWord详解

    阅读本博客前,需要了解基本的同步概念,传送门:http://note.youdao.com/noteshare?id=7f10475c6bb01658b955eaca531c0be6&sub= ...

最新文章

  1. 【数据结构与算法】之深入解析“缺失的第一个正数”的求解思路与算法示例
  2. mysql select效率_Mysql优化之selectcount效率_MySQL
  3. 完美解决header,footer等HTML5标签在IE(IE6/IE7/IE8)无效的方法
  4. css html 语法,CSS基础语法
  5. ElasticSearch 7 正式发布!
  6. centos下eclipse的安装
  7. html 显示接口数据格式化,科技常识:html格式化输出JSON示例(测试接口)
  8. 08.Prevent exceptions from leaving destructors
  9. HDOJ(HDU) 1563 Find your present!(异或)
  10. 003.ASP.NET MVC集中管理Session
  11. 数值分析(计算方法)
  12. 好用在线html编辑器,求一款好用的html在线编辑器
  13. 系列微课|《Python程序设计(第3版)》第4章
  14. 关于ubuntu自带英文版firefox浏览器,安装evernote剪藏插件总是登录到国际版及firefox插件无法下载
  15. Edge、Chrome 1月12日之后继续使用Flash的方法(超级专业,高能预警)
  16. 微信小程序使用云函数进行mysql操作
  17. linux 创建文件 permission denied,mac linux 创建文件 Permission denied
  18. js中定时器与延时器的用法
  19. iphone11夜景鬼影分析
  20. Linux下安装EDB

热门文章

  1. Udacity利用深度学习玩赛车小游戏
  2. BOOTP引导程序协议
  3. 100套炫酷网站错误页Html5模板(403,404,500等)
  4. 游戏的基本因素 余建斌
  5. 前端模拟手机浏览器,调移动端样式
  6. 用心写就的雅思攻略——从7到8的飞跃(转自OL)
  7. 【知了堂学习笔记】_Java笔试题整理(二)
  8. Linux 信号signal\sigaction
  9. magic squire幻方的学习——奇数阶幻方
  10. hibetnate 的inverse属性的作用