• 多线程 -- AQS


    简述:AQS(AbstractQueuedSynchronizer)抽象的队列同步器,其是 JUC 包众多锁机制和信号量机制的基础,例如 ReentrantLock、Semaphore、CountDownLatch、ReadWriteLock、CyclicBarrier 底层的同步互斥操作都建立在 AQS 之上。AQS 的本质是一个采用双向链表实现的 FIFO 线程等待队列,等待队列上的线程释放和等待都依据一个整型的信号量 volatile int state ,可以将这个信号量视为各个线程所竞争的 "资源"。如下图所示

     

    AQS定义了一系列操作这个等待队列的方法规范,需要定制化采用 AQS 来实现同步器亦或是自定义规则的锁,可以先继承 AQS 这个类,然后重写它对于 state 变量的一系列操作(模板方法模式)。这些你可以在 ReentrantLock 的源码里面一探究竟。

     

    资源共享方式:AQS 提供了两种资源共享的方式,即独占(Exclusive)和共享(Share),独占的例子有 ReentrantLock,共享的例子有 CountDownLatch、ReadWriteLock。

     

    学习简述:

    1、首先线程进入队列等待需要 AQS 配套实现如何将线程挂起和唤醒,底层用到的是 LockSupport 工具类,里面提供了 pack() 和 unpack() 两个 native 方法来进行线程的挂起和唤醒

    2、等待队列的 Node 都包含了什么信息?其主要的当然包含了线程信息、线程状态信息、节点前驱后继等,强烈建议看源码(英文注释十分之好)

    static final class Node {
            static final Node SHARED = new Node();//表示是共享模式,源码里面的nextWaiter字段有注释说明了这个 special value
            static final Node EXCLUSIVE = null;//表示是独占模式
            static final int CANCELLED =  1;
            static final int SIGNAL    = -1;
            static final int CONDITION = -2;
            static final int PROPAGATE = -3;
            volatile int waitStatus;
            volatile Node prev; //前驱节点
            volatile Node next; //后继节点
            volatile Thread thread;//当前线程
            Node nextWaiter; //存储在condition队列中的后继节点
            //是否为共享锁
            final boolean isShared() { 
                return nextWaiter == SHARED;
            }
    
            final Node predecessor() throws NullPointerException {
                Node p = prev;
                if (p == null)
                    throw new NullPointerException();
                else
                    return p;
            }
    
            Node() {    // Used to establish initial head or SHARED marker
            }
            //将线程构造成一个Node,添加到等待队列
            Node(Thread thread, Node mode) {     // Used by addWaiter
                this.nextWaiter = mode;
                this.thread = thread;
            }
            //这个方法会在Condition队列使用,后续单独写一篇文章分析condition
            Node(Thread thread, int waitStatus) { // Used by Condition
                this.waitStatus = waitStatus;
                this.thread = thread;
            }
        }
    AQS 中的 Node

    3、除了同步队列,在独占模式下,还可以使用 Condition 来让线程进入条件队列等待。说白了,就是你可以视 AQS 里面有两个队列,一个是同步队列,里面的线程等待调度获取资源,而条件队列是针对某一条件来让线程进行等待唤醒。当位于条件队列的线程被唤醒之后会被转化到同步队列中去,源码里面有个方法 transferForSignal 就是干这个事情的!而 AQS 中的 Node 为两用,同时可作为同步队列的节点也可以作为条件队列的节点,可以看源码说明。

    4、AQS 是个模板方法模式的经典体现,定义了一些类规则方法或者说接口,让这些具体的方法延续到子类(即各种锁或者信号量)去实现,那么具体是怎么进行实现和操作的可以看别人的博客,但是更重要的是,博客的说明一定要自己进去源码一探究竟,这样就有更深的体会

     

    下面参考链接:

    AQS 源码中各种方法详解

    AQS 源码中各种方法详解2

    并发数据结构的基石

     AQS 简单应用--自定义 mutex 互斥锁

    ReentrantLock与AQS

    Lock与AQS

  • 相关阅读:
    InfoPath开发误区
    error: 80040111
    EasyUi通过POI 实现导出xls表格功能
    webservice入门
    CXF框架入门(重点)
    Spring整合Shiro
    EasyUi通过OCUpload上传及POI上传 实现导入xls表格功能
    Matlab自定义安装
    一位大学教师对学生的建议:如何做好研究
    What is covariate(协变量)
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/12688249.html
Copyright © 2020-2023  润新知