java.util.concurrent.locks.AbstractQueuedSynchronizer

简介

提供给阻塞锁和基于FIFO等待序列的相关同步器实现的一个框架。此类设计给那些依靠一个int来表示状态的同步器。子类必须定义方法去改变状态, 比如,acquired和released。然,由于要确保同步,子类需使用 getState, setState and compareAndSetState方法获取或更新状态。

子类最好被定义为非公共(non-public)内部(internal)工具类,供其封闭类(enclosing类,不懂译得对否,即相对来说前者是嵌套类,Nested class)。

此锁类支持排他模式和共享模式。在排他模式中,其他线程将不能成功获取到此锁。通常,子类实现仅支持其中一种模式,但例如,ReadWriteLock 是可以同时使用两种模式。

该类还定义了一个嵌套的 AbstractQueuedSynchronizer.ConditionObject类,它能给那些是排他实现的子类提供支持。

序列化该类仅存了原子int状态值,所以反序列化后的类会是空线程队列。

要使用该类作为同步器的基本机构,需重新定义如下方法去检测和修改同步int状态:

  • tryAcquire
  • tryRelease
  • tryAcquireShared
  • tryReleaseShared
  • isHeldExclusively

这些方法的内部实现必须是线程安全的,且应是短的非阻塞的。实现这些方法是使用该类的唯一的真正方式。

AQS的继承结构: AQS类继承结构

可看到,比如ThreadPoolExecutor,ReentrantLock,CountDownLaunch,Semaphore等Concurrent包下的核心类都在内部实现了此类, 还有一些比如CyclicBarrier是使用了ReentrantLock。由此可见,AQS的价值。

源码阅读

作者是Doug Lea老爷子 :-)

Node

AQS的核心结构是静态内部final类Node。归纳介绍几点:

  1. 此Node类是等待队列的节点类。而该等待队列的实现是"CLH"锁队列的变种。CLH锁一般用于自旋锁。但我们是用该结构去维护一些 关于持有线程的队列节点关系的控制信息,而不是用它作为阻塞同步器。
  2. 位于队列首部的可能会尝试acquire,但不能保证能成功acquire。
  3. 入队列就是通过拼接一个新的尾节点,出队列,则是需设置HEAD属性。

Node类与AQS的关系: Node

Node类源码及字段解析:

static final class Node {
        static final Node SHARED = new Node(); //标记一个在分享模式等待中节点
        static final Node EXCLUSIVE = null; //标记一个在排他模式中的节点
        static final int CANCELLED =  1; //waitStatus的一个值,指明线程已被取消
        static final int SIGNAL    = -1; //waitStatus的一个值,指明继任者线程需要取消阻塞
        static final int CONDITION = -2; //waitStatus的一个值,指明现在正处于condition等待中
        static final int PROPAGATE = -3; //waitStatus的一个值,指明下一个acquireShared是无条件传播的
        volatile int waitStatus; 
        volatile Node prev; 
        volatile Node next; //
        volatile Thread thread;
        Node nextWaiter;

        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(Thread thread, Node mode) {     // Used by addWaiter
            this.nextWaiter = mode;
            this.thread = thread;
        }

        Node(Thread thread, int waitStatus) { // Used by Condition
            this.waitStatus = waitStatus;
            this.thread = thread;
        }
    }

references

[1] Washington University | Spin Locks and Contention

results matching ""

    No results matching ""