CountDownLatchCyclicBarrierSemaphore多线程协助操作API

Posted learning_code_blog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CountDownLatchCyclicBarrierSemaphore多线程协助操作API相关的知识,希望对你有一定的参考价值。

目录

Semaphore信号量

CountDownLatch协助线程

CyclicBarrier 循环利用

总结


主要说一下应用场景

Semaphore信号量

 场景:Semaphore 许可证
1、可以限制每个资源同时处理能力 比如:一个API接口、限制只能同时两个线程响应请求,其余的线程需要等待
处理逻辑:
 a.获取线程之后semaphore.acquire() -- 如果没有获取,则会阻塞
 b.用完之后释放 semaphore.release();

场景1:一个API接口,限制同时只能两个线程想相应请求,针对单机版本,可以做限流处理。


public class SemaphoreDemo01 

    static Semaphore semaphore = new Semaphore(3);

    /**
     * Semaphore 许可证
     * 1、可以限制每个资源同时处理能力 比如:一个API接口、限制只能同时两个线程响应请求,其余的线程需要等待
     * 处理逻辑:
     * a.获取线程之后semaphore.acquire() -- 如果没有获取,则会阻塞
     * b.用完之后释放 semaphore.release();
     * @param args
     */
    public static void main(String[] args) 
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) 
            int  finalInt = i ;
            executorService.submit(() -> 
                try 
                    // 获取许可证 如果没有获取,则会阻塞
                    semaphore.acquire();
//                    semaphore.acquire(2); // 可以一次性获取2个授权
                 catch (InterruptedException e) 
                    e.printStackTrace();
                
                System.out.println(Thread.currentThread().getName()+"拿到许可证,耗时2 s");
                try 
                    Thread.sleep(2000);
                 catch (InterruptedException e) 
                    e.printStackTrace();
                
                System.out.println("慢服务执行完成:"+Thread.currentThread().getName());
                // 释放许可证
                semaphore.release();
            );
        
        executorService.shutdown();
    

CountDownLatch协助线程

 两种用法:允许一个或多个线程,等待其他一组线程完成操作,再继续执行。

场景1:eg: 比如去查询外部接口API,多个不同类型的API都需要请求

跑步为例,所有runner都需要等待裁判员枪响之后才开始运动


public class CountDownLatchDemo03 

    /**
     * 运动员 到达终点、所有场景统一汇合之后然后进行
     */
   static CountDownLatch countDownLatch = new CountDownLatch(10);

    public static void main(String[] args) throws InterruptedException 
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) 
            int finalInt = i ;
            executorService.submit(()->
                try 
                    Thread.sleep((long) (Math.random()*100));
                    countDownLatch.countDown();
                 catch (Exception e) 
                    e.printStackTrace();
                
                System.out.println("第" + finalInt + "号 到达终点 ");
            );
        
        System.out.println("等待所有运动员跑完");
        countDownLatch.await();
        System.out.println("所有人都跑完了");
        executorService.shutdown();
    

场景2   

  •  运动员到达终点时,需要知道是否已经所有运动员已经到场了
  • 程序中,比如买机票,针对同一个行程,从不同的航空公司获取对应的票价返回给前端。 

public class CountDownLatchDemo03 

    /**
     * 运动员 到达终点
     */
   static CountDownLatch countDownLatch = new CountDownLatch(10);

    public static void main(String[] args) throws InterruptedException 
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) 
            int finalInt = i ;
            executorService.submit(()->
                try 
                    Thread.sleep((long) (Math.random()*100));
                    countDownLatch.countDown();
                 catch (Exception e) 
                    e.printStackTrace();
                
                System.out.println("第" + finalInt + "号 到达终点 ");
            );
        
        System.out.println("等待所有运动员跑完");
        countDownLatch.await();
        System.out.println("所有人都跑完了");
        executorService.shutdown();
    

 

CyclicBarrier 循环利用

场景: 多人骑行车、多人坐船

eg:

比如去海边游玩,三人自行车、需要等待三人才能开始,下大巴车之后到海边有一段距离(需要步行,每个人的速度不一样),所以就出现了必须要三个人之后才能启动自行车

public class CyclicBarrierDemo01 

    // 参数构建 还可以添加其他的
   // 方式1// private static CyclicBarrier cyclicBarrier = new CyclicBarrier(4);
   // 方式2 循环一次(在开闸的时候) 打印一次
    private static CyclicBarrier cyclicBarrier =  new CyclicBarrier(4,()->
        System.out.println("凑够人数了。 出发!");
    );

    public static void main(String[] args) 
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 16; i++) 
            int finalInt = i ;
            System.out.println("第" + finalInt +" 前往,等待启动");
            executorService.submit(()->
                try 
                    Thread.sleep((long) (Math.random()*1000));
                 catch (InterruptedException e) 
                    e.printStackTrace();
                
                System.out.println("第" + finalInt +" 到达驿站,等待启动");
                try 
                    cyclicBarrier.await(10, TimeUnit.SECONDS);// 当不足时,超过时间区间。则会抛出异常
                    System.out.println("第" + finalInt +" 开始骑车");
                 catch (InterruptedException e) 
                    e.printStackTrace();
                 catch (BrokenBarrierException e) 
                    e.printStackTrace();
                 catch (TimeoutException e) 
                    e.printStackTrace();
                
            );
        
        executorService.shutdown();
    

总结

# Semaphore 信号量
1、控制用户请求的数量。比如限制2个线程进入,其余的线程则需要等待,直到某个线程完成才会重新进入新的线程工作
# CountDownLatch 
用法1:
  主线程等待-多个子线程执行完成之后一起执行
   eg: 比如去查询外部接口API,多个不同类型的API都需要请求, 
   **1.api1 2.api2 3.api3**
   一般做法: 一次调用api1、api2、api3
   同时调用 :多线程调用api1、api2、api3
   最后主线程等待即可
   
用法2:
  多个线程等待某一个线程信号,同时开始执行
    eg: 同时5个线程同时争夺某个资源
    一般在测试类中使用

# CyclicBarrier 循环使用场景
场景:
  比如 划船,必须4个人一组,否则不允许开船,并且可以循环执行

代码连接地址 demo链接

 

以上是关于CountDownLatchCyclicBarrierSemaphore多线程协助操作API的主要内容,如果未能解决你的问题,请参考以下文章