zoukankan      html  css  js  c++  java
  • 【Java并发编程四】关卡

    一、什么是关卡?

      关卡类似于闭锁,它们都能阻塞一组线程,直到某些事件发生。

      关卡和闭锁关键的不同在于,所有线程必须同时到达关卡点,才能继续处理。闭锁等待的是事件,关卡等待的是其他线程。

    二、CyclicBarrier

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

      当线程到达关卡点时,调用await方法,await会被阻塞,直到所有的线程都到达关卡点。如果所有的线程都到达了关卡点,关卡就会被突破,这样所有的线程都被释放,关卡会重置以备下一次使用。如果对await的方法调用超时,或者阻塞中的线程被中断,那么关卡就被认为是失败的,所有对await未完成的调用都通过BrokenBarrierException终止。

      CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。

      实例代码如下:

    public class CyclicBarrierTest
    {
        public static void main(String[] args) throws InterruptedException, BrokenBarrierException
        {
            CyclicBarrier cyclicBarrier=new CyclicBarrier(4);
            for(int i=0;i<3;i++)
            {
                new Writer(cyclicBarrier).start();
            }
            cyclicBarrier.await();
            System.out.println("所有数据均写完!");
        }
        static class Writer extends Thread
        {
            CyclicBarrier cyclicBarrier;
            public Writer(CyclicBarrier cyclicBarrier)
            {
                this.cyclicBarrier=cyclicBarrier;
            }
            @Override
            public void run()
            {
                try
                {
                    Thread.sleep(1000);
                    System.out.println("线程"+Thread.currentThread().getName()+"写入数据完毕,等待其他线程写入完毕");
                    cyclicBarrier.await();
                } catch (Exception e)
                {
                    // TODO 自动生成的 catch 块
                    e.printStackTrace();
                }
                
            }
        }
    }

      输出

      

      CyclicBarrier还提供一个更高级的构造函数CyclicBarrier(int parties, Runnable barrierAction),用于在线程到达屏障时,优先执行barrierAction,方便处理更复杂的业务场景。代码如下:

    public class CyclicBarrierTest2
    {
         final static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 
         public static void main(String[] args)
        {
             CyclicBarrier end = new CyclicBarrier(2,new MainTask());// 两个工人的协作
    
             Worker worker1 = new Worker("zhang san", 5000, end);
             Worker worker2 = new Worker("li si", 8000,end);
             
             worker1.start();
             worker2.start();
        }
         static class MainTask implements Runnable
         {   
                public void run() 
                {   
                        System.out.println("执行最后的任务");   
                }   
        }  
         static class Worker extends Thread
            {
                String workerName;
                int workTime;
               
                CyclicBarrier end;
                public Worker(String workerName, int workTime, CyclicBarrier end)
                {
                    this.workerName = workerName;
                    this.workTime = workTime;
                    this.end = end;
                }
                public void run()
                {
                    try
                    {
                        System.out.println("Worker " + workerName + " do work begin at "+ sdf.format(new Date()));
                        Thread.sleep(workTime);
                        System.out.println("Worker " + workerName + " do work complete at " + sdf.format(new Date()));
                    } 
                    catch (InterruptedException e)
                    {
                        // TODO 自动生成的 catch 块
                        e.printStackTrace();
                    }
                    finally
                    {
                        try
                        {
                            end.await();
                        } catch (InterruptedException | BrokenBarrierException e)
                        {
                            // TODO 自动生成的 catch 块
                            e.printStackTrace();
                        }
                    }
                }
            }
    }

      输出:

      

    三、CyclicBarrier和CountDownLatch的区别

    1. CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()方法重置,因此CyclicBarrier能够处理更为复杂的业务场景,比如如果计算发送错误,可以重置计数器,并让线程重新执行一次。
    2. CountDownLatch是减计数方式,计数==0时释放所有等待的线程;CyclicBarrier是加计数方式,计数达到构造方法中参数指定的值时释放所有等待的线程。
      CountDownLatch当计数到0时,计数无法被重置;CyclicBarrier计数达到指定值时,计数置为0重新开始。
      CountDownLatch每次调用countDown()方法计数减一,调用await()方法只进行阻塞,对计数没任何影响;CyclicBarrier只有一个await()方法,调用await()方法计数加1,若加1后的值不等于构造方法的值,则线程阻塞。
    3. CountDownLatch: 一个或者是一部分线程 ,等待另外一部线程都完成了,再继续执行 。
      CyclicBarrier: 所有线程互相等待完成。

    四、参考资料

      1、http://ifeve.com/concurrency-cyclicbarrier/

      2、Java并发编程实践

  • 相关阅读:
    1、jQuery基本认识
    Zabbix agent 启动报错:cannot set resource limit [13] Permission denied
    Zabbix agent启动报错:cannot create semaphore set
    Windows系统版本号对照表
    学习使用 vue mixin
    windows cmd 生成文件目录树
    合村并镇
    Adobe宣布今年12月31日正式终止支持Flash
    好春光
    npm package version
  • 原文地址:https://www.cnblogs.com/xujian2014/p/5363759.html
Copyright © 2011-2022 走看看