文章目录
CountDownLatch
可用于实现闭锁操作,
延迟线程的进度直到其到达终止状态。确保某些活动直到其它活动都完成后才继续运行,只开启一次。发令枪响后,所有运动员跑步
//这个节点由于超时或中断被取消了。节点不会离开(改变)这个状态。尤其,一个被取消的线程不再会被阻塞了
static final int CANCELLED = 1;
/** waitStatus value to indicate successor's thread needs unparking */
/* 这个节点的后继(或者即将被阻塞)被阻塞(通过park阻塞)了,所以当前节点需要唤醒它的后继当它被释放或者取消时。
为了避免竞争,获取方法必须首先表示他们需要一个通知信号,然后再原子性的尝试获取锁,如果失败,则阻塞。
也就是说,在获取锁的操作中,需要确保当前node的preNode的waitStatus状态值为’SIGNAL’,才可以被阻塞,当
获取锁失败时。(『shouldParkAfterFailedAcquire』方法的用意就是这)*/
static final int SIGNAL = -1;
/** waitStatus value to indicate thread is waiting on condition */
/* 这个节点当前在一个条件队列中。它将不会被用于当做一个同步队列的节点直到它被转移到同步队列中,
转移的同时状态值(waitStatus)将会被设置为0。
(这里使用这个值将不会做任何事情与该字段其他值对比,只是为了简化机制)。*/
static final int CONDITION = -2;
/**
* waitStatus value to indicate the next acquireShared should
* unconditionally propagate
*/
//一个releaseShared操作必须被广播给其他节点。(只有头节点的)该值会在doReleaseShared方法中被设置去确保持续的广播,即便其他操作的介入。
static final int PROPAGATE = -3;
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
//构造一个用给定计数初始化的 CountDownLatch。
this.sync = new Sync(count);
}
Sync(int count) {
//设置同步状态的值。
setState(count);
}
await
public void await() throws InterruptedException {
//以共享模式获取对象,如果被中断则中止。
sync.acquireSharedInterruptibly(1);
}
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
//中断检测
if (Thread.interrupted())
throw new InterruptedException();
//个数是否消耗完,消耗完则直接跳过,直接执行
//否则执行下列方法
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
//将当前线程以及共享模式等待标记,存储到尾端节点
final Node node = addWaiter(Node.SHARED);
//标记是否正常处理,如果出现中断,则取消执行
boolean failed = true;
try {
for (;;) {
//返回前端节点
final Node p = node.predecessor();
//如果是当前头节点
if (p == head) {
//判断闭锁是否是开的
int r = tryAcquireShared(arg);
//如果闭锁是开的
if (r >= 0) {
setHeadAndPropagate(node, r);
//释放GC
p.next = null; // help GC
//标记正确执行
failed = false;
return;
}
}
//检查并修改一个节点的状态,当该节点获取锁失败时。返回true如果线程需要阻塞。
if (shouldParkAfterFailedAcquire(p, node) &&
//这里执行阻塞
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
private Node addWaiter(Node mode) {
//包装当前线程以及表示该节点正在共享模式下等待
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
//将当前节点添加到尾部节点
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
//设置尾部节点,以及节点初始化
enq(node);
return node;
}
private Node enq(final Node node) {
//(自旋+CAS)
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;
}
}
}
}
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head; // Record old head for check below
//设置当前节点为头节点,以及清空当前线程和前置节点
setHead(node);
//如果闭锁是开的,且头为null,且waitStatus
//如果标识了广播(propagate>0),
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
Node s = node.next;
//如果当前节点为null或者当前节点为共享等待标记,则释放,执行
//enq初始化时,会有短暂为null现象
if (s == null || s.isShared())
doReleaseShared();
}
}
private void doReleaseShared() {
/*
* Ensure that a release propagates, even if there are other
* in-progress acquires/releases. This proceeds in the usual
* way of trying to unparkSuccessor of head if it needs
* signal. But if it does not, status is set to PROPAGATE to
* ensure that upon release, propagation continues.
* Additionally, we must loop in case a new node is added
* while we are doing this. Also, unlike other uses of
* unparkSuccessor, we need to know if CAS to reset status
* fails, if so rechecking.
*/
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
//更新默认值0,且解除park
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
//则说明node的前驱节点已经被要求去通知释放它的后继节点,所以node可以安全的被挂起(park)
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {
//则说明node的前驱节点被取消了。那么跳过这个前驱节点并重新标志一个有效的前驱节点(即,
// waitStatus <= 0 的节点可作为有效的前驱节点),然后,退出方法,返回false。
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
//其他情况下,即pred.waitStatus为’0’或’PROPAGATE’。
// 表示我们需要一个通知信号(即,当前的node需要唤醒的通知),
// 但是当前还不能挂起node。
// 调用『compareAndSetWaitStatus(pred, ws, Node.SIGNAL)』方法通过CAS的方式来修改前驱节点的waitStatus为“SIGNAL”。
// 退出方法,返回false。
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
//等待状态值指示后续线程需要断开连接
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
private final boolean parkAndCheckInterrupt() {
//为了线程调度,在许可可用之前禁用当前线程。
LockSupport.park(this);
//测试当前线程是否已经中断。
return Thread.interrupted();
}
countDown
public void countDown() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
//检测闭锁是否开启
if (tryReleaseShared(arg)) {
//释放
doReleaseShared();
return true;
}
return false;
}
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
//修改c=c-1,当=0时,直接返回
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
private void doReleaseShared() {
/*
* Ensure that a release propagates, even if there are other
* in-progress acquires/releases. This proceeds in the usual
* way of trying to unparkSuccessor of head if it needs
* signal. But if it does not, status is set to PROPAGATE to
* ensure that upon release, propagation continues.
* Additionally, we must loop in case a new node is added
* while we are doing this. Also, unlike other uses of
* unparkSuccessor, we need to know if CAS to reset status
* fails, if so rechecking.
*/
//广播释放所有阻塞的锁
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
//更新默认值0,且解除park
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
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.
*/
int ws = node.waitStatus;
//重置状态值
if (ws < 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;
//如果下一个节点为null,且状态取消了,则从尾端遍历,查找未取消的线程
//所以当看到next字段为null时并不意味着当前节点是队列的尾部了。
//无论如何,如果一个next字段显示为null,我们能够从队列尾向前扫描进行复核。
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);
}
释放后,这里的阻塞方法会解除阻塞,向下执行
为什么node.next可能为null?
cancelAcquire
private void cancelAcquire(Node node) {
// Ignore if node doesn't exist
if (node == null)
return;
node.thread = null;
// Skip cancelled predecessors
//将node的prev属性指向一个在它之前的有效的节点
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.
/* 这个predNext是pred表面上的下一个连接的节点(即,无需考虑该节点是否被取消了)。
下面的CAS操作将会失败(『compareAndSetNext(pred, predNext, null);』or『compareAndSetNext(pred, predNext, next);』)
,如果和其他的取消或通知操作发生竞争时,这时不需要进一步的操作。因为如果产生竞争,
说明pred的next已经被修改了,并且是最新的值了,而我们的操作也就没有要执行的必要了。*/
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设置为’CANCELLED’。这里可以使用无条件的写代替CAS(注意,node的waitStatus是volatile的)。
在这个原子操作之后,其他节点会跳过我们(即,跳过waitStatus被置位CANCELLED的节点),
在这个原子操作之前,我们不受其他线程的干扰。也就是说,无论其他线程对node的waitStatus是否有在操作,
在当前的情况下我们都需要将这个node的waitStatus置为’CANCELLED’。*/
node.waitStatus = Node.CANCELLED;
// If we are the tail, remove ourselves.
/* 如果待取消的node节点是队列尾节点的话(即,『node == tail』),那么删除node自己即可。使用CAS将tail节点设置成前面得到的第一个有效前驱节点
(即,『compareAndSetTail(node, pred)』)。并且CAS操作成功的话,
执行『compareAndSetNext(pred, predNext, null);』
也就是将tail的next置为null的意思。如果该CAS操作失败的话,
没关系。说明此时tail已经被修改了。*/
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节点
pred != head &&
//pred.waitStatus为SIGNAL” 或者
((ws = pred.waitStatus) == Node.SIGNAL ||
//“pred.waitStatus <= 0”时且通过CAS将pred.waitStatus设置为SIGNAL”成功
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
//pred的thread非空
pred.thread != null) {
Node next = node.next;
/* 当node的next节点非空,且next节点的waitStatus<=0(说明next节点未被取消)时,
通过CAS将pred的next执行node的next(即,pred.next = node.next)。
同时,如果该CAS操作失败是没关系的,说明有其他线程操作已经修改了该pre的next值。*/
if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);
} else {
//释放当前这个待取消节点的下一个节点。
//当prev是head节点,或者prev也被取消的话,会执行『unparkSuccessor(node);』来释放node的下一个节点,其实也就是pred的下一个节点)
unparkSuccessor(node);
}
//释放GC
node.next = node; // help GC
}
}
总结
依次按照链表顺序执行,当设置共享模式的时候,广播唤醒,
唤醒的节点中途取消了,则从尾端遍历寻找下一个可以唤醒的节点
FutureTask
提前加载稍后需要的数据
Future表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,如有必要,计算完成前可以阻塞此方法。
Callable返回结果并且可能抛出异常的任务。实现者定义了一个不带任何参数的叫做 call 的方法。
/**
* The run state of this task, initially NEW. The run state
* transitions to a terminal state only in methods set,
* setException, and cancel. During completion, state may take on
* transient values of COMPLETING (while outcome is being set) or
* INTERRUPTING (only while interrupting the runner to satisfy a
* cancel(true)). Transitions from these intermediate to final
* states use cheaper ordered/lazy writes because values are unique
* and cannot be further modified.
*
* Possible state transitions:
* NEW -> COMPLETING -> NORMAL
* NEW -> COMPLETING -> EXCEPTIONAL
* NEW -> CANCELLED
* NEW -> INTERRUPTING -> INTERRUPTED
*/
private volatile int state;
//表示是个新的任务或者还没被执行完的任务。这是初始状态。
private static final int NEW = 0;
//任务已经执行完成或者执行任务的时候发生异常,但是任务执行结果或者异常原因还没有保存到outcome字段
// (outcome字段用来保存任务执行结果,如果发生异常,则用来保存异常原因)的时候,
// 状态会从NEW变更到COMPLETING。但是这个状态会时间会比较短,属于中间状态。
private static final int COMPLETING = 1;
//任务已经执行完成并且任务执行结果已经保存到outcome字段,状态会从COMPLETING转换到NORMAL。这是一个最终态。
private static final int NORMAL = 2;
//任务执行发生异常并且异常原因已经保存到outcome字段中后,状态会从COMPLETING转换到EXCEPTIONAL。这是一个最终态。
private static final int EXCEPTIONAL = 3;
//任务还没开始执行或者已经开始执行但是还没有执行完成的时候,用户调用了cancel(false)方法取消任务且不中断任务执行线程,
// 这个时候状态会从NEW转化为CANCELLED状态。这是一个最终态。
private static final int CANCELLED = 4;
//任务还没开始执行或者已经执行但是还没有执行完成的时候,
// 用户调用了cancel(true)方法取消任务并且要中断任务执行线程但是还没有中断任务执行线程之前,
// 状态会从NEW转化为INTERRUPTING。这是一个中间状态。
private static final int INTERRUPTING = 5;
//调用interrupt()中断任务执行线程之后状态会从INTERRUPTING转换到INTERRUPTED。这是一个最终态。
private static final int INTERRUPTED = 6;
构造
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
//设置回调函数,返回value
this.callable = callable;
//初始状态
this.state = NEW; // ensure visibility of callable
}
带返回构造
public FutureTask(Runnable runnable, V result) {
//任务执行成果,返回result
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);
}
static final class RunnableAdapter<T> implements Callable<T> {
final Runnable task;
final T result;
//适配器,底层包装task
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
public T call() {
task.run();
//返回设置结果
return result;
}
}
run
因为继承了runnable接口,所以使用线程时,直接调用run
public void run() {
//当前状态不是新建,说明已经执行过或者取消了,直接返回
if (state != NEW ||
// 状态为新建,则尝试添加当前线程到runner中,如果失败直接返回
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
//回调函数有值且状态新建
if (c != null && state == NEW) {
V result;
boolean ran;
try {
//调用回调函数,保存值到result中
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
//异常处理
setException(ex);
}
//正确执行,则赋值
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
//任务中断,中断执行
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
protected void setException(Throwable t) {
//将当前状态 NEW => COMPLETING
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
//异常保存到outcome中
outcome = t;
//将当前状态COMPLETING => EXCEPTIONAL
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
finishCompletion();
}
}
protected void set(V v) {
// NEW => COMPLETING
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
// outcome保存返回结果
outcome = v;
//COMPLETING => NORMAL
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
get
public V get() throws InterruptedException, ExecutionException {
int s = state;
//还在执行,则阻塞等待
if (s <= COMPLETING)
s = awaitDone(false, 0L);
//返回结果
return report(s);
}
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
//计算阻塞时间
final long deadline = timed ? System.nanoTime() + nanos : 0L;
WaitNode q = null;
boolean queued = false;
for (;;) {
//对中断的处理
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
}
int s = state;
//已经取消或者出现异常,则清空线程,返回值
if (s > COMPLETING) {
if (q != null)
q.thread = null;
return s;
}
else if (s == COMPLETING) // cannot time out yet
//正在执行则暂停当前线程,并允许执行其他线程
Thread.yield();
else if (q == null)
//创建等待节点
q = new WaitNode();
else if (!queued)
//当前节点添加到头
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
else if (timed) {
//计算超时时间
nanos = deadline - System.nanoTime();
//对超时的处理
if (nanos <= 0L) {
//删除节点,返回状态值
removeWaiter(q);
return state;
}
//阻塞等待特定时间
LockSupport.parkNanos(this, nanos);
}
else
//阻塞等待直到被其他线程唤醒
LockSupport.park(this);
}
}
private void removeWaiter(WaitNode node) {
if (node != null) {
//清空当前线程
node.thread = null;
retry:
for (;;) { // restart on removeWaiter race
for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
s = q.next;
// pred => q => s
if (q.thread != null)
pred = q;
else if (pred != null) {
//删除中间thread为null的数据
//当q.thread=null且,pred不为null,则删除q节点
pred.next = s;
if (pred.thread == null) // check for race
continue retry;
}
else if (!
//删除waiters节点的头数据,并更新为waiters.next
//当q.thread=null且,pred为null,则替换为s节点,如果q为waiters节点,且修改失败,则跳过当前循环,继续执行下一个循环
UNSAFE.compareAndSwapObject(this, waitersOffset,
q, s))
continue retry;
}
break;
}
}
}
private V report(int s) throws ExecutionException {
//获取结果值,有可能是异常
Object x = outcome;
//执行完毕,则返回结果
if (s == NORMAL)
return (V)x;
//异常或取消,则抛出异常
if (s >= CANCELLED)
throw new CancellationException();
//抛出异常
throw new ExecutionException((Throwable)x);
}
cancel
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(
//如果任务已经结束
state == NEW &&
//且将 NEW => mayInterruptIfRunning需要中断则设置为 INTERRUPTING 否则 CANCELLED
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
//直接返回
return false;
try { // in case call to interrupt throws exception
//需要中断
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
//中断
t.interrupt();
} finally { // final state
//修改状态为INTERRUPTED
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
finishCompletion();
}
return true;
}
finishCompletion
private void finishCompletion() {
//成功,异常,中断的时候会调用
// assert state > COMPLETING;
//依次遍历waiters链表,唤醒节点中的线程,然后把callable置空。
for (WaitNode q; (q = waiters) != null;) {
//清空waiters
if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
for (;;) {
Thread t = q.thread;
if (t != null) {
//清空线程,且唤醒
q.thread = null;
//唤醒
LockSupport.unpark(t);
}
WaitNode next = q.next;
//到达边界,则跳出
if (next == null)
break;
//q更新为下一个节点
q.next = null; // unlink to help gc
q = next;
}
break;
}
}
done();
callable = null; // to reduce footprint
}
总结
每次涉及到成功,异常,中断的时候会唤醒所有等待的线程
最后执行的会先添加到等待线程头节点中.也就是最先唤醒的时最后执行的线程
内部维护7个状态,分别监控执行,取消,中断3个执行过程.
Semaphore
计数信号量:控制同时访问某个特定资源的操作数量,或者同时执行某个指定操作的数量,实现某种资源池,对容器施加边界
acquire
步骤同CountDownLatch.wait
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
final int nonfairTryAcquireShared(int acquires) {
//<0才阻塞
for (;;) {
//获取同步状态的值。
int available = getState();
int remaining = available - acquires;
//available为0或者更新成功,直接返回
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
release
public void release() {
sync.releaseShared(1);
}
protected final boolean tryReleaseShared(int releases) {
for (;;) {
//获取同步状态的值。
int current = getState();
//累加
int next = current + releases;
//内存溢出,也就是超过了Integer范围上限
if (next < current) // overflow
throw new Error("Maximum permit count exceeded");
//修改值返回
if (compareAndSetState(current, next))
return true;
}
}
总结
与闭锁和其类似,闭锁是为0,才可以访问,信号量恰恰相反,
信号量和闭锁的区别是不是一次性的,可以重复限定多少线程可以访问资源.
如果不限定释放的条件,可以不停的释放从而超过构造设置的许可个数,
建议这样使用
public boolean add(T o) throws InterruptedException {
//阻塞获得许可
sem.acquire();
boolean wasAdded = false;
try {
wasAdded = set.add(o);
return wasAdded;
} finally {
//返回许可给信号量
if (!wasAdded)
sem.release();
}
}
public boolean remove(Object o) {
boolean wasRemoved = set.remove(o);
if (wasRemoved)
sem.release();
return wasRemoved;
}
CyclicBarrier
阻塞一组线程直到某件事发生,可重复使用,另一种栅栏式。5个人约好集合后去其他地方。
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
//屏障拦截的线程数量
this.parties = parties;
//线程数量
this.count = parties;
//指定个数线程被wait后,执行的后续方法
this.barrierCommand = barrierAction;
}
await
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
```java
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;
//说明最后一个调用了
if (index == 0) { // tripped
boolean ranAction = false;
try {
//获取栅栏任务
final Runnable command = barrierCommand;
if (command != null)
//执行
command.run();
ranAction = true;
//重新构造可wait线程数
//以及换代
nextGeneration();
return 0;
} finally {
//非正常退出
if (!ranAction)
//标记栅栏损坏
breakBarrier();
}
}
// loop until tripped, broken, interrupted, or timed out
for (;;) {
try {
//没有设置超时,则一直阻塞
if (!timed)
//等待的时候,会释放锁
trip.await();
else if (nanos > 0L)
//阻塞超时时间
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
//当代未变,且没标记损坏
if (g == generation && ! g.broken) {
//栅栏损坏
breakBarrier();
throw ie;
} else {
//说明这个线程不是当代的,就不会影响当代执行,则中断线程
//如果在等待过程中,线程被中断了,就抛出异常。但如果中断的线程所对应的CyclicBarrier不是这代的,
// 比如,在最后一次线程执行signalAll后,并且更新了这个“代”对象。在这个区间,
// 这个线程被中断了,那么,JDK认为任务已经完成了,就不必在乎中断了,只需要打个标记。
// 该部分源码已在dowait(boolean, long)方法中进行了注释
Thread.currentThread().interrupt();
}
}
if (g.broken)
throw new BrokenBarrierException();
//表示正常换代了,返回当前线程所在下标,便于下次做选举等操作
//仔细发现,栅栏不是一次性的,可以重复使用多次,但是锁是同一个,所以需要用generation进行区分,是否是同一个栅栏
if (g != generation)
return index;
//超时,标记栅栏损坏,且抛出异常
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
//释放锁
lock.unlock();
}
}
private void nextGeneration() {
// signal completion of last generation
//唤醒所有线程
trip.signalAll();
// set up next generation
//count恢复parties个数
count = parties;
//换代
generation = new Generation();
}
private void breakBarrier() {
//标记栅栏损坏
generation.broken = true;
//count恢复parties个数
count = parties;
//唤醒所有线程
trip.signalAll();
}
reset
public void reset() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
breakBarrier(); // break the current generation
nextGeneration(); // start a new generation
} finally {
lock.unlock();
}
}
总结:可重复使用多次,底层采用显示锁进行加锁,
索引按照初始count递减,当索引为0时,执行栅栏任务
当执行成功,通知当代所有线程,接着换代,如果当代有线程中断了,且已经执行了换代任务了,这个时候会将中断线程标记中断
Exchanger
2方栅栏(Exchange):一个人有零食,另一个人有钱,他们两个想等价交换,对好口号在某个地方相见,一个人先到了之后,必须等另一个人带着需要的东西来了之后,才能开始交换。