美文网首页
CyclicBarrier 的作用、应用场景和实战

CyclicBarrier 的作用、应用场景和实战

作者: wuchao226 | 来源:发表于2021-04-13 14:18 被阅读0次

    CountDownLatch 的作用、应用场景和实战
    Semaphore 的作用、应用场景和实战

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

    过程如下图所示:

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

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

    CyclicBarrier 使用场景

    CyclicBarrier 可以用于多线程计算数据,最后合并计算结果的场景。

    示例代码:

    package cn.enjoyedu.ch2.tools;
    
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.CyclicBarrier;
    
    /**
     * 类说明:演示CyclicBarrier用法,共4个子线程,他们全部完成工作后,交出自己结果,
     * 再被统一释放去做自己的事情,而交出的结果被另外的线程拿来拼接字符串
     */
    public class UseCyclicBarrier {
        /*创建一个CyclicBarrier实例,屏障数据设为3,处理完之后执行CollectThread类的run方法*/
        private static CyclicBarrier barrier
                = new CyclicBarrier(4, new CollectThread());
    
        /*创建一个ConcurrentHashMap,用来保存每个线程的id*/
        private static ConcurrentHashMap<String, Long> resultMap
                = new ConcurrentHashMap<>();
    
        public static void main(String[] args) {
            for (int i = 0; i < 4; i++) {
                Thread thread = new Thread(new SubThread());
                thread.start();
            }
    
        }
    
        /*汇总的任务*/
        private static class CollectThread implements Runnable {
            /*等到所有的线程到达屏障*/
            @Override
            public void run() {
                StringBuilder result = new StringBuilder();
                for (Map.Entry<String, Long> workResult : resultMap.entrySet()) {
                    result.append("[" + workResult.getValue() + "]");
                }
                System.out.println(" the result = " + result);
                System.out.println("do other business........");
            }
        }
    
        /*相互等待的子线程*/
        private static class SubThread implements Runnable {
    
            @Override
            public void run() {
                long id = Thread.currentThread().getId();
                resultMap.put(Thread.currentThread().getId() + "", id);
                try {
                    Thread.sleep(1000 + id);
                    System.out.println("Thread_" + id + " ....do something ");
                    /*线程完成工作后调用await 设置屏障*/
                    barrier.await();
    //                Thread.sleep(1000 + id);
    //                System.out.println("Thread_" + id + " ....do its business ");
    //                barrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    打印结果:

    Thread_13 ....do something 
    Thread_11 ....do something 
    Thread_12 ....do something 
    Thread_14 ....do something 
     the result = [11][12][13][14]
    do other business........
    

    放开 SubThread 线程中以下代码注释:

    Thread.sleep(1000 + id);
    System.out.println("Thread_" + id + " ....do its business ");
    barrier.await();
    

    打印结果:

    Thread_11 ....do something 
    Thread_14 ....do something 
    Thread_13 ....do something 
    Thread_12 ....do something 
     the result = [11][12][13][14]
    do other business........
    Thread_12 ....do its business 
    Thread_13 ....do its business 
    Thread_14 ....do its business 
    Thread_11 ....do its business 
     the result = [11][12][13][14]
    do other business........
    

    从以上打印结果中可以看出 CyclicBarrier 的计数器可以反复使用。

    使用 CyclicBarrier 时要注意的问题

    在线程池中使用 CyclicBarrier 时一定要注意线程的数量要多于 CyclicBarrier 实例中设置的阻塞线程的数量就会发生死锁。 调用 await() 方法的次数一定要等于屏障中设置的阻塞线程的数量,否则也会死锁。

    CyclicBarrier 和 CountDownLatch 的区别

    • 二者都能让一个或多个线程阻塞等待,都可以用在多个线程间的协调,起到线程同步的作用。
    • CountDownLatch 的计数器只能使用一次,而 CyclicBarrier 的计数器可以反复 使用。
    • CountDownLatch.await 一般阻塞工作线程,所有的进行预备工作的线程执行 countDown,而 CyclicBarrier 通过工作线程调用 await 从而自行阻塞,直到所有工作线程达到指定屏障,所有的线程才会返回各自执行自己的工作。
    • 在控制多个线程同时运行上,CountDownLatch 可以不限线程数量,而 CyclicBarrier 是固定线程数。
    • CyclicBarrier 还可以提供一个 barrierAction,合并多线程计算结果。

    相关文章

      网友评论

          本文标题:CyclicBarrier 的作用、应用场景和实战

          本文链接:https://www.haomeiwen.com/subject/tdvqlltx.html