countDownLatch、CyclicBarrier、Semaphore
countDownLatch 简介
countDownLatch这个类使一个线程等待其他线程各自执行完毕后再执行。
是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。
减法计数器
原理 countDownLatch.countDown();
// 数量-1countDownLatch.await();
// 等待计数器归零,然后向下执行 每次有线程调用countDown(),数量减一,假设计数器变为0,countDownLatch.await();就会被唤醒,继续执行!
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class CountDownLatchDemo { public static void main (String[] args) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(6 ); for (int i = 0 ; i <= 6 ; i++) { new Thread(() -> { System.out.println(Thread.currentThread().getName() + " Go out" ); countDownLatch.countDown(); }, String.valueOf(i)).start(); } countDownLatch.await(); System.out.println("close door" ); } }
结果:
1 2 3 4 5 6 7 8 // x顺序不确定,但只有6个线程结束后才向下执行 x Go out x Go out x Go out x Go out x Go out x Go out Close door
CyclicBarrier 简介
举个例子,就像生活中我们会约朋友们到某个餐厅一起吃饭,有些朋友可能会早到,有些朋友可能会晚到,但是这个餐厅规定必须等到所有人到齐之后才会让我们进去。这里的朋友们就是各个线程,餐厅就是 CyclicBarrier。
作用 CyclicBarrier的作用是让所有线程都等待完成后才会继续下一步行动。
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class CyclicBarrierDemo { public static void main (String[] args) { CyclicBarrier cyclicBarrier = new CyclicBarrier(7 , () -> { System.out.println("召唤神龙成功!" ); }); for (int i = 1 ; i <= 7 ; i++) { final int temp = i; new Thread(() -> { System.out.println(Thread.currentThread().getName() + "收集了" + temp + "个龙珠" ); try { cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } }).start(); } } }
结果
1 2 3 4 5 6 7 8 Thread-1 收集了2 个龙珠 Thread-2 收集了3 个龙珠 Thread-0 收集了1 个龙珠 Thread-3 收集了4 个龙珠 Thread-4 收集了5 个龙珠 Thread-5 收集了6 个龙珠 Thread-6 收集了7 个龙珠 召唤神龙成功!
Semaphore 简介 一般用来控制同时访问特定共享资源的线程数,它通过协调各个线程来保证使用公共资源的合理性。
作用
Semaphore的作用是控制并发访问的线程数目。
多个共享资源互斥使用,开发限流!
原理 semaphore.acquire()
// 获得,假设已经满了,等待,等待被释放为止semaphore.release()
// 释放,会将当前的信号量释放 + 1,然后唤醒等待线程!
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class SemaphoreDemo { public static void main (String[] args) { Semaphore semaphore = new Semaphore(3 ); for (int i = 1 ; i <= 6 ; i++) { new Thread(() -> { try { semaphore.acquire(); System.out.println(Thread.currentThread().getName() + "抢到车位" ); TimeUnit.SECONDS.sleep(2 ); System.out.println(Thread.currentThread().getName() + "离开车位" ); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); } }, String.valueOf(i)).start(); } } }
结果:
1 2 3 4 5 6 7 8 9 10 11 12 1 抢到车位2 抢到车位3 抢到车位1 离开车位2 离开车位3 离开车位4 抢到车位6 抢到车位5 抢到车位4 离开车位6 离开车位5 离开车位
CountDownLatch和CyclicBarrier区别
countDownLatch是一个计数器,线程完成一个记录一个,计数器递减,只能只用一次
CyclicBarrier的计数器更像一个阀门,需要所有线程都到达,然后继续执行,计数器递增,提供reset功能,可以多次使用。