1、CyclicBarrier:回环栅栏,可以让一组线程等待到某个状态,然后在全部通过并执行,可以复用。
//parties 定义线程达到该值才可以放行
public CyclicBarrier(int parties) {
this(parties, null);
}
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
//值
this.parties = parties;
this.count = parties;
//到达定义的parties值,执行的任务。
this.barrierCommand = barrierAction;
}
2、底层使用的ReentrantLock 和Condition (条件等待队列)实现的。
代码
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor threadPoolExecutor =
new ThreadPoolExecutor(10, 20, 10, TimeUnit.SECONDS, new ArrayBlockingQueue(10));
CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
ReentrantLock reentrantLock = new ReentrantLock();
for (int i = 0; i < 5; i++) {
reentrantLock.lock();
try {
threadPoolExecutor.execute(() -> {
System.out.println(Thread.currentThread().getName() + "线程等待");
try {
/*
* 获取锁->释放锁->进入条件等待队列、阻塞线程->(被singalAll线程唤醒,会把条件等待队列转为同步等待队列)获取锁(执行定义的任务)->释放锁(执行完任务释放锁)
*/
cyclicBarrier.await();
/**
* 线程数够3个时开始执行
*/
System.out.println("线程数达到3执行!");
} catch (InterruptedException|BrokenBarrierException e) {
e.printStackTrace();
}
});
} finally {
//唤醒的是同步等待队列的节点
reentrantLock.unlock();
}
}
}
源码解析
await()源码(CyclicBarrier类的源码)
// cyclicBarrier.await();
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock;
//加锁
lock.lock();
try {
final Generation g = generation;
if (g.broken)
throw new BrokenBarrierException();
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
//计数器减一
int index = --count;
//如果count为0
if (index == 0) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
/*
* 如果command 不为null 就执行传入的任务
*/
if (command != null)
command.run();
ranAction = true;
/*
* 唤醒其他线程,并且count重置为设置的值
*/
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
// loop until tripped, broken, interrupted, or timed out
for (;;) {
try {
if (!timed)
/**
*让该线程等待(Condition trip = lock.newCondition();)使用的是Condition
* 调用AQS中的阻塞,入队
* 直到被唤醒
**/
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
// We're about to finish waiting even if we had not
// been interrupted, so this interrupt is deemed to
// "belong" to subsequent execution.
Thread.currentThread().interrupt();
}
}
if (g.broken)
throw new BrokenBarrierException();
if (g != generation)
return index;
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
//最终会调用release()方法
lock.unlock();
}
}
/*
* 唤醒其他阻塞线程
*/
private void nextGeneration() {
/*
* signal completion of last generation 上一代信号完成
* 源码在下面AQS源码中
*/
trip.signalAll();
// set up next generation
count = parties;
generation = new Generation();
}
入队条件等待队列源码(AQS源码)
// trip.await();
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
//入队(入队逻辑)
Node node = addConditionWaiter();
/**
* 释放锁的逻辑 fullyRelease();
**/
int savedState = fullyRelease(node);
int interruptMode = 0;
/*
* 判断node是不是在同步等待队列中
* 返回false当前场景,非得话为true
*/
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) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
//入队,条件队列,是一个单向链表
private Node addConditionWaiter() {
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter;
}
//存放到链表中
Node node = new Node(Thread.currentThread(), Node.CONDITION);
//t==null是链表为null(代表刚创建的队列),头设置为当前值
if (t == null)
firstWaiter = node;
else
//设置上一个节点的下一个节点
t.nextWaiter = node;
//尾设置为当前值
lastWaiter = node;
return node;
}
/*
*释放锁的逻辑
*/
final int fullyRelease(Node node) {
boolean failed = true;
try {
/*
* 获取锁的状态,由于前已经加锁,所以savedState 为1,
* (独占锁)加锁把state由0改为1
* 解锁把state由1改为0
*/
int savedState = getState();
/*
* 释放锁
*/
if (release(savedState)) {
failed = false;
return savedState;
} else {
throw new IllegalMonitorStateException();
}
} finally {
if (failed)
node.waitStatus = Node.CANCELLED;
}
}
/*
* 释放锁
* unparkSuccessor(h);
* arg = 1
*/
public final boolean release(int arg) {
/*
* 调用ReentrantLock 类中的tryRelease(arg) 解锁放法。
* 返回true释放锁成功
*/
if (tryRelease(arg)) {
Node h = head;
/*
* 这个快只有在同步队列不为null才会执行
* 在当前例子中在,第三个线程解锁时执行该代码
* CyclicBarrier源码的dowait()方法中最后的finally代码块lock.unlock();
*/
if (h != null && h.waitStatus != 0)
//如果存在后继节点,唤醒后继节点
unparkSuccessor(h);
//释放锁成功
return true;
}
return false;
}
/*
* 调用的是ReentrantLock 的解锁逻辑(ReentrantLock类)
*/
protected final boolean tryRelease(int releases) {
//c=1
int c = getState() - releases;
//判断是否为同一个线程,不是就抛异常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
//独占线程设置为null
setExclusiveOwnerThread(null);
}
//state的状态设置为0
setState(c);
//返回true释放锁成功
return free;
}
/*
* 唤醒所有线程
*/
public final void signalAll() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
//获取头结点
Node first = firstWaiter;
//头结点不为null
if (first != null)
//条件队列转为同步等待队列
doSignalAll(first);
}
/*
* 删除并转移所有节点
*/
private void doSignalAll(Node first) {
//首位节点变为null
lastWaiter = firstWaiter = null;
//条件等待队列出队
do {
//第一个节点的下一个节点
Node next = first.nextWaiter;
//断开指针
first.nextWaiter = null;
//将节点从条件队列转移到同步队列方法调用
transferForSignal(first);
//设置下一个节点为第一个节点
first = next;
} while (first != null);
}
/*
* 将节点从条件队列转移到同步队列
*/
final boolean transferForSignal(Node node) {
/*
* If cannot change waitStatus, the node has been cancelled.
*/
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
/*
* Splice onto queue and try to set waitStatus of predecessor to
* indicate that thread is (probably) waiting. If cancelled or
* attempt to set waitStatus fails, wake up to resync (in which
* case the waitStatus can be transiently and harmlessly wrong).
* 同步等待队列入队
*/
Node p = enq(node);
//等待状态为0
int ws = p.waitStatus;
//如果ws大于0直接唤醒 或者 把返回的线程p设置为-1(p为node的上一个节点)
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
//唤醒线程
LockSupport.unpark(node.thread);
return true;
}
/**
* 同步等待队列(双向链表)
*/
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
//第一次入队,创建新节点
if (compareAndSetHead(new Node()))
//设置头、尾
tail = head;
} else {
//前一个指针 prev
node.prev = t;
//设置后一个指针next
if (compareAndSetTail(t, node)) {
t.next = node;
//最后一个节点的前一个node
return t;
}
}
}
}
/*
* 唤醒线程
*/
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
* 获取waitStatus = -1
*/
int ws = node.waitStatus;
if (ws < 0)
//修改waitStatus = 0
compareAndSetWaitStatus(node, ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
//找到下一个节点并唤醒线程
if (s != null)
LockSupport.unpark(s.thread);
}
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
//获取头结点,并且尝试获取锁tryAcquire ->nonfairTryAcquire()
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);
}
}
/*
* 获取锁,使用CAS方式获取锁
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
//设置为独占线程,获取锁成功
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
逻辑图