zoukankan      html  css  js  c++  java
  • Java并发编程-CountDownLatch&CyclicBarrier

    1、CountDownLatch和CyclicBarrier作用

      CountDownLatch和CyclicBarrier都位于java.util.concurrent包中,都具有计数功能,一般用于多线程间的协作。

      CountDownLatch是减法计数器,子线程中调用countDown()计数减1,主线程调用await()阻塞线程执行,直到计数为0才会让线程继续执行,CountDownLatch不可重复利用。

      CyclicBarrier是加法计数器,子线程调用await()计数加1,同时阻塞线程执行,直到兄弟线程都执行了await(),计数到达了设定值,CyclicBarrier可重复使用,计数到达指定值后重新开始。CyclicBarrier构造函数设定一个Runnable参数,通知计数已到达指定值。

    2、使用示例

    package com.zhi.test;
    
    import java.util.Random;
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.CyclicBarrier;
    
    import org.junit.Test;
    
    /**
     * CyclicBarrier和CountDownLatch使用样例
     * 
     * @author 张远志
     * @since 2020年5月4日18:01:00
     *
     */
    public class MyTest {
        @Test
        public void test() {
            int jobCount = 5;
            CountDownLatch latch = new CountDownLatch(jobCount);
            CyclicBarrier barrier = new CyclicBarrier(jobCount, new Runnable() {
                public void run() {
                    System.out.println("所有线程都到了");
                }
            });
            for (int i = 1; i <= jobCount; i++) {
                new Thread(new Job(latch, barrier, i)).start();
            }
            try {
                latch.await();
            } catch (Exception e) {
            }
            System.out.println("所有线程已执行完成!");
        }
    
        class Job implements Runnable {
            private CountDownLatch latch;
            private CyclicBarrier barrier;
            private final int id;
    
            public Job(CountDownLatch latch, CyclicBarrier barrier, int id) {
                this.latch = latch;
                this.barrier = barrier;
                this.id = id;
            }
    
            @Override
            public void run() {
                try {
                    Thread.sleep(new Random().nextInt(10) * 1000);
                    System.out.println("线程" + id + "到达栅栏1");
                    barrier.await();
                } catch (Exception e) {
                }
                try {
                    System.out.println("线程" + id + "到达栅栏2");
                    barrier.await();
                } catch (Exception e) {
                }
                System.out.println("任务" + id + "执行完成");
                latch.countDown();
            }
        }
    }

      执行结果:

    线程2到达栅栏1
    线程4到达栅栏1
    线程5到达栅栏1
    线程3到达栅栏1
    线程1到达栅栏1
    所有线程都到了
    线程1到达栅栏2
    线程2到达栅栏2
    线程5到达栅栏2
    线程4到达栅栏2
    线程3到达栅栏2
    所有线程都到了
    任务3执行完成
    任务1执行完成
    任务2执行完成
    任务4执行完成
    任务5执行完成
    所有线程已执行完成!

    3、如何保证计数的线程安全性

      CountDownLatch的countDown会进行加法计数,CyclicBarrier的await()会进行加法计数,查看源码我们会发现,这2个方法都没有使用synchronized关键字,那他们有时如何保证线程安全性的呢?

      查看CountDownLatch源码,我们看到CountDownLatch使用了Sync内部类(继承AbstractQueuedSynchronizer)做减法,通过Unsafe类比较并设置新值。

      查看CyclicBarrier源码,我们看到ReentrantLock锁。为啥它与CountDownLatch不一样呢,因为CyclicBarrier不仅要完成计数,还需要调用barrierCommand,并且要实现重复可用(将count值还原),其实ReentrantLock内部也使用Unsafe类进行了原子操作。

  • 相关阅读:
    [Functional Programming] liftA2 and converge
    [Javascript] Convert a forEach method to generator
    [React Native] Up & Running with React Native & TypeScript
    [React] Create a Query Parameter Modal Route with React Router
    [ES2019] Represent Collision-free String Constants as Symbols in JavaScript
    形形色色的软件生命周期模型(4)——MSF、实用型
    整型数组处理算法(九)给定任意一个正整数,求比这个数大且最小的“不重复数”(性能优化)[2014百度笔试题]
    Easyui获取数据库date数据的显示
    [置顶] 如何更改CSDN博客高亮代码皮肤的样式,使博客看起来更有范(推荐)
    try-catch-finally 引发的奇怪问题
  • 原文地址:https://www.cnblogs.com/zhi-leaf/p/10275334.html
Copyright © 2011-2022 走看看