CountDownLatch/CyclicBarrier/Semaphore
CountDownLatch
让一些线程堵塞直到另一个线程完成一系列操作后才被唤醒。CountDownLatch 主要有两个方法,当一个或多个线程调用 await 方法时,调用线程会被堵塞,其他线程调用 countDown 方法会将计数减一(调用 countDown 方法的线程不会堵塞),当计数其值变为零时,因调用 await 方法被堵塞的线程会被唤醒,继续执行
/** * 假设我们有这么一个场景,教室里有班长和其他6个人在教室上自习,班长要在其他同学走后关门 */ public class CountDownLanchDemo { public static void main(String[] args) { for (int i = 0; i < 6; i++) { new Thread(() -> { System.out.println(Thread.currentThread().getName() + " 离开了教室..."); }, String.valueOf(i)).start(); } System.out.println("班长把门给关了,离开了教室..."); } } // 输出: // 0 离开了教室... // 1 离开了教室... // 2 离开了教室... // 3 离开了教室... // 班长把门给关了,离开了教室... // 5 离开了教室... // 4 离开了教室...
/** * 发现班长都没有等其他人理他教室就把门给关了,此时我们就可以使用 CountDownLatch 来控制 */ public class CountDownLanchDemo { public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(6); for (int i = 0; i < 6; i++) { new Thread(() -> { countDownLatch.countDown(); System.out.println(Thread.currentThread().getName() + " 离开了教室..."); }, String.valueOf(i)).start(); } countDownLatch.await(); System.out.println("班长把门给关了,离开了教室..."); } } // 输出: // 0 离开了教室... // 1 离开了教室... // 2 离开了教室... // 3 离开了教室... // 4 离开了教室... // 5 离开了教室... // 班长把门给关了,离开了教室...
CyclicBarrier
/** * 我们假设有这么一个场景,每辆车只能坐个人,当车满了,就发车 */ public class CyclicBarrierDemo { public static void main(String[] args) { CyclicBarrier cyclicBarrier = new CyclicBarrier(4, () -> { System.out.println("车满了,开始出发..."); }); for (int i = 0; i < 8; i++) { new Thread(() -> { System.out.println(Thread.currentThread().getName() + " 开始上车..."); try { cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } }).start(); } } } // 输出: // Thread-0 开始上车... // Thread-1 开始上车... // Thread-3 开始上车... // Thread-4 开始上车... // 车满了,开始出发... // Thread-5 开始上车... // Thread-7 开始上车... // Thread-2 开始上车... // Thread-6 开始上车... // 车满了,开始出发...
Semaphore
/** * 假设我们有 3 个停车位,6 辆车去抢,走一辆进一辆 */ public class SemaphoreDemo { public static void main(String[] args) { Semaphore semaphore = new Semaphore(3); for (int i = 0; i < 6; i++) { new Thread(() -> { try { semaphore.acquire(); // 获取一个许可 System.out.println(Thread.currentThread().getName() + " 抢到车位..."); Thread.sleep(3000); System.out.println(Thread.currentThread().getName() + " 离开车位"); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); // 释放一个许可 } }).start(); } } } // 输出: // Thread-1 抢到车位... // Thread-2 抢到车位... // Thread-0 抢到车位... // Thread-2 离开车位 // Thread-0 离开车位 // Thread-3 抢到车位... // Thread-1 离开车位 // Thread-4 抢到车位... // Thread-5 抢到车位... // Thread-3 离开车位 // Thread-5 离开车位 // Thread-4 离开车位