[TOC]
Javaの並行処理されたCountDownLatchツールと原則解決CyclicBarrierを
I.はじめに
たCountDownLatchは、他のスレッドが終了するのを待っている1つまたは複数のスレッドを可能にします。
CyclicBarrierを文字通り再利用することができることを意味します(サイ)の障壁(バリア)。これは、スレッドがブロックされたすべての障壁を実行し続けます、最後のスレッドがバリアに到達するまで、それは、バリアがドアを開くときにブロックされたスレッドのグループは(も同期ポイントと呼ばれる)バリアに到達させることです行われる必要があります。
第二に、コード・ショー
CountDownLatchDemo
public class CountDownLatchDemo {
public static final CountDownLatch count = new CountDownLatch(10);
private static int j = 0;
public static void main(String[] args) throws Exception {
for (int i = 0; i < 10; i++) {
new Thread(
()-> {
System.out.println("我是"+(++j));
count.countDown();
}
).start();
}
count.await();
System.out.println("我是总数"+j+"!!!");
}
}
运行结果:
我是1
我是2
我是3
我是4
我是5
我是6
我是7
我是8
我是9
我是10
我是总数10!!!
CyclicBarrierDemo
public class CyclicBarrierDemo {
private static final CyclicBarrier c = new CyclicBarrier(6,new Thread(() ->
System.out.println("我是最后一个")
));
private static AtomicInteger index = new AtomicInteger(1);
public static void main(String[] args) throws Exception, BrokenBarrierException {
for (int i = 1; i <= 6; i ++) {
new Thread(() -> {
try {
c.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("我是:"+(index.getAndIncrement()));
}) .start();
}
}
}
运行结果:
我是最后一个
我是:1
我是:2
我是:3
我是:4
我是:5
我是:6
第三に、解決の源
出典たCountDownLatch
原理:
あなたはn個のノードの完了を待つしたい場合も閉鎖症と呼ばれたCountDownLatch、たCountDownLatchコンストラクタは、着信N、カウンタとしてint型のパラメータを受け入れ、私たちはたCountDownLatchのカウントダウンメソッドを呼び出すと、Nは、1マイナスたCountDownLatchになりますN点前記場合、Nは、スレッドがNステップであってもよい、スレッドであってもよいカウントダウン方式がどこでも使用することができるので、; Nが0になるまでこのメソッドはブロックされ待ちます。
出典:
// 构造方法
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
// 内部类 Sync 继承AQS
private static final class Sync extends AbstractQueuedSynchronizer {
}
カウントダウン方法
public void countDown() {
// 调用了AQS的releaseShared方法
sync.releaseShared(1);
}
// 这是Sync的tryReleaseShared
// AQS的releaseShared会调用子类的tryReleaseShared 用来控制count
// tryReleaseShared 共享式的释放状态 具体参考AQS
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
// 获取的其实就是我们构造函数的count
int c = getState();
// count == 0 证明整个记录流程已经完毕了
if (c == 0)
return false;
// 减1
int nextc = c-1;
if (compareAndSetState(c, nextc)) cas 更新
return nextc == 0; // 等于0,返回ture 证明计数结束了,可以去唤醒同步队列的线程了
// 唤醒是AQS的releaseShared方法
// 结合CountDownLatch的await方法理解整这里
}
}
メソッドを待ちます
public void await() throws InterruptedException {
// 共享式获取同步转态
sync.acquireSharedInterruptibly(1);
}
// 这是Sync的方法
// await 其实是调用的AQS的acquireSharedInterruptibly 但是aqs会调用子类tryAcquireShared
// 我们看到值有state等于0 才会返回true 成功 -1 表示失败 失败就要加入同步队列
// 所以在countDown方法里面等于0 为什么要去唤醒 ,应为这里会进入同步队列
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
カウントダウンカウントダウンが呼び出し元のスレッドがAQS同期キューに入り待つれるため、実行するために、他のスレッドを終了し、その後、ブロックされている場合にのみ、ソースによって、我々はこの方法を見つけることができます。
ソースCyclicBarrierを
原理:
CyclicBarrierを海はCyclicBarrierを、高レベルのコンストラクタを提供し、CyclicBarrierをデフォルトコンストラクタはCyclicBarrierを(当事者INT)であり、パラメータを遮断する障壁がスレッドの数を示しており、各スレッドの呼び出しは、Iがバリアに到達しており、その後、現在のスレッドがブロックされCyclicBarrierをを伝える待ちますスレッドは、より複雑なビジネスロジックを扱いやすいスレッドの優先順位barrierActionを、バリアに到達したとき(政党、RunnableをbarrierAction INT)、使用されています。
出典:
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;
this.barrierCommand = barrierAction;
}
private final ReentrantLock lock = new ReentrantLock();
/** Condition to wait on until tripped */
private final Condition trip = lock.newCondition();
/** The number of parties */
private final int parties;
/* The command to run when tripped */
private final Runnable barrierCommand;
/** The current generation */
private Generation generation = new Generation();
メソッドを待ちます
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
// 获取锁
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 这一代的状态
final Generation g = generation;
// 默认为false Barrier被Broken 就会为true
if (g.broken)
throw new BrokenBarrierException();
// 线程被中断了,标记为breakBarrier,唤醒所有线程
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
// 计数器减减
int index = --count;
// 到达 trip
if (index == 0) { // tripped
boolean ranAction = false;
try {
// 执行构造函数里面的线程
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
// 唤醒所有等待线程 然后重置
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
// loop until tripped, broken, interrupted, or timed out
// 一直自旋直到发生:tripped, broken, interrupted, timed out
for (;;) {
try {
// 带时间
if (!timed)
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
// 自旋过程中发生中断
} catch (InterruptedException ie) {
// 等于说明当前被重点的这个线程没有被broken
// 抛异常
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else { // 不等于说明后来的线程已经broken了
// We're about to finish waiting even if we had not
// been interrupted, so this interrupt is deemed to
// "belong" to subsequent execution.
// 中断线程 breakBarrier已经没有意义了
Thread.currentThread().interrupt();
}
}
if (g.broken) // 屏蔽Broken
throw new BrokenBarrierException();
// 别的线程更新了generation 不属于当前代
if (g != generation)
return index;
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}
private void breakBarrier() {
generation.broken = true;
count = parties;
trip.signalAll();
}
private void nextGeneration() {
// signal completion of last generation
trip.signalAll();
// set up next generation
count = parties;
generation = new Generation();
}
私たちは、それがバリアポイントに到達するまで、すべてのスレッドがブロックされ、その後、一緒にすべてを実行するために目を覚ます一緒にCyclicBarrierを見つけました。
IVの概要
たCountDownLatchは、誰もが実行を完了するまでブロックを実行しないで、1つ以上のスレッドがポイントに到達した後に実行するまでたCountDownLatchとCyclicBarrierを、スレッドが待機を実現することができるが、この状態は、一つ以上のスレッドがない同じで有しますスレッドでの呼び出しは、実行の方法を待って、我々はすべてブロックされたスレッドをきっかけに、コンストラクタ内で優先度のスレッドを実行し、ブロックが完了するまで、CyclicBarrierを一に閉塞され、たCountDownLatchカウンタは一度だけ実行することができ、CyclicBarrierを、実行することができます何度も、そうCyclicBarrierを、複雑なビジネスシナリオを実行することができます。
参考「アートのJava並行プログラミング。」