AQS-ReentrantLock.CyclicBarrier 源码
2021-04-13 22:59:13 13 举报
AQS-ReentrantLock.CyclicBarrier 源码
作者其他创作
大纲/内容
// 唤醒所有线程。count数重置,Generation重置private void nextGeneration() { trip.signalAll(); count = parties; generation = new Generation(); }
private final boolean parkAndCheckInterrupt() { LockSupport.park(this); return Thread.interrupted(); }
当多个线程达到栅栏时,会加入到条件队列进行等待。当最后一个线程到达栅栏时,会从头头队列开始依次唤醒节点所在的线程。并将对于的节点转移到同步队列中条件队列是单向的,同步队列是双向链表
cyclicBarrier.await()
如果条件队列的最后一个节点状态=-2,则从第一个节点开始遍历删除节点!=-2的节点
// 注意这里唤醒的是等待队列的头结点的下个等待被唤醒的节点// 这里唤醒后 就会接着指向这里public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; // 获取等待队列里面的头结点 if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; }
tail
head
public void unlock() { sync.release(1); }
// 这里有个点需要注意下,线程被唤醒可能是调用了unpark方法,也可能是执行了线程的interrupt()方法 正常 返回0private int checkInterruptWhileWaiting(Node node) { return Thread.interrupted() ? (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) : 0; }
如果获取成功,则将对应节点设置为头结点(可以理解为从同步队列删除节点)
节点2
CyclicBarrier cyclicBarrier = new CyclicBarrier(4)
执行到这里 表示最后一个线程已到达设置的栅栏,且前面的线程对应的节点已经阻塞在条件队列中。而此前因lock阻塞在同步队列中的节点对应的线程已全部唤醒并执行完成。即同步队列此时又变成了空的
// 释放锁 protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }
//释放当前线程所有持有的锁。如当前线程重复持有,则一起释放// 释放前需要保存状态,以便恢复的时候使用final int fullyRelease(Node node) { boolean failed = true; try { int savedState = getState(); if (release(savedState)) { failed = false; return savedState; } else { throw new IllegalMonitorStateException(); } } finally { if (failed) // 如果失败,将节点设置为取消状态 node.waitStatus = Node.CANCELLED; } }
private final ReentrantLock lock = new ReentrantLock(); 默认初始化为非公平锁private final Condition trip = lock.newCondition();private final int parties;private final Runnable barrierCommand;private Generation generation = new Generation();private int count;span style=\"font-size: inherit;\
// 从头节点开始循环,将条件队列里面的节点放入到等待队里中,注意这里并没有唤醒节点对应的线程private void doSignalAll(Node first) { lastWaiter = firstWaiter = null; do { Node next = first.nextWaiter; first.nextWaiter = null; transferForSignal(first); first = next; } while (first != null);}
第一个线程执行到这里的时候 条件队列的为空,则直接插入;当第二个线程执行到这里时,直接插入的第一个线程所在节点后面以此类推
protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }
调用ReentrantLock.Sync方法判持有锁的线程是否为当前线程。若不是则抛出异常。若是,则从头条件队列头节点开始,唤醒节点public final void signalAll() { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter; if (first != null) doSignalAll(first); }
lastWaiter
private void reportInterruptAfterWait(int interruptMode) throws InterruptedException { if (interruptMode == THROW_IE) throw new InterruptedException(); else if (interruptMode == REINTERRUPT) selfInterrupt(); }
public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; }
firstWaiter
最后一个节点达到栅栏后,将条件队列里面的节点全部转移到等待队里中,执行finally里面的unlock方法,唤醒线程
static void selfInterrupt() { Thread.currentThread().interrupt(); }
这里的head节点是执行lock的线程因为无法获取到锁而挂起的线程对应的节点
节点1 status=0
// 从第一个节点开始遍历删除节点!=-2的节点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; } }
// 从尾节点开始依次向前 检查节点是否在等待队列中private boolean findNodeFromTail(Node node) { Node t = tail; for (;;) { if (t == node) return true; if (t == null) return false; t = t.prev; } }
节点3
节点1
0 条评论
下一页