1. CountDownLatch
允许一个或多个线程等待直到在其他线程中执行的一组操作完成的同步辅助。CountDownLatch用给定的计数初始化。 await方法阻塞,直到由于countDown()方法的调用而导致当前计数达到零,之后所有等待线程被释放,并且任何后续的await 调用立即返回。 (理解成线程的减法计数器)
CountDownLatch是一种通用的同步工具,可用于多种用途。 一个CountDownLatch为一个计数的CountDownLatch用作一个简单的开/关锁存器,或者门:所有线程调用await在门口等待,直到被调用countDown()的线程打开。 一个CountDownLatch初始化N可以用来做一个线程等待,直到N个线程完成某项操作,或某些动作已经完成N次。
countDown
await
案例:
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 0; i < 6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"ThreadOut");
countDownLatch.countDown();
},String.valueOf(i)).start();
}
countDownLatch.await();
System.out.println("AllStop");
0ThreadOut
1ThreadOut
4ThreadOut
5ThreadOut
2ThreadOut
3ThreadOut
AllStop
不加 countDownLatch.await();
0ThreadOut
3ThreadOut
AllStop
1ThreadOut
2ThreadOut
5ThreadOut
4ThreadOut
2. CyclicBarrier
允许一组线程全部等待彼此达到共同屏障点的同步辅助。 循环阻塞在涉及固定大小的线程方的程序中很有用,这些线程必须偶尔等待彼此。 屏障被称为循环 ,因为它可以在等待的线程被释放之后重新使用。 (理解成线程加分计数器)
CyclicBarrier支持一个可选的Runnable命令,每个屏障点运行一次,在parties中的最后一个线程到达之后,但在任何线程释放之前。 在任何一方继续进行之前,此屏障操作对更新共享状态很有用。
构造方法
await
案例:召唤神龙;当线程数累加到7时,才会达到结束堵塞条件,如果达不到则一直堵塞;
// 召唤龙珠的线程
CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
System.out.println(Thread.currentThread().getName()+"召唤神龙");
});
for (int i = 1; i <= 7; i++) {
final int tmp=i;
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"获取龙珠"+tmp);
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
Thread-1获取龙珠2
Thread-0获取龙珠1
Thread-4获取龙珠5
Thread-3获取龙珠4
Thread-2获取龙珠3
Thread-5获取龙珠6
Thread-6获取龙珠7
Thread-6召唤神龙
当parties数量大于等待线程的数量时候,就会死锁;
Thread-1获取龙珠2
Thread-2获取龙珠3
Thread-0获取龙珠1
Thread-3获取龙珠4
Thread-4获取龙珠5
Thread-6获取龙珠7
Thread-5获取龙珠6
3.Semaphore
一个计数信号量。 在概念上,信号量维持一组许可证。 在一个线程中通过acquire()获取一张通行证,release()方法释放该通行证。如果信号量中通行证剩余数量为0,则该线程堵塞,只有等待其他线程释放通行证才能使用。(限流的思想)
acquire方法
release
抢车位案例:六个线程(车)抢占3个信号量(车位)
//抢车位案例
//设置线程数量:车位限定3个(限流)
Semaphore semaphore = new Semaphore(3);
for (int i = 1; i < 6; i++) {
final int tmp=i;
new Thread(()->{
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"抢占车位"+tmp);
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+"离开车位"+tmp);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release();
}
},String.valueOf(i)).start();
}
2抢占车位2
3抢占车位3
1抢占车位1
1离开车位1
2离开车位2
3离开车位3
4抢占车位4
5抢占车位5
4离开车位4
5离开车位5