您的位置:首页 > 编程语言 > Java开发

Java并发包:CountDownLatch和CyclicBarrier

2016-07-07 11:41 615 查看
文章译自:http://tutorials.jenkov.com/java-util-concurrent/index.html

抽空翻译了一下这个教程的文章,后面会陆续放出,如有不妥,请批评指正。

转自请注明出处。

CountDownLatch

java.util.concurrent.CountDownLatch是一种并发结构,它允许一个或者多个线程等待一个给定的操作集合完成。

CountDownLatch初始化时需要给定一个总数。这个总数将会随着调用countDown()方法每次递减。通过调用await()方法,线程将会等到这个总数变为0。调用await()方法会阻塞线程直到那个总数递减到0为止。

下面是一个简单的例子。Decrementer在CountDownLatch上调用了countDown()3次之后,Waiter将会释放。

CountDownLatch latch = new CountDownLatch(3);

Waiter      waiter      = new Waiter(latch);
Decrementer decrementer = new Decrementer(latch);

new Thread(waiter).start();
new Thread(decrementer).start();

Thread.sleep(4000);


public class Waiter implements Runnable{

CountDownLatch latch = null;

public Waiter(CountDownLatch latch) {
this.latch = latch;
}

public void run() {
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println("Waiter Released");
}
}


public class Decrementer implements Runnable {

CountDownLatch latch = null;

public Decrementer(CountDownLatch latch) {
this.latch = latch;
}

public void run() {

try {
Thread.sleep(1000);
this.latch.countDown();

Thread.sleep(1000);
this.latch.countDown();

Thread.sleep(1000);
this.latch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}


CyclicBarrier

java.util.concurrent.CyclicBarrier类的同步机制可以通过某些算法实现同步线程的执行,换句话说,它就像一个屏障(或着说栏栅),在任何线程执行之前,所有线程必须在此处等着,直到所有线程都到达才执行。下面是图解:



所有的线程会在CyclicBarrier上调用await()方法相互等待,一旦N个线程正在CyclicBarrier上等待,所有的线程都会释放并且继续执行。

创建 CyclicBarrier

当你创建一个CyclicBarrier,你需要指定在它上面有多少个体线程同时等待,下面是如何创建一个CyclicBarrier:

CyclicBarrier barrier = new CyclicBarrier(2);


有2个线程在CyclicBarrier上等待,这两个线程就会释放。

在CyclicBarrier上等待

下面是一个线程如何在CyclicBarrier上等待:

barrier.await();


你也可以指定线程等待的时间。当等待的时间过了,即使不是所有指定的线程都在CyclicBarrier上等待,线程也会被释放。下面是如何指定超时时间:

barrier.await(10, TimeUnit.SECONDS);


等待的线程会在CyclicBarrier上等待直至:

最后的线程达到

线程被另一个线程中断(另一个线程调用interrupt()方法)

另一个等待的线程被中断

另一个等待的线程等待超时

某些外部线程调用了CyclicBarrier.reset()方法

CyclicBarrier Action

CyclicBarrire支持一种栏栅行为,一但最后的线程达到时线程将会执行。Runnable的栅栏行为通过CyclicBarrier的构造函数传递,像下面这样:

Runnable      barrierAction = ... ;
CyclicBarrier barrier       = new CyclicBarrier(2, barrierAction);


CyclicBarrier示例

下面的代码展示如何使用CyclicBarrier:

Runnable barrier1Action = new Runnable() {
public void run() {
System.out.println("BarrierAction 1 executed ");
}
};
Runnable barrier2Action = new Runnable() {
public void run() {
System.out.println("BarrierAction 2 executed ");
}
};

CyclicBarrier barrier1 = new CyclicBarrier(2, barrier1Action);
CyclicBarrier barrier2 = new CyclicBarrier(2, barrier2Action);

CyclicBarrierRunnable barrierRunnable1 =
new CyclicBarrierRunnable(barrier1, barrier2);

CyclicBarrierRunnable barrierRunnable2 =
new CyclicBarrierRunnable(barrier1, barrier2);

new Thread(barrierRunnable1).start();
new Thread(barrierRunnable2).start();


下面是CyclicBarrier类:

public class CyclicBarrierRunnable implements Runnable{

CyclicBarrier barrier1 = null;
CyclicBarrier barrier2 = null;

public CyclicBarrierRunnable(
CyclicBarrier barrier1,
CyclicBarrier barrier2) {

this.barrier1 = barrier1;
this.barrier2 = barrier2;
}

public void run() {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() +
" waiting at barrier 1");
this.barrier1.await();

Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() +
" waiting at barrier 2");
this.barrier2.await();

System.out.println(Thread.currentThread().getName() +
" done!");

} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}


下面是上面代码在控制台的输出结果,注意每次执行线程在控制台上打印的顺序也可能不一样。有时候可能是Thread-0先打印,有时候可能是Thread-1先打印。

Thread-0 waiting at barrier 1
Thread-1 waiting at barrier 1
BarrierAction 1 executed
Thread-1 waiting at barrier 2
Thread-0 waiting at barrier 2
BarrierAction 2 executed
Thread-0 done!
Thread-1 done!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: