zoukankan      html  css  js  c++  java
  • JUC包Lock机制的支持--AQS

    在上一次总结中,提到了JUC包下使用Lock接口实现同步的方法,以及和Synchronized关键字的一些比较,那么使用Lock完成锁机制的底层支持又是什么呢?总结如下:

    1 AQS是什么

     AQS是一个抽象类,全名AbstractQueuedSynchronizer,意为抽象的队列式同步器。他在整个同步机制的作用如下:

          

    AQS是一个中间的工具类,它的基础是CAS操作,和volatile关键字的支持。最终还是给Lock接口下的类提供服务的,具体包括获取对象锁的方法、将获取锁失败线程挂挂到等待队列、维护队列等等

    2 AQS是如何与Lock合作的

    在上次总结以及给出AQS与Lock接口下的实现类的关系,这次更详细的总结一下:

            

    在创建ReentrantLock时可以指定公平or不公平锁,非公平锁,即对于同一个锁,不保证先到的线程会首先获得。以非公平锁为例,Lock接口下的ReentrantLock类持有一个AQS抽象类下的实现类NofairSync类,ReentrantLock又是由一个对象持有,我们可以简单的认为一个对象持有一个AQS类实例,这个AQS类实例有一个成员变量state(int)则是关键之关键。

    state变量代表所属对象的状态,state == 0 则说明所属对象还没有被线程获取到锁,否则说明以及有线程已经获取到锁正在访问同步块。线程通过Lock机制获取锁的过程其实就是修改对象的state变量的过程,这个修改过程正是由CAS操作完成的,所以state也需要由volatile关键字修饰,保证state变量的可见性,即CAS操作时变量值是最新的。说白了,Synchronized机制下通过对象头的几个标志位的值来表示对象的锁状态。而Lock机制下则通过让对象持有AQS的state变量,用state变量的值表示对象的锁状态。

    如果CAS的将state从0改为1失败,则调用acquire(x),x表示获取锁次数 ,这个方法再调用tryAcquire(x):判断一次state当state == 0则CAS修改state为1,每次重入+1,unlock则-1;当state != 0 ,且发现锁的所有者就是本线程,则直接state+x,实现重入锁的功能。

    获取锁的代码和过程很复杂,这里只是从最顶层的角度描述大致过程,很多细节需要大量篇幅叙述。想了解的可以看看源码。

    3 获取锁失败线程怎么办

    如果tryAcquire(x)返回false,即发现state != 0,或者 state == 0  CAS修改失败,且该锁的当前所有者不是本线程无法重入,则表明获取锁失败。这个时候,就会调用AQS下的 addWaiter(Node n)将失败的线程包成一个节点,用CAS的方法插入一个CLH(基于链表的、公平的自旋锁)的双向队列的尾部tail节点之后成为新的tail节点。  若CAS插入失败,则自旋调用enq(Node n)再次使用CAS尝试重新插入。

    对于新进入队列的节点,不会立即将它阻塞,判断节点的前驱节点如果是头节点则再次tryAcquire()尝试获取锁,成功就将本线程设为头节点,若还是失败判断节点状态决定是否则调用lockSupport.park () 阻塞本线程。

    (图片来源于网络)

    队列的节点都有一个状态位,该状态位与线程状态密切相关:

    CANCELLED =  1:因为超时或者中断,节点会被设置为取消状态,被取消的节点时不会参与到竞争中的,他会一直保持取消状态不会转变为其他状态;

    SIGNAL    = -1:其后继节点已经被阻塞了,到时需要进行唤醒操作;

    CONDITION = -2:表示这个结点在条件队列中,因为等待某个条件而被阻塞;

    0:新建节点一般都为0。

    AQS这里很复杂,这里只是从最顶层的角度做了一些粗浅的总结,并不深入。

  • 相关阅读:
    LOJ.6435.[PKUSC2018]星际穿越(倍增)
    webpack---style-loader的配置:insertAt 和insert
    react-native项目启动报错——watchman安装问题(mac pro)
    js基础---event.target/ event.currentTarget/this的区别
    js基础---querySelector系列和getElementsBy系列获取页面元素的最大差异(返回值的属性区别)
    js基础----用户在浏览器输入网址后页面的加载
    js基础----dom节点使用console.log打印始终是最新的现象(待验证)
    js基础---嵌套循环中的break使用
    环境变量的配置之——全局安装@vue/cli脚手架,出现vue不是内部或外部命令(Windows)
    Chocolatey 和 Scoop的安装和介绍 (windows)
  • 原文地址:https://www.cnblogs.com/shen-qian/p/11226380.html
Copyright © 2011-2022 走看看