CountDownLatch(减法计数器)
允许一个或多个线程等待直到在其他线程中执行的一组操作完成的同步辅助。
CountDownLatch
是一种通用的同步工具,可用于多种用途。 一个CountDownLatch
为一个计数的CountDownLatch用作一个简单的开/关锁存器,或者门:所有线程调用await()
在门口等待,直到被调用countDown()
的线程打开。 一个CountDownLatch
初始化N可以用来做一个线程等待,直到N个线程完成某项操作,或某些动作已经完成N次。计数无法重置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| package cn.running.multithreading.coding;
import cn.hutool.core.lang.Console; import cn.hutool.core.util.StrUtil;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit;
public class StudyAuxiliary {
public static void studyCountDownLatch() throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(5); Console.log("开始组队!等待队员!"); for (int i = 0; i < 10; i++) { new Thread(() -> { String tempPlayer = Thread.currentThread().getName(); Console.log("已邀请 {} 队员!", tempPlayer); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } countDownLatch.countDown(); Console.log("{} 已接受邀请!", tempPlayer); }, StrUtil.format("队员{}号", i)).start(); } countDownLatch.await(); Console.log("队伍已满,开始游戏"); }
public static void main(String[] args) throws InterruptedException { studyCountDownLatch(); } }
|
init:开启一个5人的组队,等待邀请的队员,因网络延迟影响,我们加入了睡眠等待
每个线程睡醒会去调用countDown()
减少初始计数
1:好友邀请已全部发送,队伍一直再阻塞等待队员
2:队员们尝试进入队伍,但只会有5位队员可以成功进入
3:队伍满员,队伍不在阻塞等待,游戏直接开始
4:其余队员接受邀请较晚,队伍已满,尝试进入队伍失败
CyclicBarrier(加法计数器)
允许一组线程全部等待彼此达到共同屏障点的同步辅助。
CyclicBarrier
支持一个可选的Runnable
命令,每个屏障点运行一次,在派对中的最后一个线程到达之后,但在任何线程释放之前。 在任何一方继续进行之前,此屏障操作对更新共享状态很有用。可以循环使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| package cn.running.multithreading.coding;
import cn.hutool.core.lang.Console; import cn.hutool.core.util.StrUtil;
import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.TimeUnit;
public class StudyAuxiliary {
public static void studyCyclicBarrier() { CyclicBarrier cyclicBarrier = new CyclicBarrier(5, () -> System.out.println("队伍已满,开始游戏")); for (int i = 0; i < 10; i++) { new Thread(() -> { String tempPlayer = Thread.currentThread().getName(); Console.log("已邀请 {} 队员!", tempPlayer); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } Console.log("{} 已接受邀请!", tempPlayer); try { cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } }, StrUtil.format("队员{}号", i)).start(); } }
public static void main(String[] args) throws InterruptedException { studyCyclicBarrier(); } }
|
init:开启一个5人的组队,等待邀请的队员,因网络延迟影响,我们加入了睡眠等待
每个线程睡醒会去调用await()
进行等待其他线程,直到最后一个线程调用await()
1:好友邀请已全部发送,队伍等待队员
2:队员们尝试进入队伍,但只会有5位队员可以成功进入一个队伍,队伍满员,当前队伍不在等待,开始游戏
3:其余队员接受邀请较晚,尝试进入新队伍,开始游戏
Semaphore(信号量)
一个计数信号量。
在概念上,信号量维持一组许可证。 如果有必要,每个acquire()
都会阻塞,直到许可证可用,然后才能使用它。 每个release()
添加许可证,潜在地释放阻塞获取方。 但是,没有使用实际的许可证对象; Semaphore
只保留可用数量的计数,并相应地执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| package cn.running.multithreading.coding;
import cn.hutool.core.lang.Console; import cn.hutool.core.util.StrUtil;
import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit;
public class StudyAuxiliary {
public static void studySemaphore() { Semaphore semaphore = new Semaphore(5); for (int i = 0; i < 10; i++) { new Thread(() -> { String tempSpace = Thread.currentThread().getName(); try { semaphore.acquire(); Console.log("{} 驶入车位!", tempSpace); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } Console.log("{} 驶出车位!", tempSpace); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); } }, StrUtil.format("劳斯莱斯{}号", i)).start(); }
}
public static void main(String[] args) { studySemaphore(); } }
|
init:初始化5个车位,等待车辆驶入
每个线程调用acquire()
阻塞获得,直到调用release()
释放
只有5个车位,只允许驶入5个车辆,驶出一辆车就可以驶入一辆车