1、java.util.concurrent.CountDownLatch;
CountDownLatch 又叫闭锁,可以让一个线程等待其他一组线程都执行结束之后再继续执行,如果在主方法中使用,就会将主线程阻塞,等待指定个数的线程都执行结束之后,主线程在恢复执行。
举个例子:就相当于在比赛的时候,一个裁判,要等待所有运动员都到了终点之后,裁判才会结束比赛
CountDownLatch中有几个常用的方法,如下:
- public CountDownLatch( int count ) : 其中count表示要等待的线程个数
- public void await( ) : 在需要阻塞的线程中调用这个方法,表示将当前线程阻塞
- public void countDown( ) :执行一次这个方法将要等待的线程个数减一,当计数器减为0表示所有线程执行完了
CountDownLatch的使用:
/**
* 运动员线程和裁判线程
* 裁判要等最后一个运动员到达终点之后再结束比赛
*/
class CountDownLatchTest implements Runnable{
private CountDownLatch downLatch ;
public CountDownLatchTest(CountDownLatch downLatch) {
this.downLatch = downLatch;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"到达终点");
downLatch.countDown();
}
}
/**
* 主线程相当于裁判线程,等待运动员线程都执行完了之后再宣布比赛结束
*/
public class Test {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(5); // 5表示要等待的线程数
CountDownLatchTest test = new CountDownLatchTest(countDownLatch);
List<Thread> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(test, "运行员"+i);
list.add(thread) ;
}
System.out.println("-----比赛开始-----");
for (Thread t : list){
t.start();
}
countDownLatch.await();
System.out.println("-----比赛结束-----");
}
}
运行结果:
如果我们将countDownLatch.await( )方法注释掉,运行结果应该是(这个运行结果不固定,也有可能是结束比赛再运动员线程中间打印):主线程和其他线程各运行各的
从上面两个图应该很容易看出来区别。
注意:CountDownLatch的值减为0时,不可恢复,所以有叫闭锁
2、java.util.concurrent.CyclicBarrier 循环栅栏
CyclicBarrier 有叫循环栅栏,它的作用是等待一组线程都执行到某个状态后再继续执行;看起来好像和CountDownLatch差不多,下面来看一个例子具体说明CyclicBarrier的作用:
模拟一个开会的场景:
现在有几个人要开会,需要等待所有人都到齐了之后再开会,假如现在第一个人到了,第一个人调用await方法,然后将第一个人阻塞着,等待其他的人,后面再有来的人都调用await方法阻塞着等后面的人,直到所有人都到了,再一起开始开会 ;
CyclicBarrier中的核心方法:
- public int await( ) throws InterruptedException, BrokenBarrierException
- 阻塞当前线程,让当前线程等待其他线程
- public CyclicBarrier(int parties)
- 构造方法 其中parties表示等待的线程个数
- public CyclicBarrier(int parties, Runnable barrierAction)
- parties 表示等待的线程个数
- barrierAction 传入一个Runnable对象,表示当所有线程到达栅栏的位置之后再所有线程中随便挑选一个线程去执行这个Runnable对象中的任务,执行完这个任务之后再让所有线程同时开始往下执行
class CyclicBarrierTest implements Runnable{
private CyclicBarrier cyclicBarrier ;
public CyclicBarrierTest(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"到达会议室");
try {
cyclicBarrier.await(); // 栅栏,先要等所有线程都到这个位置
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"总结上周工作");
}
}
public class Test {
public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
// 传入一个Runnable对象,等所有线程到达栅栏位置之后再随便挑选一个线程执行这个任务 打印会议开始
CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable(){
@Override
public void run(){
System.out.println("会议开始");
}
});
CyclicBarrierTest test = new CyclicBarrierTest(cyclicBarrier);
List<Thread> list = new ArrayList<>();
for (int i=0; i<5; i++)
{
Thread thread = new Thread(test, "成员"+i);
list.add(thread);
}
System.out.println("等待所有人到达会场...");
for (Thread t : list)
{
t.start();
}
}
}
运行结果:
3、Exchanger线程交换器
Exchange主要用于再两个线程之间交换数据,就是当两个线程配对之后(调用Exchanger里面的exchange方法),将两个线程间的数据交换,然后再一起执行,如果只有一个线程调用exchange方法,这个线程将阻塞,直到有另一个线程和他配对,下面看例子:
// 一个Boy线程
class Boy implements Runnable{
private Exchanger exchanger ;
public Boy(Exchanger exchanger) {
this.exchanger = exchanger;
}
@Override
public void run() {
String say = "我是24K纯爷们..." ;
try {
say = (String) exchanger.exchange(say);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("男孩说:"+say);
}
}
// 一个Girl线程
class Gril implements Runnable{
private Exchanger exchanger ;
public Gril(Exchanger exchanger) {
this.exchanger = exchanger;
}
@Override
public void run() {
String say = "我是可爱的小仙女...";
try {
say = (String) exchanger.exchange(say);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("女孩说:"+say);
}
}
public class Test {
public static void main(String[] args) {
Exchanger<String> exchanger = new Exchanger<>() ;
Boy boy = new Boy(exchanger) ;
Gril gril = new Gril(exchanger) ;
new Thread(boy).start() ;
new Thread(gril).start() ;
}
}
运行结果: