CountDownLatch和CyclicBarrier都可以用来让一个线程等待其他线程执行完再继续执行
一、CountDownLatch
public class Test8 {
static Logger LOG = LoggerFactory.getLogger(Test8.class);
public static void main(String[] args) throws InterruptedException {
LOG.info("start");
CountDownLatch count = new CountDownLatch(2);//计数器初始值为2
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count.countDown();
LOG.info("t1 run");
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//计数器的值减1
count.countDown();
LOG.info("t2 run");
}
});
t1.start();
t2.start();
//等待计数器的值边为0后主线程继续执行
count.await();
LOG.info("end");
}
}
CountDownLatch用来让一个线程等待其余线程执行完后再继续执行,使用者调用await方法后就会开始等待
CountDownLatch的初始值创建时指定后就不能被修改,所以这个倒计时器是一次性的,减到0作用就完成了,不能被再次使用。
二、CyclicBarrier
它的作用:
让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。
public class Test8 {
static Logger LOG = LoggerFactory.getLogger(Test8.class);
public static void main(String[] args) throws InterruptedException {
LOG.info("start");
CyclicBarrier cycleCount = new CyclicBarrier(2);
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
LOG.info("t1 run start");
try {
Thread.sleep(2000);
cycleCount.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
LOG.info("t1 run end");
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
LOG.info("t2 run start");
try {
Thread.sleep(1000);
cycleCount.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
LOG.info("t2 run end");
}
});
t1.start();
t2.start();
}
}
上边的代码,cycleCount让线程t1或t2先执行await后都会让计数器的值减1然后开始等待,直到最后一个线程执行await让计数器的值变为0,就会唤醒阻塞的所有线程继续执行后续逻辑。
CyclicBarrier还有一个接收Runnable对象的构造方法,传递的Runnable对象会在计数器减为0其他调用await方法的线程都运行结束后被执行,常用来汇总其他线程的执行结果。
public class Test8 {
static Logger LOG = LoggerFactory.getLogger(Test8.class);
static AtomicInteger count = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
LOG.info("start");
CyclicBarrier cycleCount = new CyclicBarrier(2, new Runnable() {
@Override
public void run() {
LOG.info("其他线程都执行完了,count:{}",count.get());
}
});
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
LOG.info("t1 run start");
try {
Thread.sleep(2000);
count.getAndIncrement();
cycleCount.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
LOG.info("t1 run end");
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
LOG.info("t2 run start");
try {
Thread.sleep(1000);
count.getAndIncrement();
cycleCount.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
LOG.info("t2 run end");
}
});
t1.start();
t2.start();
}
}
同时CyclicBarrier是一个可重用的计时器,当内部的计数器减为0后再次调用其await方法,计数器又会从初始值开始倒数让调用线程等待。
public static void main(String[] args) throws InterruptedException {
LOG.info("start");
CyclicBarrier cycleCount = new CyclicBarrier(2);
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
LOG.info("t1 run start");
try {
Thread.sleep(2000);
cycleCount.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
LOG.info("t1 run end");
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
LOG.info("t2 run start");
try {
Thread.sleep(1000);
cycleCount.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
LOG.info("t2 run end");
}
});
t1.start();
t2.start();
t1.join();
t2.join();
// 当t1 t2运行结束后t3再调用await方法又会让t3进行等待;只到其他线程让cycleCount内部计数器
// 变为0就会唤醒所有等待的线程。
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
LOG.info("t3 run start");
try {
Thread.sleep(1000);
cycleCount.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
LOG.info("t3 run end");
}
},"t3");
Thread t4 = new Thread(new Runnable() {
@Override
public void run() {
LOG.info("t4 run start");
try {
Thread.sleep(1000);
cycleCount.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
LOG.info("t4 run end");
}
},"t3");
t3.start();
t4.start();
}