首页 > 其他 > 详细

AQS(AbstractQueuedSynchronizer)--队列同步器

时间:2020-09-01 16:24:28      阅读:48      评论:0      收藏:0      [点我收藏+]

1.介绍:

   AQS指的是AbstractQueuedSynchronizer(队列同步器),

  AQS是JDK下提供的一套用于实现基于FIFO等待队列的阻塞锁和相关的同步器的一个同步框架。

  ReentrantLock、Semaphore、CountDownLatch、CyclicBarrier等并发类均是基于AQS来实现的,

  具体用法是通过继承AQS实现其模板方法,然后将子类作为同步组件的内部类。

  例如CountDownLatch,源码发现其内部有一个继承了 AbstractQueuedSynchronizer 的内部类 Sync。

 

2.谁实现的

   AQS是JDK1.5之后才出现的,由大名鼎鼎的Doug Lea李大爷来操刀设计并开发实现,全部源代码(加注释)2315行,整体难度中等。

   技术分享图片

 

 

3.基本架构图解(关键点volatile语义下的共享变量state)

   技术分享图片

 

 

总结:AQS使用一个int类型的成员变量state来表示同步状态,

           当state>0时表示已经获取了锁,当state = 0时表示释放了锁。

           它提供了三个方法(getState()、setState(int newState)、compareAndSetState(int expect,int update))

           来对同步状态state进行操作,当然AQS可以确保对state的操作是安全的。

 

4.State(共享资源变量,它是int数据类型的)

   基本方法:getState(),setState(int newState),compareAndSetState(int expect, int update)

   注:上述3种方式均是原子操作,其中compareAndSetState()的实现依赖于Unsafe的compareAndSwapInt()方法。

   源码:

     private volatile int state;

    // 具有内存读可见性语义

    protected final int getState() {

          return state;

     }

    // 具有内存写可见性语义

   protected final void setState(int newState) {

         state = newState;

    }

   // 具有内存读/写可见性语义

  protected final boolean compareAndSetState(int expect, int update) {

     // See below for intrinsics setup to support this

    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);

  }

 

5.资源的共享方式

   第一种:独占式(Exclusive)

         只有单个线程能够成功获取资源并执行,如ReentrantLock。

    第二种:共享式(Shared)

         多个线程可成功获取资源并执行,如Semaphore/CountDownLatch等。

    总的来说:

         AQS将大部分的同步逻辑均已经实现好,

        继承的自定义同步器只需要实现state的获取(acquire)

        和释放(release)的逻辑代码就可以,主要包括下面方法:

         tryAcquire(int):独占方式。尝试获取资源,成功则返回true,失败则返回false。

         tryRelease(int):独占方式。尝试释放资源,成功则返回true,失败则返回false。

         tryAcquireShared(int):共享方式。尝试获取资源。

              负数表示失败;

 

              0表示成功,但没有剩余可用资源;

              正数表示成功,且有剩余资源。

          tryReleaseShared(int):共享方式。尝试释放资源,如果释放后允许唤醒后续等待结点返回true,否则返回false。

          isHeldExclusively():该线程是否正在独占资源。只有用到condition才需要去实现它。

 

    注:AQS需要子类复写的方法均没有声明为abstract,

           目的是避免子类需要强制性覆写多个方法,

           因为一般自定义同步器要么是独占方法,要么是共享方法,

           只需实现tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared中的一种即可。

          当然,AQS也支持子类同时实现独占和共享两种模式,如ReentrantReadWriteLock。

 

6.CLH队列(FIFO)

    AQS是通过内部类Node来实现FIFO队列的,源代码解析如下:

    static final class Node {

       // 表明节点在共享模式下等待的标记

      static final Node SHARED = new Node();

      // 表明节点在独占模式下等待的标记

       static final Node EXCLUSIVE = null;

       // 表征等待线程已取消的

       static final int CANCELLED = 1;

       // 表征需要唤醒后续线程

       static final int SIGNAL = -1;

       // 表征线程正在等待触发条件(condition)

       static final int CONDITION = -2;

       // 表征下一个acquireShared应无条件传播

       static final int PROPAGATE = -3;

       /**
         *   SIGNAL: 当前节点释放state或者取消后,将通知后续节点竞争state。
         *   CANCELLED: 线程因timeout和interrupt而放弃竞争state,当前节点将与state彻底拜拜
         *   CONDITION: 表征当前节点处于条件队列中,它将不能用作同步队列节点,直到其waitStatus被重置为0
         *   PROPAGATE: 表征下一个acquireShared应无条件传播
         *   0: None of the above
        */

     volatile int waitStatus;

      // 前继节点

     volatile Node prev;

     // 后继节点

     volatile Node next;

     // 持有的线程

     volatile Thread thread;

     // 链接下一个等待条件触发的节点

     Node nextWaiter;

     // 返回节点是否处于Shared状态下

     final boolean isShared() {

          return nextWaiter == SHARED;

     }

     // 返回前继节点

    final Node predecessor() throws NullPointerException {

          Node p = prev;

         if (p == null)

            throw new NullPointerException();

        else return p;

    

     // Shared模式下的Node构造函数

     Node() { }

     // 用于addWaiter

     Node(Thread thread, Node mode) {

              this.nextWaiter = mode;

              this.thread = thread;

      }

     // 用于Condition

   Node(Thread thread, int waitStatus) {

           this.waitStatus = waitStatus;

           this.thread = thread;

     }

  }

  总结:可以看到,waitStatus非负的时候,表征不可用,

            正数代表处于等待状态,所以waitStatus只需要检查其正负符号即可,

            不用太多关注特定值。 

学习来源:https://www.cnblogs.com/wushenghfut/p/11258767.html

                  https://www.jianshu.com/p/0f876ead2846

AQS(AbstractQueuedSynchronizer)--队列同步器

原文:https://www.cnblogs.com/HuiShouGuoQu/p/13596080.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!