java 中 CountDownLatch、CyclicBarrier 和 Semaphore 的简单使用

一、CountDownLatch

1.1 概述

       让一些线程阻塞直到另外一些完成后才被唤醒。

       该类主要有两个方法,当一个或多个线程调用 await 方法时,调用线程会被阻塞。其他线程调用 countDown方法计数器减1(调用countDown方法时线程不会阻塞),当计数器的值变为0,因调用 await 方法被阻塞的线程会被唤醒继续执行。

1.2 模拟场景

       有 6 名学生上完课后,离开教室,但他们离开的时间不相同,班长需要最后一个离开,锁上教室的门。

1.3 程序模拟

1.3.1 使用 CountDownLatch 之前

  1 public void closeDoor() {
  2 
  3     for (int i = 1; i <= 6; i++) {
  4         new Thread(() -> {
  5             System.out.println(Thread.currentThread().getName() + " 离开教室");
  6         }, String.valueOf(i)).start();
  7     }
  8 
  9     System.out.println(Thread.currentThread().getName() + " 班长锁门离开教室");
 10 }

image

1.3.2 使用 CountDownLatch 之后

  1 public void closeDoor() throws InterruptedException {
  2     CountDownLatch countDownLatch = new CountDownLatch(6);
  3 
  4     for (int i = 1; i <= 6; i++) {
  5         new Thread(() -> {
  6             System.out.println(Thread.currentThread().getName() + " 离开教室");
  7             countDownLatch.countDown();
  8         }, String.valueOf(i)).start();
  9     }
 10 
 11     countDownLatch.await();
 12     System.out.println(Thread.currentThread().getName() + " 班长锁门离开教室");
 13 }

image

1.4 CountDownLatch 配合枚举类的使用

  1 private static void nationalUnification() throws InterruptedException {
  2     CountDownLatch countDownLatch = new CountDownLatch(6);
  3 
  4     for (int i = 1; i <= 6; i++) {
  5         new Thread(() -> {
  6             System.out.println(Thread.currentThread().getName() + "国被灭...");
  7             countDownLatch.countDown();
  8         }, CountryEnum.forEachCountryEnum(i).getCountry()).start();
  9     }
 10 
 11     countDownLatch.await();
 12     System.out.println(Thread.currentThread().getName() + " 秦国灭六国,一统华夏");
 13 }
 14 
 15 // 枚举类,存储国家的名字
 16 public enum CountryEnum {
 17 
 18     ONE(1, ""),
 19     TWO(2, ""),
 20     THREE(3, ""),
 21     FOUR(4, ""),
 22     FIVE(5, ""),
 23     SIX(6, "");
 24 
 25     private Integer code;
 26     private String country;
 27 
 28     CountryEnum(Integer code, String country) {
 29         this.code = code;
 30         this.country = country;
 31     }
 32 
 33     public Integer getCode() {
 34         return code;
 35     }
 36 
 37     public String getCountry() {
 38         return country;
 39     }
 40 
 41     public static CountryEnum forEachCountryEnum(int index) {
 42         CountryEnum[] countryEnums = CountryEnum.values();
 43         for (CountryEnum element : countryEnums) {
 44             if (element.getCode() == index) {
 45                 return element;
 46             }
 47         }
 48         return null;
 49     }
 50 }
 51 
image

二、CyclicBarrier

2.1 概述

       CyclicBarrier 的字面意思是可循环(Cyclic),使用的屏障(barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫做同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活,线程进入屏障通过 CyclicBarrier 的 await() 方法。

2.2 示例

  1 public void meet() {
  2     CyclicBarrier cyclicBarrier = new CyclicBarrier(10, () -> {
  3         System.out.println("人齐了,准备开会");
  4     });
  5 
  6     for (int i = 1; i <= 10; i++) {
  7         new Thread(() -> {
  8             System.out.println(Thread.currentThread().getName() + " 来到会议室");
  9             try {
 10                 cyclicBarrier.await();
 11             } catch (InterruptedException | BrokenBarrierException e) {
 12                 e.printStackTrace();
 13             }
 14         }, String.valueOf(i)).start();
 15     }
 16 }
image

三、Semaphore

3.1 概述

       A counting semaphore. Conceptually, a semaphore maintains a set of permits. Each acquire() blocks if necessary until a permit is available, and then takes it. Each release() adds a permit, potentially releasing a blocking acquirer. However, no actual permit objects are used; the Semaphore just keeps a count of the number available and acts accordingly.

3.2 示例

  1 public void semaphoreTest() {
  2     Semaphore semaphore = new Semaphore(3);
  3 
  4     for (int i = 1; i <= 6; i++) {
  5         new Thread(() -> {
  6             try {
  7                 semaphore.acquire();
  8                 System.out.println(Thread.currentThread().getName() + " 抢到车位...");
  9                 TimeUnit.SECONDS.sleep(3);
 10                 System.out.println(Thread.currentThread().getName() + "停车3秒,离开车位");
 11             } catch (InterruptedException e) {
 12                 e.printStackTrace();
 13             } finally {
 14                 semaphore.release();
 15             }
 16         }, String.valueOf(i)).start();
 17     }
 18 }
image
posted @ 2019-11-21 16:01  辰凩風  阅读(171)  评论(0编辑  收藏  举报