AQS源码分析

来源:互联网 发布:cstr在vb中什么意思 编辑:程序博客网 时间:2024/06/11 14:16

1.AQS介绍 
AQS是为实现依赖于先进先出 (FIFO) 等待队列 的阻塞锁和相关同步器(信号量、事件,等等)提供一个框架。它使用了一个原子的int value status来作为同步器的状态值(如:独占锁。1代表已占有,0代表未占有),通过该类提供的原子修改status方法(getState, setState and compareAndSetState),我们可以把它作为同步器的基础框架类来实现各种同步器。 
AQS还定义了一个实现了Condition接口的ConditionObject内部类。Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set (wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。 
简单来说,就是Condition提供类似于Object的wait、notify的功能signal和await,都是可以使一个正在执行的线程挂起(推迟执行),直到被其他线程唤醒。但是Condition更加强大,如支持多个条件谓词、保证线程唤醒的顺序和在挂起时不需要拥有锁。关于Condition更加详细的资料可以看这里http://blog.csdn.net/ghsau/article/details/7481142

以下是一个关于AQS官方提供的“独占锁实现” 的例子 
通过设置AQS的state值来实现独占锁。 1代表当前锁被占有,0代表未被占

class Mutex implements Lock, java.io.Serializable {   // 定义一个内部帮助类   private static class Sync extends AbstractQueuedSynchronizer {     // 判断当前独占锁是否被持有     protected boolean isHeldExclusively() {       return getState() == 1;     }     // 重写AQS独占锁获取锁方法:如果当前AQS的state状态为0,则获取锁成功     public boolean tryAcquire(int acquires) {       assert acquires == 1; // Otherwise unused       //CAS (Compare and Set)调用CPU指令原子更新AQS的state值       if (compareAndSetState(0, 1)) {         setExclusiveOwnerThread(Thread.currentThread());         //返回获取成功         return true;       }       return false;     }     // 重写AQS独占锁释放方法     protected boolean tryRelease(int releases) {       assert releases == 1; // Otherwise unused       if (getState() == 0) throw new IllegalMonitorStateException();       setExclusiveOwnerThread(null);      //可以看到这里并没有使用CAS原子更新state的值,不够严谨       setState(0);       return true;     }     // 提供条件队列功能     Condition newCondition() { return new ConditionObject(); }     // Deserialize properly     private void readObject(ObjectInputStream s)         throws IOException, ClassNotFoundException {       s.defaultReadObject();       setState(0); // reset to unlocked state     }   }   // 下面Mutex提供的功能,实际上仅仅只是委托了AQS的独占锁实现类Sync   private final Sync sync = new Sync();   public void lock()                { sync.acquire(1); }   public boolean tryLock()          { return sync.tryAcquire(1); }   public void unlock()              { sync.release(1); }   public Condition newCondition()   { return sync.newCondition(); }   public boolean isLocked()         { return sync.isHeldExclusively(); }   public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }   public void lockInterruptibly() throws InterruptedException {     sync.acquireInterruptibly(1);   }   public boolean tryLock(long timeout, TimeUnit unit)       throws InterruptedException {     return sync.tryAcquireNanos(1, unit.toNanos(timeout));   } }/* 看完了上面AQS的独占锁实现,再来看下AQS的共享锁实现。下面这个是AQS的共享锁实现类,它类似于JDK提供的闭锁CountDownLatchBooleanLatch 顾名思义,是个类似于布尔型的闭锁。即如果该锁为真时候则能获取,为假时候则等待直到另外线程修改该锁状态为真。*/ class BooleanLatch {   private static class Sync extends AbstractQueuedSynchronizer {     boolean isSignalled() { return getState() != 0; }     //重写AQS的共享锁获取方法,只要返回的值大于0则可以获取锁,否则AQS会调用unsafe的park挂起线程,后面我们会分析这块源码     protected int tryAcquireShared(int ignore) {       return isSignalled() ? 1 : -1;     }     //重写AQS的共享锁释放方法,这里仅仅只是设置AQS的state值为1,和参数ignore没有任何关系。设置完毕后,AQS会调用unsafe的unpark唤醒线程,则之前被挂起的线程会重新执行tryAcquireShared    //方法。而此时的state大于0,则可以获取锁     protected boolean tryReleaseShared(int ignore) {       setState(1);       return true;     }   }   private final Sync sync = new Sync();   public boolean isSignalled() { return sync.isSignalled(); }   public void signal()         { sync.releaseShared(1); }   public void await() throws InterruptedException {     sync.acquireSharedInterruptibly(1);   } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89

通过上面这两个例子,我们可以清楚知道AQS究竟是在JUC里扮演了什么样的角色。就是一个阻塞锁和相关同步器的实现类的底层框架!它封装了线程、挂起唤醒的内部运作,我们只需要通过设置AQS的state值来控制他的线程挂起和唤醒的运作路径,就可以实现我们的同步器类了。

2.Park 和 Unpark 
看完了上面的AQS我们能猜到了ReentranLock、CountDownLatch、Semaphore这些基于AQS框架的同步器是如何实现的了。在进入AQS源码前,我们先了解一个与之相关的类 LockSupport 
http://blog.csdn.net/wojiaolinaaa/article/details/50016515

3.AQS的链表队列结构 
AQS内部维护了一个以Node为节点实现的链表的队列。

/**      +------+  prev +-----+       +-----+ head |      | <---- |     | <---- |     |  tail      +------+       +-----+       +-----+/**static final class Node {        //SHARED作为共享模式下的常量        static final Node SHARED = new Node();        //EXCLUSIVE作为独占模式下的常量        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;        /**         *  状态字段:只具有以下值         *   SIGNAL:     当前节点的后继节点已经 (或即将)被阻塞(通过park) , 所以当 当前节点释放或则被取消时候                      *               ,一定要unpark它的后继节点。为了避免竞争,获取方法一定要首先设置node为signal,然后再次重        *              新调用获取方法,如果失败,则阻塞         *   CANCELLED:  当前节点由于超时或者被中断而被取消。一旦节点被取消后,那么它的状态值不在会被改变,且当前节点的线程不会再次被阻塞         *   CONDITION:  表示当前节点正在条件队列(AQS下的ConditionObject里也维护了个队列)中,         *               在从conditionObject队列转移到同步队列前,它不会在同步队列(AQS下的队列)中被使用。         *               当成功转移后,该节点的状态值将由CONDITION设置为0         *   PROPAGATE:  共享模式下的释放操作应该被传播到其他节点。该状态值在doReleaseShared方法中被设置的,         *                        *   0:          以上都不是         *         * 该状态值为了简便使用,所以使用了数值类型。非负数值意味着该节点不需要被唤醒。所以,大多数代码中不需要检查该状态值的确定值,         * 只需要根据正负值来判断即可对于一个正常的Node,他的waitStatus初始化值时0.           对于一个condition队列中的Node,他的初始化值时CONDITION           如果想要修改这个值,可以使用AQS提供CAS进行修改         */        volatile int waitStatus;        /**         * 指向当前节点的前驱节点,当前节点依赖前驱节点来检测waitStatus,前驱节点是在当前节点入队时候被设置的。         * 为了提高GC效率,在当前节点出队时候会把前驱节点设置为null。而且,在取消前驱节点中,则会循环直到找到一个非取消的节点,         * 由于头节点永远不会是取消状态,所以一定能找到。         */        volatile Node prev;        /**         * 指向当前节点的后继节点,在当前节点释放时候会唤醒后继节点。该后继节点也是在入队时候被分配的。         * 当前驱节点被取消时候,会重新调整链表的节点链接指向关系。如:前驱节点的前驱节点指向当前节点。         * 且把前驱节点设置为null。节点入队操作过程完成前,入队操作并还未设置前驱节点的后继节点。所以         * 会看到前驱节点的后继节点为null,但是这并不意味着前驱节点就是队列的尾节点!如果后继节点为null,         * 我们可以通过从尾节点向前扫描来做双重检测。一个被取消的节点的后继节点被设置为自身。即node.next=node。         * 这样设置会帮助isOnSyncQueue的执行效率更高(即执行时间更短。注意该方法的if (node.next != null))         */        volatile Node next;        /**         * 当前节点的线程。在构造Node时候被初始化,在节点使用完毕后设置为null         * construction and nulled out after use.         */        volatile Thread thread;        /**         * ConditionObject链表的后继节点或者代表共享模式的节点SHARED。Condition条件队列:因为Condition队列只能在独占模式下被能被访问,         * 我们只需要简单的使用链表队列来链接正在等待条件的节点。再然后它们会被转移到同步队列(AQS队列)再次重新获取。         * 由于条件队列只能在独占模式下使用,所以我们要表示共享模式的节点的话只要使用特殊值SHARED来标明即可。         */        Node nextWaiter;        /**         * 如果节点是属于共享模式节点则返回true         */        final boolean isShared() {            return nextWaiter == SHARED;        }        /**         * Returns previous node, or throws NullPointerException if null.         * Use when predecessor cannot be null.  The null check could         * be elided, but is present to help the VM.         *         * @return the predecessor of this node         */        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;        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94

公共辅助方法 
在node获取失败时,node入队后,检测和更新node的状态值。

 private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {        int ws = pred.waitStatus;        //该节点如果状态如果为SIGNAL。则返回true,然后park挂起线程        if (ws == Node.SIGNAL)            return true;       //表明该节点已经被取消,向前循环重新调整链表节点        if (ws > 0) {            /*             * Predecessor was cancelled. Skip over predecessors and             * indicate retry.             */            do {                node.prev = pred = pred.prev;            } while (pred.waitStatus > 0);            pred.next = node;        } else {            //执行到这里代表节点是0或者PROPAGATE,然后标记他们为SIGNAL,但是            //还不能park挂起线程。需要重试是否能获取,如果不能则挂起            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);        }        return false;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

挂起当前线程,且返回线程的中断状态

 private final boolean parkAndCheckInterrupt() {        LockSupport.park(this);        return Thread.interrupted();    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

取消节点

private void cancelAcquire(Node node) {        // Ignore if node doesn't exist        if (node == null)            return;        node.thread = null;        // Skip cancelled predecessors        Node pred = node.prev;      //迭代剔除已被取消的节点        while (pred.waitStatus > 0)            node.prev = pred = pred.prev;        // predNext is the apparent node to unsplice. CASes below will        // fail if not, in which case, we lost race vs another cancel        // or signal, so no further action is necessary.        Node predNext = pred.next;        // Can use unconditional write instead of CAS here.        // After this atomic step, other Nodes can skip past us.        // Before, we are free of interference from other threads.        node.waitStatus = Node.CANCELLED;        // If we are the tail, remove ourselves.        if (node == tail && compareAndSetTail(node, pred)) {            compareAndSetNext(pred, predNext, null);        } else {            // If successor needs signal, try to set pred's next-link            // so it will get one. Otherwise wake it up to propagate.            int ws;            if (pred != head &&                ((ws = pred.waitStatus) == Node.SIGNAL ||                 (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&                pred.thread != null) {                Node next = node.next;                if (next != null && next.waitStatus <= 0)                    compareAndSetNext(pred, predNext, next);            } else {                /**            1.头部head            2.当前节点的前驱节点状态为SIGNAL + 前驱节点线程不为null            3.如果前驱节点不是取消状态且修改前驱节点状态为SIGNAL成功 + 前驱节点线程不为null             以上三总情况则会释放当前取消的节点的后继节点的线程(注意仅仅只是释放线程,并不代表能成功出队列。还需要在for(;;)重试truAcquire*)。            **/                unparkSuccessor(node);            }            node.next = node; // help GC        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

3.独占模式:public final void acquire(int arg) 和public final boolean release(int arg) 
先来看下独占模式的获取方法

  /**     * 忽略中断的(即不手动抛出InterruptedException异常)独占模式下的获取方法。该方法在成功返回前至少     * 会调用一次tryAcquire()方法(该方法是子类重写的方法,如果返回true则代表能成功获取).否则当前线程会进入     * 队列排队,重复的阻塞和唤醒等待再次成功获取后返回, 该方法可以用来实现Lock.lock     *     * @param arg 这个值被传递给tryAcquire使用,主要是用来作为state值处理的参数。可以根据需要灵活使用该值     */    public final void acquire(int arg) {       //首先调用tryAcquire(arg)值尝试获取,如果成功则返回true。!true则等于false不需要进入 acquireQueued(addWaiter(Node.EXCLUSIVE), arg))      //进行排队等待再次成功获取        if (!tryAcquire(arg) &&            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))            selfInterrupt();    } /**     * 尝试在独占模式下获取.这个方法应该查下该对象的状态是否被允许在独占模式下获取,如果是才获取     * 这个方法通常由线程执行获取时调用,如果该方法返回false,且该线程还未进入队列,则该线程会进去AQS队列排队然后挂起线程,     * 直到其他线程调用release进行通知已被的线程释放。该方法可以备用来实现Lock.tryLock     *     *默认抛出UnsupportedOperationException异常     *     */    protected boolean tryAcquire(int arg) {        throw new UnsupportedOperationException();    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

根据参数mode(Node.EXCLUSIVE或者Node.SHARED)和Thread.currentThread()创建一个节点Node,然后加到AQS链表队列. 
只有在tryAcquire获取失败时候,才进入AQS链表队列等待再次成功获取。 
打个比方:我们去医院看医生,挂号在某个特定教授。如果当前该教授没有任何病人在看病(相等于tryAcquired),那么我们不需要排队就能 
进去看病。否则的话,我们要在门口排队(相当于addWaiter),等待当前在看病的病人出来,出来一个(相当于release)则正在队列 
头部的病人可以进去看病了(大概相当于acquireQueued)。

   private Node addWaiter(Node mode) {        Node node = new Node(Thread.currentThread(), mode);        // 尝试快速入队,即无竞争条件下肯定成功。如果失败,则进入enq自旋重试入队        Node pred = tail;        if (pred != null) {            node.prev = pred;            //CAS替换当前尾部。成功则返回            if (compareAndSetTail(pred, node)) {                pred.next = node;                return node;            }        }        enq(node);        return node;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

插入节点到队列中,如果队列未初始化则初始化。然后再插入

 private Node enq(final Node node) {        for (;;) {            Node t = tail;            if (t == null) { // Must initialize                if (compareAndSetHead(new Node()))                    tail = head;            } else {                node.prev = t;                if (compareAndSetTail(t, node)) {                    t.next = node;                    return t;                }            }        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

acquireQueued主要是处理正在排队等待的线程。自旋、阻塞重试获取。如果获取成功则替换当前节点为链表头,然后返回。

 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);                    //设置前驱节点的后继节点为null。使前驱节点成为不可达。方便GC回收                    p.next = null; // help GC                    failed = false;                    return interrupted;                }                //判断当前节点的线程是否应该被挂起,如果应该被挂起则挂起。等待release唤醒释放                //问题:为什么要挂起当前线程?因为如果不挂起的话,线程会一直抢占着CPU                if (shouldParkAfterFailedAcquire(p, node) &&                    parkAndCheckInterrupt())                    interrupted = true;            }        } finally {            if (failed)                //在队列中取消当前节点                cancelAcquire(node);        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

独占模式下的释放,如果方法返回true,可释放1个或者多个线程。该方法可以用来实现Lock.unlock方法

    public final boolean release(int arg) {        if (tryRelease(arg)) {            Node h = head;            if (h != null && h.waitStatus != 0)                unparkSuccessor(h);            return true;        }        return false;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

4.共享模式:public final void acquireShared(int arg)和public final boolean releaseShared(int arg) 
共享模式的典型例子就是信号量和闭锁了。

共享模式下忽略中断的获取,该方法至少会调用一次子类重写的tryAcquireShared方法,如果首次获取结果大于等于0.则完成获取 
否则进入AQS同步队列阻塞等待机会再次重新尝试获取,直到获取成功。

 public final void acquireShared(int arg) {        if (tryAcquireShared(arg) < 0)            doAcquireShared(arg); }  /**     * 共享模式下尝试获取。该方法应该确定在共享模式下,Object的状态值是否允许被获取。     * 如果该方法返回结果被认为失败(值<0),则当前线程会进入AQS的同步队列阻塞等待     * 知道其他线程调用release释放。     *      *     * 默认抛出 UnsupportedOperationException异常     *     * @param arg the acquire argument. This value is always the one         *        passed to an acquire method, or is the value saved on entry     *        to a condition wait.  The value is otherwise uninterpreted     *        and can represent anything you like.     * @return a negative value on failure; zero if acquisition in shared     *         mode succeeded but no subsequent shared-mode acquire can     *         succeed; and a positive value if acquisition in shared     *         mode succeeded and subsequent shared-mode acquires might     *         also succeed, in which case a subsequent waiting thread     *         must check availability. (Support for three different     *         return values enables this method to be used in contexts     *         where acquires only sometimes act exclusively.)  Upon     *         success, this object has been acquired.     * @throws IllegalMonitorStateException if acquiring would place this     *         synchronizer in an illegal state. This exception must be     *         thrown in a consistent fashion for synchronization to work     *         correctly.     * @throws UnsupportedOperationException if shared mode is not supported     */    protected int tryAcquireShared(int arg) {        throw new UnsupportedOperationException();    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

共享模式获取的核心公共方法

  private void doAcquireShared(int arg) {        //添加当前线程为一个共享模式的节点        final Node node = addWaiter(Node.SHARED);        boolean failed = true;        try {            boolean interrupted = false;            for (;;) {                final Node p = node.predecessor();                if (p == head) {                    int r = tryAcquireShared(arg);                   //如果当前节点的前驱节点==head 且 state值大于0则认为获取成功                    if (r >= 0) {                        setHeadAndPropagate(node, r);                        p.next = null; // help GC                        if (interrupted)                            selfInterrupt();                        failed = false;                        return;                    }                }                //判断当前节点是否应该被阻塞,是则阻塞等待其他线程release                if (shouldParkAfterFailedAcquire(p, node) &&                    parkAndCheckInterrupt())                    interrupted = true;            }        } finally {            //如果出异常,没有完成当前节点的出队,则取消当前节点            if (failed)                cancelAcquire(node);        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

设置节点node为AQS同步队列的头结点。如果后继节点为共享模式且参数propagate是否大于0或者PROPAGATE是否已被设置,则唤醒后继节点

 private void setHeadAndPropagate(Node node, int propagate) {        Node h = head; // Record old head for check below        //首先设置node为头节点        setHead(node);        /*         * Try to signal next queued node if:         *   Propagation was indicated by caller,         *     or was recorded (as h.waitStatus) by a previous operation         *     (note: this uses sign-check of waitStatus because         *      PROPAGATE status may transition to SIGNAL.)         * and         *   The next node is waiting in shared mode,         *     or we don't know, because it appears null         *         * The conservatism in both of these checks may cause         * unnecessary wake-ups, but only when there are multiple         * racing acquires/releases, so most need signals now or soon         * anyway.         */        if (propagate > 0 || h == null || h.waitStatus < 0) {            Node s = node.next;            if (s == null || s.isShared())                doReleaseShared();        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

共享模式下的释放,唤醒后继节点并且保证传播。 
注意:在独占模式下,如果需要唤醒,仅仅相当于调用头节点的unparkSuccessor动作。

 private void doReleaseShared() {        /*         * 确保释放的传播性, 即使在并发情况下,多个线程在获取、释放。         * 如果需要唤醒,则通常尝试头节点的unparkSuccessor 动作。         * 但是如果他不符合唤醒的条件,为了确保能正确release,那么则把头节点的state设置为         * 的state设置为PROPAGATE。此外,在执行该行为时,为了以防万一有新         * 节点的加入我们的行为必须在循环中,而且如果在修改状态中,如果修改失败,那么         * 也需要重新尝试修改。         */        for (;;) {            Node h = head;            if (h != null && h != tail) {                int ws = h.waitStatus;                if (ws == Node.SIGNAL) {                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))                        continue;            // loop to recheck cases                    unparkSuccessor(h);                }                /**                    为什么这里要把state状态修改为Node.PROPAGATE?可以想象一下在什么情况下节点的状态会被修改为0,。                    线程1调用doReleaseShared的方法释放头节点,此时头节点的状态被设置为0,compareAndSetWaitStatus(h, Node.SIGNAL, 0)                        然后unparkSuccessor(h);   AQS的头节点则被唤醒重试尝试出队。注意:此时的头节点状态为0!!                    线程2调用且成功进入到doReleaseShared方法,此时获取头节点状态为0(新的头节点还未被setHead),既然能进入到这里,总不能释放失败吧?                        然后则把头节点由0修改为Node.PROPAGATE,这样我们在关注下setHeadAndPropagate方法                        if (propagate > 0 || h == null || h.waitStatus < 0) {                                Node s = node.next;                                if (s == null || s.isShared())                                    doReleaseShared();                          }                        可以看到这时候h.waitStatus是小于0的。则保证了并发情况下线程2的释放成功!                **/                else if (ws == 0 &&                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))                    continue;                // loop on failed CAS            }            /**                    为什么这里要加个h == head?                    思考什么情况下这里的头部会被改变。上面也说了:Additionally, we must loop in case a new node is addedwhile we are doing this                    假设当前AQS队列没有任何等待的节点,即head==tail。这时候上面的if判断不成立,执行到这里适合再次判断h==head,如果有新节点添加                    进来,则h!=head,会重新尝试释放。我结论:应该是为了保证在多线程情况下的尽可能成功性。            **/            if (h == head)                   // loop if head changed                break;        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

5.区别 Shard(共享模式) 和非Shard(独占模式)

虽然AQS的共享模式和独占模式写的有点复杂。但是要知道无非就两种情况: 
独占模式:即state值在0和1之前来回切换,保证同一时间只能有一个线程是处于活动的,其他线程都被阻塞, 参考:ReentranLock.. 
共享模式:state值在整数区间内,如果state值<0则阻塞,否则则不阻塞。可以参考:Semphore、CountDownLautch..

6.ConditionObject 
Condition内部类是作为锁实现的一种基础服务。 
Condition内部类实现类Condition接口。 
Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set (wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。

public class ConditionObject implements Condition, java.io.Serializable {        private static final long serialVersionUID = 1173984872572414699L;       //条件队列的头节点        private transient Node firstWaiter;       //条件队列的尾节点        private transient Node lastWaiter;        /**         * Creates a new <tt>ConditionObject</tt> instance.         */        public ConditionObject() { }        // Internal methods        /**            添加一个新节点到条件队列            可以看到,在修改队列节点结构时候并没有使用CAS,这是因为通常使用condition的前提必须是在独占模式的lock下。           **/        private Node addConditionWaiter() {            Node t = lastWaiter;            //如果条件队列的尾节点已被取消,则调用unlinkCancelledWaiters重新调整队列结构            if (t != null && t.waitStatus != Node.CONDITION) {                unlinkCancelledWaiters();                t = lastWaiter;            }            Node node = new Node(Thread.currentThread(), Node.CONDITION);            if (t == null)                firstWaiter = node;            else                t.nextWaiter = node;            lastWaiter = node;            return node;        }        /**            删除condition等待队列中的节点first,且把节点first转移到condition所属的AQS等待队列中,            直到成功。         **/        private void doSignal(Node first) {            do {                if ( (firstWaiter = first.nextWaiter) == null)                    lastWaiter = null;                first.nextWaiter = null;            } while (!transferForSignal(first) &&                     (first = firstWaiter) != null);        }        /**            转移且删除所有的节点        **/        private void doSignalAll(Node first) {            lastWaiter = firstWaiter = null;            do {                Node next = first.nextWaiter;                first.nextWaiter = null;                transferForSignal(first);                first = next;            } while (first != null);        }        /**            持有锁的情况下,从condition等待队列中分离已被取消的节点。            该方法只有在条件队列中发生节点取消或者添加一个新的节点的时候发现尾节点已被取消时调用。            该方法需要避免垃圾滞留(没有signal时候),所以即使它需要完整遍历,但也只有在在由于没有signal            而导致的超时或者取消时才起作用。 It traverses all nodes rather than stopping at a            particular target to unlink all pointers to garbage nodes without requiring many re-traversals             during cancellation storms.        **/           private void unlinkCancelledWaiters() {            Node t = firstWaiter;            Node trail = null;            while (t != null) {                Node next = t.nextWaiter;                if (t.waitStatus != Node.CONDITION) {                    t.nextWaiter = null;                    if (trail == null)                        firstWaiter = next;                    else                        trail.nextWaiter = next;                    if (next == null)                        lastWaiter = trail;                }                else                    trail = t;                t = next;            }        }        // public methods        /**            在独占锁模式下,删除当前Condition中的等待队列的头节点.        **/        public final void signal() {            if (!isHeldExclusively())                throw new IllegalMonitorStateException();            Node first = firstWaiter;            if (first != null)               /**                删除当前Condition中的等待队列的头节点,且转移头节点到AQS的同步等待队列中                注意:仅仅只是删除头节点,并没有唤醒任何节点!                那么疑问来了,为什么signal不唤醒节点却能达到Object的signal一样的效果呢?(头)                单纯的从这一步解释的通,因为signal代表着唤醒线程。AQS利用signal必须得持有独占锁,                在unlock时候实际上就是唤醒await节点。而这里的signal仅仅只是移除等待队列的头部                **/                doSignal(first);        }        /**        在当前线程拥有独占锁的情况下,删除当前condition 中等待队列的所有线程            **/        public final void signalAll() {            //判断是否拥有独占锁            if (!isHeldExclusively())                throw new IllegalMonitorStateException();            Node first = firstWaiter;            if (first != null)                doSignalAll(first);        }          /**                不抛出线程中断异常的的条件等待的实现.            保存getState方法返回的状态值,且调用release释放getState方法返回的状态值。                为什么要释放所有的getState的状态值?            试下Condition的await方法功能是类似于Object的await方法,Object的await方法            在调用时候需要进行该Object的同步(Synchronized)。所以Condition的await在            被调用时候也需要拥有独占锁(Lock.lock)。            如果 线程1 await后不释放AQS的state,那么 线程2 在signal时候无法获取锁。           如果release失败,则抛出异常 IllegalMonitorStateException             接着会调用LockSupport.park(this);阻塞当前线程,直到该线程被唤醒        **/        public final void awaitUninterruptibly() {            Node node = addConditionWaiter();            int savedState = fullyRelease(node);            boolean interrupted = false;           //线程被唤醒后需要判断当前节点是否在同步队列(因为调用signal唤醒,会把头节点从等待队列转移到AQS的同步队列 )            while (!isOnSyncQueue(node)) {                LockSupport.park(this);                if (Thread.interrupted())                    interrupted = true;            }            //这里注意acquireQueued带有一个形参savedState。至于为什么要把这个savedState传入,           //想想之前释放掉的savedState就明白了            if (acquireQueued(node, savedState) || interrupted)                selfInterrupt();        }        /*         * For interruptible waits, we need to track whether to throw         * InterruptedException, if interrupted while blocked on         * condition, versus reinterrupt current thread, if         * interrupted while blocked waiting to re-acquire.         */        /** Mode meaning to reinterrupt on exit from wait */        private static final int REINTERRUPT =  1;        /** Mode meaning to throw InterruptedException on exit from wait */        private static final int THROW_IE    = -1;        /**         * Checks for interrupt, returning THROW_IE if interrupted         * before signalled, REINTERRUPT if after signalled, or         * 0 if not interrupted.         */         /**        **/        private int checkInterruptWhileWaiting(Node node) {            return Thread.interrupted() ?                (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :                0;        }        /**            根据mode来决定是否抛出InterruptedException异常或者,或者不执行任何动作。        **/        private void reportInterruptAfterWait(int interruptMode)            throws InterruptedException {            if (interruptMode == THROW_IE)                throw new InterruptedException();            else if (interruptMode == REINTERRUPT)                selfInterrupt();        }        /**         * Implements interruptible condition wait.         * <ol>         * <li> If current thread is interrupted, throw Interrupte dException.         * <li> Save lock state returned by {@link #getState}.         * <li> Invoke {@link #release} with         *      saved state as argument, throwing         *      IllegalMonitorStateException if it fails.         * <li> Block until signalled or interrupted.         * <li> Reacquire by invoking specialized version of         *      {@link #acquire} with saved state as argument.         * <li> If interrupted while blocked in step 4, throw InterruptedException.         * </ol>         */        public final void await() throws InterruptedException {            if (Thread.interrupted())                throw new InterruptedException();             // 添加一个新节点到等待队列              Node node = addConditionWaiter();            //释放当前所有state。因为其他线程需要lock,后面还会恢复            int savedState = fullyRelease(node);            int interruptMode = 0;            //判断当前节点是否已被释放(从等待队列转移到同步队列)            while (!isOnSyncQueue(node)) {                LockSupport.park(this);                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)                    break;            }             //调用acquireQueued使节点node从AQS同步队列出队            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)                interruptMode = REINTERRUPT;            //  如果存在后继节点,则检查且清理取消节点。            if (node.nextWaiter != null) // clean up if cancelled                unlinkCancelledWaiters();            if (interruptMode != 0)                reportInterruptAfterWait(interruptMode);        }       //指定一个相对时间,如果在相对时间内被唤醒且检查是否满足不再阻塞线程条件,否知阻塞直至到达过期时间,                                                 //释放当前线程        public final long awaitNanos(long nanosTimeout)                throws InterruptedException {            if (Thread.interrupted())                throw new InterruptedException();            Node node = addConditionWaiter();            int savedState = fullyRelease(node);            long lastTime = System.nanoTime();            int interruptMode = 0;            while (!isOnSyncQueue(node)) {                if (nanosTimeout <= 0L) {                    transferAfterCancelledWait(node);                    break;                }                //这里和上面普通。只挂起线程nanosTimeout纳秒                LockSupport.parkNanos(this, nanosTimeout);                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)                    break;                long now = System.nanoTime();                //注意这里运算符德优先级关系                nanosTimeout -= now - lastTime;                lastTime = now;            }            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)                interruptMode = REINTERRUPT;            if (node.nextWaiter != null)                unlinkCancelledWaiters();            if (interruptMode != 0)                reportInterruptAfterWait(interruptMode);            return nanosTimeout - (System.nanoTime() - lastTime);        }        //指定一个绝对时间,如果在绝对时间之前被唤醒,则线程检查是否满足完成阻塞,是则推出阻塞。        //否则继续阻塞直至到达绝对时间,然后才中断阻塞        public final boolean awaitUntil(Date deadline)                throws InterruptedException {            if (deadline == null)                throw new NullPointerException();            long abstime = deadline.getTime();            if (Thread.interrupted())                throw new InterruptedException();            Node node = addConditionWaiter();            int savedState = fullyRelease(node);            boolean timedout = false;            int interruptMode = 0;            while (!isOnSyncQueue(node)) {                if (System.currentTimeMillis() > abstime) {                    timedout = transferAfterCancelledWait(node);                    break;                }                LockSupport.parkUntil(this, abstime);                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)                    break;            }            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)                interruptMode = REINTERRUPT;            if (node.nextWaiter != null)                unlinkCancelledWaiters();            if (interruptMode != 0)                reportInterruptAfterWait(interruptMode);            return !timedout;        }        public final boolean await(long time, TimeUnit unit)                throws InterruptedException {            if (unit == null)                throw new NullPointerException();            long nanosTimeout = unit.toNanos(time);            if (Thread.interrupted())                throw new InterruptedException();            Node node = addConditionWaiter();            int savedState = fullyRelease(node);            long lastTime = System.nanoTime();            boolean timedout = false;            int interruptMode = 0;            while (!isOnSyncQueue(node)) {                if (nanosTimeout <= 0L) {                    timedout = transferAfterCancelledWait(node);                    break;                }                if (nanosTimeout >= spinForTimeoutThreshold)                    LockSupport.parkNanos(this, nanosTimeout);                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)                    break;                long now = System.nanoTime();                nanosTimeout -= now - lastTime;                lastTime = now;            }            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)                interruptMode = REINTERRUPT;            if (node.nextWaiter != null)                unlinkCancelledWaiters();            if (interruptMode != 0)                reportInterruptAfterWait(interruptMode);            return !timedout;        }        //  support for instrumentation       //判断sync是否和和当前的调用的this是同一个。追踪下AQS的owns(ConditionObject condition)就明白了        final boolean isOwnedBy(AbstractQueuedSynchronizer sync) {            return sync == AbstractQueuedSynchronizer.this;        }        //查询当前等待队列是否存在 有效等待(waitStatus 值为CONDITION)的线程        protected final boolean hasWaiters() {            if (!isHeldExclusively())                throw new IllegalMonitorStateException();            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {                if (w.waitStatus == Node.CONDITION)                    return true;            }            return false;        }        //获取当前等待队列里节点数的估计值        protected final int getWaitQueueLength() {            if (!isHeldExclusively())                throw new IllegalMonitorStateException();            int n = 0;            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {                if (w.waitStatus == Node.CONDITION)                    ++n;            }            return n;        }        //获取当前等待队列里节点里的处于有效等待唤醒状态的线程的集合        protected final Collection<Thread> getWaitingThreads() {            if (!isHeldExclusively())                throw new IllegalMonitorStateException();            ArrayList<Thread> list = new ArrayList<Thread>();            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {                if (w.waitStatus == Node.CONDITION) {                    Thread t = w.thread;                    if (t != null)                        list.add(t);                }            }            return list;        }    }
原创粉丝点击