Java中CountDownLatch和CyclicBarrier的区别
尽管CountDownLatch和CyclicBarrier都被用作同步帮助,允许至少一个线程等待,但它们之间有明显的区别。了解Java中CountDownLatch和CyclicBarrier之间的对比,将有助于你选择这些工具中的某一个为你提供更好的服务,显然这也是一个很好的Java调查问题。
CountDownLatch是一个线程在等待多个线程完成或调用 countDown()
。当所有线程都调用了 countDown()
,等待的线程继续执行。
示例代码:
// Importing required classes
import java.util.concurrent.CountDownLatch;
// Main class
public class CountDownLatchDemo {
// Main driver method
public static void main(String args[])
throws InterruptedException
{
// Let us create task that is going to wait for four threads before it starts
CountDownLatch latch = new CountDownLatch(4);
// Creating worker threads
Worker first = new Worker(1000, latch, "WORKER-1");
Worker second = new Worker(2000, latch, "WORKER-2");
Worker third = new Worker(3000, latch, "WORKER-3");
Worker fourth = new Worker(4000, latch, "WORKER-4");
// Starting above 4 threads
first.start();
second.start();
third.start();
fourth.start();
// The main task waits for four threads
latch.await();
// Main thread has started
System.out.println(Thread.currentThread().getName() + " has finished");
}
}
// A class to represent threads for which
// the main thread waits.
class Worker extends Thread {
private int delay;
private CountDownLatch latch;
public Worker(int delay, CountDownLatch latch,
String name)
{
super(name);
this.delay = delay;
this.latch = latch;
}
@Override public void run()
{
try {
Thread.sleep(delay);
latch.countDown();
System.out.println(
Thread.currentThread().getName() + " finished");
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果:
WORKER-1 finished
WORKER-2 finished
WORKER-3 finished
main has finished
WORKER-4 finished
循环障碍(CyclicBarrier)是指不同的线程互相挂起(互相等待),当所有的线程都完成了它们的执行,结果需要在父线程中进行合并。
示例代码:
// Java program to demonstrate Execution on Cyclic Barrier
// Importing required classes
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
// Class 1
// Class implementing Runnable interface
class Computation1 implements Runnable {
public static int product = 0;
public void run()
{
product = 2 * 3;
try {
// thread1 awaits for other threads
Tester.newBarrier.await();
}
catch (InterruptedException
| BrokenBarrierException e) {
e.printStackTrace();
}
}
}
// Class 2
// Implementing Runnable interface
class Computation2 implements Runnable {
public static int sum = 0;
public void run()
{
// check if newBarrier is broken or not
System.out.println("Is the barrier broken? - " + Tester.newBarrier.isBroken());
sum = 10 + 20;
try {
Tester.newBarrier.await(3000, TimeUnit.MILLISECONDS);
// number of parties waiting at the barrier
System.out.println("Number of parties waiting at the barrier " + "at this point = " + Tester.newBarrier.getNumberWaiting());
}
catch (InterruptedException
| BrokenBarrierException e) {
e.printStackTrace();
}
catch (TimeoutException e) {
e.printStackTrace();
}
}
}
public class Tester implements Runnable {
// create a static CyclicBarrier instance
public static CyclicBarrier newBarrier = new CyclicBarrier(3);
public static void main(String[] args)
{
// parent thread
Tester test = new Tester();
Thread t1 = new Thread(test);
// Starting the thread using start() method
t1.start();
}
// Method
public void run()
{
// Print statement
System.out.println("Number of parties required to trip the barrier = "+ newBarrier.getParties());
System.out.println("Sum of product and sum = "+ (Computation1.product + Computation2.sum));
// Creating object of class 1 objects on which the child thread has to run
Computation1 comp1 = new Computation1();
Computation2 comp2 = new Computation2();
// creation of child thread
Thread t1 = new Thread(comp1);
Thread t2 = new Thread(comp2);
// Moving child thread to runnable state
t1.start();
t2.start();
try {
// parent thread awaits
Tester.newBarrier.await();
}
catch (InterruptedException
| BrokenBarrierException e) {
// Display exceptions along with line number
// using printStackTrace() method
e.printStackTrace();
}
// barrier breaks as the number of thread waiting
// for the barrier at this point = 3
System.out.println(
"Sum of product and sum = "+ (Computation1.product + Computation2.sum));
// Resetting the newBarrier
newBarrier.reset();
System.out.println("Barrier reset successful");
}
}
运行结果:
Number of parties required to trip the barrier = 3
Sum of product and sum = 0
Is the barrier broken? - false
Number of parties waiting at the barrier at this point = 0
Sum of product and sum = 36
Barrier reset successful
CountDownLatch和CyclicBarrier的区别 –
倒计时锁存器 | 循环障碍 |
---|---|
CountDownLatch是一种构造,一个线程在寻找的同时,不同的线程在锁存器上进行计数,直到到达0。 | 循环屏障(CyclicBarrier)是一个可重复使用的结构,在这个结构中,一个线程的聚集在一起,直到所有的线程都出现。到那时,屏障就会被打破,可以交替进行移动。 |
CountDownLatch保持对任务的计数。 | 循环屏障(CyclicBarrier)保持着线程的数量。 |
在CountDownLatch中,单线程可以倒计时一次以上,这将减少countdown()方法被调用的次数。 | 在CyclicBarrier中,单线程可以只调用awits一次,这将使障碍计数减少一次,即使调用awits()方法超过一次。 |
当使用CountDownLatch时,你必须在创建CountDownLatch对象时指定对倒计时()方法的调用次数。 | 当使用CyclicBarrier时,你必须指定调用await()函数来跳过障碍的线程数量。 |
CountDownLatch被初始化为N,用于使一个线程待命,直到N个字符串完成某些活动,或者某些活动已经完成了N次。 | 如果有一个初始化为3的CyclicBarrier,这意味着你在任何情况下都应该有3个字符串来调用await()。 |
CountDownLatch不能被重复使用,当计数到达0时,它不能被重置。 | CyclicBarrier在持有线程被释放后可以被重新使用。 |
在CountDownLatch中,只有当前有问题的线程会抛出一个特殊情况/异常。 | 在CyclicBarrier中,如果一个线程遇到了问题(超时、中断),已经到达await()的广泛的各种线程都会得到一个特殊情况/异常。 |
CountDownLatch是可以提前的。 | CyclicBarrier是不可提前的。 |
如果当前线程被中断,它将抛出InterruptedException。它不会影响其他线程。 | 如果一个线程在等待时被打断,那么所有其他等待的线程将抛出BrokenBarrierException。 |