CountDownLatch
该类主要实现了:让一个线程等待其他线程完成后再执行的功能,好比1
2
3
4
5
6
该类的初始化需要一个整数值count,当每次调用```CountDownLatch.countDown()```时Count会递减。直到count降到0时,所有执行```CountDownLatch.await()```的方法都会返回。
初始化了一个共享变量latch,并赋予count为3
```java
CountDownLatch latch = new CountDownLatch(3);
创建一个任务,睡眠1秒假装执行任务,最后执行countDown1
2
3
4
5
6
public void run() throw InterruptedException{
System.out.println("执行任务...");
Thread.sleep(1000);
latch.countDown();
}
主线程里执行如下方法1
2
3
4// 调用3个线程执行上述的任务
...
latch.await();
System.out.println("执行结束")
当三个任务线程全部执行完latch.countDown()时,main线程就会从阻塞的await()中返回,最后输出”执行结束”。
注意:CountDownLatch 只能使用一次,下一次使用要重新创建一个。
CylicBarrier
该类和CountDownLatch有点类似,不过从名字就可以看出它是一个可循环使用 的类。它的功能主要是等待所有线程达到某个位置,然后统一执行。可以想象成出发旅游,大家都先到集合地等待,待所有人都到了,就可以出发了。
创建一个屏障1
CyclicBarrier barrier = new CyclicBarrier(4);
任务类,让先完成的任务进行等待,等待其他线程到达1
2
3
4
5
6
public void run() throw InterruptedException{
System.out.println(Thread.currentThread.getName() + " -> 到达集合点");
barrier.await();
System.out.println(Thread.currentThread.getName() + "出发!")
}
睡5秒,不让主线程过早结束1
2
3
4// 创建4个线程执行上述的任务
...
Thread.sleep(5000);
System.out.println("执行结束")
注意,如果barrier在等待过程中某个线程被中断了一次,那么整个barrier就需要重新来过。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16Thread thread = new Thread(() -> {
try {
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
});
thread.start();
thread.interrupt();
try{
barrier.await();
}catch (Exception e){
System.out.println("无法等待...");
}
当另起的线程被中断后,后续的barrier就无法使用了,会抛出1
2
3
## Semaphore
该类被称作信号量,用于控制同一时间的线程执行数。想象下面一副场景:
🚌 🚌 🚌 🚌↘—————
🚌 🚌 🚌 🚌🚌 🚌🚌
🚌 🚌 🚌↗—————
1 |
|
最后输出:
1 | Thread-1-------> Thread-0-----A的数据 |
总结
重新熟悉一下同步工具,学习到了CyclicBarrier被中断一次后,整个作废的点;学习到了Exchanger的适用场景