CountDownLatch和CyclicBarrier
CountDownLatch
功能介绍
CountDownLatch 是一个同步功能的辅助类 线程计数不为0时呈wait状态如果为0则继续执行。通过await 和 countDown 两个方法来实现等待和继续运行。
作用:一个线程或多个线程等待另一个线程或多个线程完成后再继续执行。
public class MyCountDownLatch {
private CountDownLatch countDownLatch = new CountDownLatch(1);
public void test(){
try {
System.out.println("start await");
//等待
countDownLatch.await();
System.out.println("end await");
} catch (Exception e){
e.printStackTrace();
}
}
public void downTest(){
System.out.println("start countDown");
countDownLatch.countDown();
}
@AllArgsConstructor
@NoArgsConstructor
public static class MyThread extends Thread{
private MyCountDownLatch countDownLatch = new MyCountDownLatch();
@Override
public void run(){
countDownLatch.test();
}
}
public static void main(String[] args) throws InterruptedException {
MyCountDownLatch myCountDownLatch = new MyCountDownLatch();
MyThread myThread = new MyThread(myCountDownLatch);
myThread.start();
Thread.sleep(1000);
myCountDownLatch.downTest();
}
}
await() 存在线程阻塞的风险 可以使用 await(long timeout, TimeUnit unit) 在最大时间内进入waiting状态,超过后会自动唤醒,防止阻塞
getCount() 可以获取当前计数的值
应用场景
- 裁判员等待全部运动员回来
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(5);
System.out.println("start wait");
for (int i = 0; i < 5; i++){
MyThreadA myThreadA = new MyThreadA(countDownLatch);
myThreadA.setName("runner" + i);
myThreadA.start();
}
countDownLatch.await();
System.out.println("all back");
}
@AllArgsConstructor
@NoArgsConstructor
public static class MyThreadA extends Thread{
private CountDownLatch countDownLatch;
@Override
public void run(){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " countDown");
countDownLatch.countDown();
}
}
- 准备比赛
public class MyCountDownLatch {
private CountDownLatch countDownLatch = new CountDownLatch(1);
public void awaitStart(){
try {
System.out.println(Thread.currentThread().getName() + " start await");
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + " end await");
} catch (Exception e){
e.printStackTrace();
}
}
public void downCount(){
System.out.println(Thread.currentThread().getName() + " start countDown");
countDownLatch.countDown();
}
@AllArgsConstructor
@NoArgsConstructor
public static class MyThread extends Thread{
private MyCountDownLatch countDownLatch = new MyCountDownLatch();
@Override
public void run(){
countDownLatch.awaitStart();
}
}
public static void main(String[] args) throws InterruptedException {
MyCountDownLatch countDownLatch = new MyCountDownLatch();
System.out.println("start wait");
for (int i = 0; i < 3; i++){
MyThread myThread = new MyThread(countDownLatch);
myThread.setName("runner" + i);
myThread.start();
}
Thread.sleep(2000);
countDownLatch.downCount();
System.out.println("all back");
}
}
CyclicBarrier
功能介绍
CyclicBarrier 具有CountDownLatch的所有功能还可以实现屏障(阶段性同步)等能力。
作用:多个线程之间相互等待,任何一个线程完成之前所有线程都必须等待。
与CountDownLanch相同的功能不再介绍
public class MyCyclicBarrier {
@AllArgsConstructor
@NoArgsConstructor
public static class MyThread extends Thread{
private CyclicBarrier cyclicBarrier;
@Override
public void run() {
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
MyThread myThread = new MyThread(cyclicBarrier);
myThread.start();
Thread.sleep(1000);
System.out.println(cyclicBarrier.getNumberWaiting());
MyThread myThread1 = new MyThread(cyclicBarrier);
myThread1.start();
Thread.sleep(1000);
System.out.println(cyclicBarrier.getNumberWaiting());
MyThread myThread2 = new MyThread(cyclicBarrier);
myThread2.start();
Thread.sleep(1000);
System.out.println(cyclicBarrier.getNumberWaiting());
MyThread myThread3 = new MyThread(cyclicBarrier);
myThread3.start();
Thread.sleep(1000);
System.out.println(cyclicBarrier.getNumberWaiting());
}
}
可以看出CyclicBarrier具有屏障的重制性计数值可以重制为0
isBroken() 查询屏障是否属于破损状态
getNumberWaiting() 查看有几个线程到达屏障点
getParties() 获取 parties 个数
reset() 重制屏障
应用场景
- 阶段跑步比赛
public class MyCyclicBarrier {
public CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
private void start(){
try {
int sleepValue = (int) (Math.random() * 10000);
Thread.sleep(sleepValue);
System.out.println(Thread.currentThread().getName() + " start 第一阶段");
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName() + " end 第一阶段");
int sleepValue1 = (int) (Math.random() * 10000);
Thread.sleep(sleepValue1);
System.out.println(Thread.currentThread().getName() + " start 第二阶段");
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName() + " end 第二阶段");
}catch (InterruptedException | BrokenBarrierException e){
e.printStackTrace();
}
}
@AllArgsConstructor
@NoArgsConstructor
public static class MyThread extends Thread{
private MyCyclicBarrier cyclicBarrier;
@Override
public void run() {
cyclicBarrier.start();
}
}
public static void main(String[] args) throws InterruptedException {
MyCyclicBarrier cyclicBarrier = new MyCyclicBarrier();
MyThread myThread = new MyThread(cyclicBarrier);
myThread.setName("myThread");
myThread.start();
Thread.sleep(1000);
MyThread myThread1 = new MyThread(cyclicBarrier);
myThread.setName("myThread1");
myThread1.start();
Thread.sleep(1000);
MyThread myThread2 = new MyThread(cyclicBarrier);
myThread.setName("myThread2");
myThread2.start();
Thread.sleep(1000);
MyThread myThread3 = new MyThread(cyclicBarrier);
myThread.setName("myThread3");
myThread3.start();
Thread.sleep(1000);
}
}