目录
CountDownLatch
官方文档解释:CountDownLatch是一种同步辅助工具,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。
CountDownLatch 使用给定的计数进行初始化。await 方法会阻塞,直到当前计数因 countDown() 方法的调用而减至零,此后所有等待的线程被释放,并且任何后续对 await 的调用都会立即返回。这是一次性现象------计数无法重置。如果需要可以重置计数的版本,请考虑使用 CyclicBarrier。
使用示例:
java
import java.util.concurrent.CountDownLatch;
public class CountDownLatchTest {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "..........");
countDownLatch.countDown(); //数量减一
}, String.valueOf(i)).start();
}
// countDownLatch.await(); //等待计数器归零, 然后向下执行
System.out.println("已经全部执行完成");
}
}
如果不加上await方法的话,线程不会被阻塞,main线程往下执行,输出打印

如果加上了await方法的话,线程会等待计数器归零才会往下执行

原理
countDownLatch.countDown() //数量减一
countDownLatch.await() //等待计数器归零,然后向下执行
每次有线程调用countDown()数量-1,假设计数器变为0,countDownLatch.await()就会被唤醒,继续执行
CyclicBarrier
CyclicBarrier 是一种同步辅助工具,它允许一组线程互相等待,直到所有线程都到达一个共同的屏障点。CyclicBarrier 在涉及固定大小线程组的程序中非常有用,这些线程偶尔需要互相等待。这个屏障被称为"循环的",是因为它可以在等待的线程被释放后重复使用。 CyclicBarrier 支持一个可选的 Runnable 命令,该命令在每个屏障点执行一次------在组中最后一个线程到达屏障之后,但在任何线程被释放之前。这个屏障操作对于在任意线程继续执行之前更新共享状态非常有用。
通俗理解就是加法计数器
使用方法和CountDownLatch类似
java
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierTest {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(5, () -> {
System.out.println("达到5了.............");
});
//创建5个线程
for (int i = 1; i <= 5; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName());
try {
cyclicBarrier.await(); // 等待
} catch (InterruptedException | BrokenBarrierException e) {
throw new RuntimeException(e);
}
}, "Thread-" + i).start();
}
}
}
代码创建了一个CyclicBarrier屏障类,它会阻塞到达屏障的线程,然后在构造器里面传入了参数5,表示五个线程到达屏障之后就会释放所有线程,并且传入了一个Runnable线程打印结果
Semaphore
Semaphore 是一个计数信号量。从概念上讲,信号量维护着一组许可。每个 acquire() 方法在必要时会阻塞,直到有可用的许可,然后获取该许可。每个 release() 方法会添加一个许可,可能会释放一个正在阻塞的获取者。但是,并没有实际的许可对象被使用;Semaphore 只是维护可用数量的计数并相应地执行操作。
使用方法
java
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class SemaphoreTest {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3); //允许3个线程同时拥有资源
for (int i = 0; i < 5; i++) {
new Thread(() -> {
try {
semaphore.acquire(); // 线程得到信号量
System.out.println(Thread.currentThread().getName() + "得到信号量......");
TimeUnit.SECONDS.sleep(5); //休眠两秒钟
System.out.println(Thread.currentThread().getName() + "释放信号量......");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
semaphore.release(); //释放信号量
}
}, String.valueOf(i)).start();
}
}
}
代码解释:
首先是某三个线程得到信号量,然后是休眠五秒钟后,执行finally代码块里面的release方法释放掉,随后空闲的三个信号量又被其他两个线程拿走(剩下了一个),休眠五秒钟后释放。

