JUC包下的并发工具类CountDownLatch,CountDownLatch为递减计数器,用于控制一个线
程等待多个线程。维护一个计数器count
,表示需要等待的事件数量,countdown方法递减计数
器,表示事件发生,调用await()
方法的线程会一直阻塞直到计数器为零,或者等待中的线程中断,
或者等待超时
CyclicBarrier,循环栅栏可以让一组线程等待至某个状态之后再全部同时执行,之所以叫循环是因
为所有等待线程被释放后可以调用reset()
方法重用。两个比较重要的方法是await()
和await(time)
,构造方法CyclicBarrier(int, Runnable)可以让所有线程到达栅栏状态是优先执行此动作。和CountDownLatch最重要的区别就是countdown()
方法后会继续执行自己的任务,而CyclicBarrier会在所有线程任务到达栅栏处才执行后续任务
例:假设有4个线程,A、B、C、D,线程 D 需要在 A、B、C 执行完之后再执行
实现:如上描述,如果想让线程 D 最后执行,结合之前的学习,我们可以采用 join() 方法来实现,比如在 A 线程调 B.join(),B 线程调用 C.join() 等等,我们来回忆一下 join() 方法:一个线程调用另一个线程的 join() 方法时,当前线程阻塞,等待被调用 join() 方法的线程执行完毕才能继续执行,这样可以保证线程执行顺序
代码实现:
/**
* @author lwy
* @create 2022-04-06 10:39
*/
public class JoinDemo {
public static void main(String[] args) {
// Thread A = new Thread(() -> System.out.println("Thread A"));
Thread A = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Thread A");
}
});
Thread B = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Thread B wait for Thread A");
try {
A.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread B");
}
});
Thread C = new Thread(() -> {
System.out.println("Thread C wait for Thread B");
try {
B.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread C");
});
Thread D = new Thread(() -> {
System.out.println("Thread D wait for Thread C");
try {
C.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread D");
});
B.start();
A.start();
C.start();
D.start();
}
}
执行结果:
Thread B wait for Thread A
Thread A
Thread D wait for Thread C
Thread C wait for Thread B
Thread B
Thread C
Thread D
显然 join() 方法是可以完成 D 线程最后执行的要求,但是却失去了多线程并行执行的意义。
因为线程 A、B、C 无法完成同步运行,本质上还是串行,join() 方法其内部的实现是基于等待通知机制
所以为了解决这个问题,可以利用 CountdownLatch
来实现这类通信方式
代码实现:
import java.util.concurrent.CountDownLatch;
/**
* @author lwy
* @create 2022-04-06 10:51
*/
public class CountdownLatch {
public static void main(String[] args) {
int N = 3;
CountDownLatch countdownLatch = new CountDownLatch(N);
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("D waiting for executing!");
try {
countdownLatch.await();
System.out.println("D start to execute");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
for (char threadName = 'A'; threadName <= 'C'; threadName++) {
final String tN = String.valueOf(threadName);
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(tN + " is executing");
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(tN + " Execute finally");
countdownLatch.countDown();
}
}).start();
}
}
}
执行结果:
D waiting for executing!
A is executing
C is executing
B is executing
C Execute finally
B Execute finally
A Execute finally
D start to execute