java多线程CountDownLatch、CyclicBarrier、Semaphore详解

CountDownLatch, CyclicBarrier, Semaphore是什么

控制线程之间通信的工具类,在juc包下

CountDownLatch

作用:用来控制线程顺序 ( 一堆线程运行,当其他所有线程运行完成后,在执行指定的线程 )

一句话总结:班长最后离开教室

案例:现在有6个人和班长在教室里上自习,要求 班长等所有学生离开教室后,才能锁门走人

//问题代码:
public static void main(String[] args) {
    for (int i = 1; i <= 6; i++) {
        int num = i;
        new Thread(() -> {
                System.out.println("第" + num +"个人离开教室");
        }, String.valueOf(i)).start();
    }
    System.out.println("班长离开教室");
}
//出现结果:
//班长最后一个走只是几率事件,有可能出现的情况是:班长没有等到最后一个人离开自己就已经把教室的门锁上了

解决方案:使用CountDownLatch

public static void main(String[] args) throws InterruptedException {
    CountDownLatch countDownLatch = new CountDownLatch(6);
    for (int i = 1; i <= 6; i++) {
        int num = i;
        new Thread(() -> {
            System.out.println("第" + num + "个人离开教室");
            //表示开始计数,每执行一次,就计数一次
            countDownLatch.countDown();
        }, String.valueOf(i)).start();
    }
    //表示次线程进入阻塞状态,只有当其他线程全部都走完了之后,才能执行此线程
    countDownLatch.await();
    System.out.println("班长离开教室");
}
//countDownLatch.countDown() 计数了6次后, 被await的线程才会继续执行

使用 await ()方法执行结果如图所示
在这里插入图片描述

使用 await(long timeout, TimeUnit unit) 方法执行结果如图所示在这里插入图片描述

主要方法:
新建一个计数器 new CountDownLatch ( int I ) ;

表示创建一个CountDownLatch执行器 ( ) 中的参数表示等待的线程数

执行计数方法 public void countDown() :

表示程序开始计数,每执行完成一次线程,都需要调用一次这个方法,构造方法中调用的参数是几,就需要调用这个方法几次

线程进入阻塞状态 public void await()

表示让其他线程进入阻塞状态

进入阻塞状态扩展方法:public boolean await(long timeout, TimeUnit unit)

表示让其他线程进入阻塞状态,但是 如果阻塞的时间达到了设定的时间,不管计数是否完成,都会执行被阻塞的线程

注意点
  1. CountDownLatch 的构造方法中() 中的int类型 需要和等待的子线程数一致
    1. 如果不一致的话 x > 等待线程数 等待线程会处于阻塞状态,不能继续执行下去
    2. 如果 x < 等待线程数,等待线程会和其他线程提前开始抢占CPU资源

CountDownLatch 执行原理

CountDownLatch主要有2个方法 ( countDown方法和await方法 ) ,当一个或多个线程调用 await 方法时,这些线程会阻塞。

其他线程调用countDown方法会将计数器减1 ( 调用countDown方法的线程不会阻塞 )

当计数器的值变为0时,因await方法阻塞的线程会被唤醒,继续执行

CyclicBarrier

一句话总结:集齐七颗龙珠才能召唤神龙

public static void main(String[] args) {
    CyclicBarrier cyclicBarrier = new CyclicBarrier(6, () -> {
        System.out.println("神龙啊");
    });
    for (int i = 1; i <= 6; i++) {
        int num = i;
        new Thread(() -> {
            System.out.println("集齐第" + num + "颗龙珠");
            try {
                cyclicBarrier.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, String.valueOf(i)).start();
    }
}

执行结果如下
在这里插入图片描述

主要作用方法:
new CyclicBarrier(int parties, Runnable barrierAction)

表示创建一个循环栅栏,计数完成后 执行Runnable中的内容

public int await()

表示 让其他线程进入阻塞状态

CountDownLatch 和 CyclicBarrier 和 semaphore 的区别是什么

  1. CountDownLatch 计数器依次递减,最终执行其他线程中的操作
  2. CyclicBarrier 循环栅栏依次递增,最终执行 Runnable 线程中的内容
  3. Semaphore 有加有减的情况

semaphore

一句话总结:抢车位

举个例子:现在有6部车,但是只有3个停车位,要求前3辆车先停在车位上 停2秒中后,另外3辆车继续抢占这3个车位,直到每个车都停了3秒中后,执行完成

public static void main(String[] args) {
    //模拟有3个空车位
    Semaphore semaphore = new Semaphore(3);
    //6个线程来抢3个资源
    for (int i = 1; i <= 6; i++) {
        int num = i;
        new Thread(() -> {
            try {
                semaphore.acquire();
                System.out.println(Thread.currentThread().getName() + "抢到了第" + num + "个车位");
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName() + "离开了");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                semaphore.release();
            }
        }, String.valueOf(i)).start();
    }
}

执行结果如下
在这里插入图片描述

主要方法:
public Semaphore(int permits)

创建一个信号量, permits 表示的是共享资源的数量

public void acquire()

当一个线程调用 acquire操作时,他要么成功获取信号量 ( 信号量 减1 ),要么一直等下去,直到有线程释放信号量 或超时

public void release()

release ( 释放 ) 实际上会将信号量的值 加1,然后唤醒等待的线程

Semaphore的作用

  1. 用于多个共享资源的互斥使用,
  2. 用于并发线程数的控制(如果不控制线程数的话,可能会导致线程吧服务器冲垮了)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值