文章目录
- 一、CountDownLatch
- 二、CyclicBarrier
- 三、Semaphore
- 四、Phaser
提示:以下是本篇文章正文内容,下面案例可供参考
一、CountDownLatch
CountDownLatch如同火箭发射,计数只能不断减减,当到达0时即发射
场景示例:考场中有多个同学考试,每个同学写完试卷后,将试卷交给老师即可离开,老师需要收齐所有人的试卷后才能离开。
代码如下(示例):
public class Test {public static void main(String[] args) throws InterruptedException {// CountDownLatch 倒计时到0,发射(减法)// 考场学生人数为 6(一旦定下就不能在增加)CountDownLatch countDownLatch = new CountDownLatch(6);for (int i = 1; i <= 6; i++) {new Thread(() -> {try {// 模拟每个学生完成试卷的时间不同(线程休眠随机时间)Thread.sleep(new Random().nextInt(3000));} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "\t同学写完,离开教室");// 上交试卷给老师(走一个,计数减少一个)countDownLatch.countDown();}, i + "号考生").start();}// 主线程相当于老师,需要等所有的人交卷,才能离开(阻塞当前线程,等待所有线程完成任务,即 countDown)countDownLatch.await();Thread.currentThread().setName("老师");System.out.println(Thread.currentThread().getName() + "\t收齐试卷,关门走人");}
}
输出结果:
二、CyclicBarrier
CyclicBarrier如同游戏匹配,不凑齐人数,就一直在匹配界面,达到指定人数后才能开始对战
代码如下(示例):
public class Test {public static void main(String[] args) throws InterruptedException {// CyclicBarrier 指定值达到 0,发射// 需要十个人才能开始游戏,(指定个数,之后不能改变,满足条件后,自动执行 Runnable 方法)CyclicBarrier cyclicBarrier = new CyclicBarrier(10, () -> {System.out.println("十个人已经全部确认,开始游戏");});for (int i = 1; i <= 10; i++) {final int tmpInt = i;new Thread(() -> {try {// 模拟玩家匹配时间Thread.sleep(new Random().nextInt(3000));} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "\t已经确认");try {// 等待其他玩家准备(阻塞等待,等待人数减 1,减到 0,就发车)cyclicBarrier.await();} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();}}, tmpInt + "号玩家").start();}}
}
输出结果:
三、Semaphore
Semaphore如同一个停车场,里面的车位数是固定的,当停满车后,必须有车出来才能再进
Semaphore 主要用于两个目的,一个是用于多个共享资源的互斥使用,另一个用于并发线程数的控制。
涉及到并发就有有两种模式:
- 非公平(谁抢到是谁的),默认是非公平的
public Semaphore(int permits) {sync = new NonfairSync(permits);}
- 公平(先来后到),当 fair 为 true 是公平的
public Semaphore(int permits, boolean fair) {sync = fair ? new FairSync(permits) : new NonfairSync(permits);}
代码如下(示例):
public class Test {public static void main(String[] args) throws InterruptedException {// 一共 3 个停车位(资源数开始时固定)Semaphore semaphore = new Semaphore(3);// 默认非公平(抢占式)// 模拟 6 辆汽车要停车for (int i = 1; i <= 6; i++) {new Thread(() -> {try {// 询问还有没有停车位,有就进去,没有等待(获得资源)semaphore.acquire();System.out.println(Thread.currentThread().getName() + "\t抢到车位");// 模拟停车时间Thread.sleep(new Random().nextInt(3000));System.out.println(Thread.currentThread().getName() + "\t事情办完,离开车位");} catch (InterruptedException e) {e.printStackTrace();} finally {// 办完事情,开车离开(释放资源)semaphore.release();}}, i + "号车主").start();}}
}
输出结果:
四、Phaser
Phaser是JDK 7新增的一个同步辅助类,它可以实现CyclicBarrier和CountDownLatch类似的功能,而且它支持对任务的动态调整,并支持分层结构来达到更高的吞吐量。
CountDownLatch 和 CyclicBarrier 在最初就固定了线程的数量,而且中途不可改变,当完成指定的任务后,就不能再次使用,Phaser 就解决了该问题。
class player implements Runnable {private final Phaser phaser;player(Phaser phaser) {this.phaser = phaser;}@Overridepublic void run() {try {// 第一阶段——确定参赛的运动员人数(等待创建好所有线程再开始)phaser.arriveAndAwaitAdvance();// 第二阶段——等待所有选手都做好准备,发令枪再开始Thread.sleep(new Random().nextInt(3000));// 模拟热身准备System.out.println(Thread.currentThread().getName() + "号运动员准备完毕");phaser.arriveAndAwaitAdvance();// 第三阶段——所有运动员开始跑步Thread.sleep(new Random().nextInt(3000));// 模拟跑步时间System.out.println(Thread.currentThread().getName() + "号运动员冲线!");// 冲线后结束(线程下线注销)phaser.arriveAndDeregister();} catch (InterruptedException e) {e.printStackTrace();}}
}public class Test {public static void main(String[] args) throws InterruptedException {// 模拟了 100 米赛跑,10 名运动员,只等裁判一声令下。当所有人都到达终点时,比赛结束。// 设置初始的注册人数(1 个裁判)final Phaser phaser = new Phaser(1);// 十名运动员for (int index = 0; index < 10; index++) {// 每个运动员都注册到其中,即确定参加比赛(动态增加,复用)phaser.register();new Thread(new player(phaser), index + "号运动员").start();}System.out.println("比赛开始");// 裁判下线,注销当前线程,比赛开始phaser.arriveAndDeregister();// 所有运动员是否到达终点,没有就一直等待while (!phaser.isTerminated()) {}System.out.println("所有运动员到达终点,比赛结束");}
}
输出结果: