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; } public boolean tryAcquire(int acquires) { assert acquires == 1; if (compareAndSetState(0, 1)) { setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } protected boolean tryRelease(int releases) { assert releases == 1; if (getState() == 0) throw new IllegalMonitorStateException(); setExclusiveOwnerThread(null); setState(0); return true; } Condition newCondition() { return new ConditionObject(); } private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); setState(0); } } 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)); } } class BooleanLatch { private static class Sync extends AbstractQueuedSynchronizer { boolean isSignalled() { return getState() != 0; } protected int tryAcquireShared(int ignore) { return isSignalled() ? 1 : -1; } 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() { } Node(Thread thread, Node mode) { this.nextWaiter = mode; this.thread = thread; } Node(Thread thread, int waitStatus) { 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; if (ws == Node.SIGNAL) return true; if (ws > 0) { do { node.prev = pred = pred.prev; } while (pred.waitStatus > 0); pred.next = node; } else { 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(); }
取消节点
private void cancelAcquire(Node node) { if (node == null) return; node.thread = null; Node pred = node.prev; while (pred.waitStatus > 0) node.prev = pred = pred.prev; Node predNext = pred.next; node.waitStatus = Node.CANCELLED; if (node == tail && compareAndSetTail(node, pred)) { compareAndSetNext(pred, predNext, null); } else { 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; } }
- 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) { 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); Node pred = tail; if (pred != null) { node.prev = pred; 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) { if (compareAndSetHead(new Node())) tail = head; } else { node.prev = t; if (compareAndSetTail(t, node)) { t.next = node; return t; } } } }
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); p.next = null; failed = false; return interrupted; } 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; }
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); if (r >= 0) { setHeadAndPropagate(node, r); p.next = null; if (interrupted) selfInterrupt(); failed = false; return; } } 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; 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() { for (;;) { Node h = head; if (h != null && h != tail) { int ws = h.waitStatus; if (ws == Node.SIGNAL) { if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) continue; 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; } /** 为什么这里要加个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) 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() { } /** 添加一个新节点到条件队列 可以看到,在修改队列节点结构时候并没有使用CAS,这是因为通常使用condition的前提必须是在独占模式的lock下。 **/ private Node addConditionWaiter() { Node t = lastWaiter; 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; } } /** 在独占锁模式下,删除当前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; while (!isOnSyncQueue(node)) { LockSupport.park(this); if (Thread.interrupted()) interrupted = true; } if (acquireQueued(node, savedState) || interrupted) selfInterrupt(); } /** 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(); int savedState = fullyRelease(node); int interruptMode = 0; while (!isOnSyncQueue(node)) { LockSupport.park(this); 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); } 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; } 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; } final boolean isOwnedBy(AbstractQueuedSynchronizer sync) { return sync == AbstractQueuedSynchronizer.this; } 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; } }