zoukankan      html  css  js  c++  java
  • CountDownLatch和CylicBarrier以及Semaphare你使用过吗

    CountDownLatch

    是什么

    CountDownLatch的字面意思:倒计时 门栓
    它的功能是:让一些线程阻塞直到另一些线程完成一系列操作后才唤醒。
    它通过调用await方法让线程进入阻塞状态等待倒计时0时唤醒。
    它通过线程调用countDown方法让倒计时中的计数器减去1,当计数器为0时,会唤醒哪些因为调用了await而阻塞的线程。

    • 底层是使用AQS实现的

    案例

    假设老板开一个紧急会议,他先到会议室等着所有人签到然后开始开会,可以使用CountDownLatch进行模拟。

     public static void main(String[] args) {
            CountDownLatch countDownLatch=new CountDownLatch(5);
    
            for (int i=1;i<=5;i++){
                new Thread(()->{
                    System.out.println(Thread.currentThread().getName()+"签到!");
                    countDownLatch.countDown();
                },"第"+i+"個人").start();
            }
    
    
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("老板宣布人夠了开始开会!");
        }
    

    运行结果:

    //注意这里的签到顺序可以随意
    第1個人签到!
    第2個人签到!
    第3個人签到!
    第4個人签到!
    第5個人签到!
    老板宣布人夠了开始开会!
    

    CyclicBarrier

    是什么

    CyclicBarrier [ˈsaɪklɪk] [ˈbæriər] 的字面意思:可循环使用的屏障 【栅栏】
    它的功能是:让一组线程到达一个屏障时被阻塞,知道最后一个线程到达屏障,所有被屏障拦截的线程才会继续执行。
    它通过调用await方法让线程进入屏障,

    • 底层是通过ReentrantLock以及Condition中的await和signal实现
     /** The lock for guarding barrier entry */
        private final ReentrantLock lock = new ReentrantLock();
        /** Condition to wait on until tripped */
        private final Condition trip = lock.newCondition();
    

    图例

    例子

    还是上面的开会的例子,我们使用CyclicBarrier实现。

    public static void main(String[] args) {
            CyclicBarrier cyclicBarrier=new CyclicBarrier(5,()->{
                System.out.println("老板宣布人夠了开始开会!!");
            });
    
            for (int i=1;i<=5;i++){
                new Thread(()->{
                    try {
                        System.out.println(Thread.currentThread().getName()+"签到!");
                        cyclicBarrier.await(); //如果等待的线程数未到,这里将一直等待
                        //等线程数够了下面语句将继续执行......
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                },"第"+i+"個人").start();
            }
        }
    

    运行结果:

    第1個人签到!
    第2個人签到!
    第3個人签到!
    第4個人签到!
    第5個人签到!
    老板宣布人夠了开始开会!!
    

    Semaphor

    是什么

    Semaphor [ˈseməfɔːr] 信号量的意思;
    它主要用于两个目的:

    • 用于多个共享资源互斥使用。【也就是具有锁的功能】
      一个停车场有多个停车位,这多个停车位对应汽车来说就是多个共享资源,Semaphor可以实现多个停车位和多个汽车之间的互斥。
    • 用于控制并发线程数。(就是控制同时得到共享资源的线程数量)
      在创建Semaphor时可以指定并发线程数,
        //permits :允许
        public Semaphore(int permits) {
            sync = new NonfairSync(permits);
        }
        //还可以指定是否为公平锁
        public Semaphore(int permits, boolean fair) {
            sync = fair ? new FairSync(permits) : new NonfairSync(permits);
        }
    
    • 信号量为1时 相当于独占锁 信号量大于1时相当于共享锁。

    例子

    我们测试使用Semaphor实现控制线程并发访问方法。

    /**
     * 测试使用Semaphor信号量控制方法的访问
     */
    public class TestSemaphor {
        Semaphore semaphore=new Semaphore(5);
        /**
         * 假设并发只能为5个
         */
        public void pay(){
            try {
                //在 semaphore.acquire() 和 semaphore.release()之间的代码,同一时刻只允许指定个数的线程进入!
                semaphore.acquire();
                System.out.println("这是支付的方法!");
                Thread.sleep(2000);
                semaphore.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
       public static void main(String[] args) {
            TestSemaphor ts=new TestSemaphor();
            for (int i=0;i<10;i++){
                new Thread(()->{
                    ts.pay();
                },"线程"+i).start();
            }
        }
    }
    

    运行效果:

    线程0这是支付的方法!
    线程3这是支付的方法!
    线程6这是支付的方法!
    线程5这是支付的方法!
    线程1这是支付的方法!
    
    //注意这里是执行的暂停点
    
    线程7这是支付的方法!
    线程8这是支付的方法!
    线程2这是支付的方法!
    线程4这是支付的方法!
    线程9这是支付的方法!
    

    注意结果:10个线程分了两批执行的,也就是说我们控制了访问pay方法的线程数量,每次并发只能是5个!

    CountDownlatch和CyclicBarrier以及Semaphor的区别是

    • CountDownLatch是做减法,CyclicBarrier是做加法,Semaphor的临界资源可以反复使用

    • CountDownLatch不能重置计数,CycliBarrier提供的reset()方法可以重置计数,不过只能等到第一个计数结束。Semaphor可以重复使用。

    • CountDownLatch和CycliBarrier不能控制并发线程的数量,Semaphor可以实现控制并发线程的数量。

    资源

    更好的介绍

  • 相关阅读:
    R语言初涉
    Android源码大全
    Centos关闭防火墙
    Java开发常用下载的网址
    linux下解压命令大全
    Android常见布局问题
    配置Nutch模拟浏览器以绕过反爬虫限制
    Nutch的发展历程
    用三层交换机当路由器——最复杂的网络拓扑结构
    Ant 简易教程
  • 原文地址:https://www.cnblogs.com/wangsen/p/11170709.html
Copyright © 2011-2022 走看看