打赏

AQS原理探究

AQS原理探究

AQS维持了一个单一的原子变量--state,通过getState、setState、compareAndSetState可以操作它的值。

  • 对于重入锁ReentrantLock的实现来说,state可以用来表示当前线程获取锁的可重入次数
  • 对于读写锁ReentrantReadWriteLock来说,state的高16位表示获取该读锁的次数,低16位表示获取该写锁的次数
  • 对于信号量Semaphore来说,state表示当前可用信号的次数
  • 对于FutuerTask来说,state表示任务状态(还没开始、运行、完成、取消)
  • 对于CountDownLatch和CyclicBarrier来说,state用来表示计算器当前的值

AQS结点

AQS是一个FIFO的双向队列。

  static final class Node {
        /** Marker to indicate a node is waiting in shared mode */
        //共享模式,标记该线程是获取共享资源时候被阻塞后挂起放入AQS队列
        static final Node SHARED = new Node();
        /** Marker to indicate a node is waiting in exclusive mode */
        //独占模式:标记该线程是获取独占资源时候被阻塞挂起放入AQS队列
        static final Node EXCLUSIVE = null;

        /** waitStatus value to indicate thread has cancelled */
        static final int CANCELLED =  1;
        /** waitStatus value to indicate successor's thread needs unparking */
        static final int SIGNAL    = -1;
        /** waitStatus value to indicate thread is waiting on condition */
        static final int CONDITION = -2;
        /**
         * waitStatus value to indicate the next acquireShared should
         * unconditionally propagate
         */
        static final int PROPAGATE = -3;
         /**
         * The field is initialized to 0 for normal sync nodes, and
         * CONDITION for condition nodes.  It is modified using CAS
         * (or when possible, unconditional volatile writes).
         */
        /**
        * 记录当前线程的状态:
        * signal: 线程需要被唤醒(unpark)
        * cancelled:线程被取消了(due to timeout or interrupt)
        * condition:线程在队列里等待
        * propagate 释放共享资源时候需要通知其他结点
        */
        volatile int waitStatus;
        
        //记录当前结点的前驱结点
        volatile Node prev;

        //记录当前结点的后继结点
        volatile Node next;
        
        //存入放入AQS队列中的线程
        volatile Thread thread;

        //存储condition队列中的后继节点。
        //若nextWaiter=SHAERD,则CLH队列是 独享锁 队列
        //如nextWaiter=EXCLUSIVE(null),则CLH为 共享锁 队列
        Node nextWaiter;

        /**
         * Returns true if node is waiting in shared mode.
         */
        //共享锁返回true
        final boolean isShared() {
            return nextWaiter == SHARED;
        }

        //获取前驱结点 
        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)  //null则抛出NullPointerException
                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; //mode表示是独享锁还是共享锁
            this.thread = thread; //结点对应的线程
        }

        Node(Thread thread, int waitStatus) { // Used by Condition
            this.waitStatus = waitStatus; //线程的等待状态
            this.thread = thread;   //结点对应的线程
        }
    }

AQS内部类ConditionObject

ConditionObejct是用来结合锁实现线程同步,其可直接访问AQS对象内部的变量,如state、AQS队列;ConditionObejct是条件变量,每个条件变量对应着一个条件队列(单向链表队列),用来存放调用条件变量的await()方法后被阻塞的线程。

  • 独占模式下获取和释放资源的方法

    void acquire(int arg)

    void acquireInterruptibly(int arg)

    boolean release(int arg)

    /**
    * 当一个线程调用acquire()方法来获取多占资源的时候,
    * 1.调用tryAcquire尝试获取资源
    * 2. 具体是设置状态变量state的值(原子操作UnSafe类实现),成功则直接返回,失败则将当前线程封装为类型为Node.Exclusive的Node结点后插入到AQS阻塞队列尾部
    * 3.调用
    *
    */
    public final void acquire(int arg) {
            if (!tryAcquire(arg) &&
                acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
                selfInterrupt();
        }
        
    public final void acquireInterruptibly(int arg)
                throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            if (!tryAcquire(arg))
                doAcquireInterruptibly(arg);
        }
    //释放锁    
    public final boolean release(int arg) {
            if (tryRelease(arg)) {
                Node h = head;
                if (h != null && h.waitStatus != 0)
                    //唤醒结点
                    unparkSuccessor(h);
                return true;
            }
            return false;
        }
    

acquire深入分析

//线程尝试获得锁,如果成功就直接返回,不成功则创建一个Node结点并添加到CLH队列中。TryAcquire尝试获得锁,addWriter则创建节点并添加到CLH到队列中。其中tryAcquire并没有实现,仅仅是抛出一个异常,需要锁自己实现
protected boolean tryAcquire(int arg) {
    throw new UnsupportedOperationException();
}

//产生一个中断。
static void selfInterrupt() {
    Thread.currentThread().interrupt();
}
//主要是根据该结点找到CLH的头节点,并尝试获得锁,判断是否需要挂起,并返回挂起标识。
final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
  • 共享状态下获取和释放资源的方法

    void acquire(int arg)

    void acquireInterruptibly(int arg)

    boolean release(int arg)

        public final void acquireShared(int arg) {
            if (tryAcquireShared(arg) < 0)
                doAcquireShared(arg);
        }
        public final void acquireSharedInterruptibly(int arg)
                throws InterruptedException {
            if (Thread.interrupted())
                throw new InterruptedException();
            if (tryAcquireShared(arg) < 0)
                doAcquireSharedInterruptibly(arg);
        }
       public final boolean releaseShared(int arg) {
            if (tryReleaseShared(arg)) {
                doReleaseShared();
                return true;
            }
            return false;
        }
    
posted @ 2018-12-17 04:27  JupiterMouse  阅读(280)  评论(0编辑  收藏  举报