• CountDownLatch的理解使用


    一、介绍

    CountDownLatch是jdk1.5中引入的一种同步辅助,允许一个或者多个线程等待,知道在其他线程中执行的一组操作完成。

    CountDownLatch使用给定的计数器进行初始化,由于调用了countDown方法,await方法会阻塞,知道当前计数器达到为零,然后释放所有等待线程,并且任何后续的await方法都会立即返回,由于在初始化时指定了计数数量,所以无法重置技术,如果需要重置计数,需要使用CyclicBarrier.

    计数为1的CountDownLatch可用于简单的锁,调用await的所有线程在等待,直到它被调用countDown的线程打开,初始化为N的线程可用于使一个主线程等待,直到N个线程完成操作执行完成,或者某个操作已完成N次。使用场景最多的可能是主线程等待所有子线程是否执行完毕。

    简单来说,CountDownLatch类是一个基于AbstractQueuedSynchronizer(AQS)实现的计数器,可以设置初始化线程数(设置完后不可改变),在子线程结束时调用countDown()方法可以使计数数量减1,当所有线程结束,即最终getCount()为0时,会调用CountDownLatch的成员方法wait()的线程就会取消BLOCKED阻塞状态,进去RUNNABLE从而继续执行。

    二、使用

    下面来看源码里举的例子,我理解的是四个搬运工装车

    import java.util.concurrent.CountDownLatch;

    /**
    * 司机
    * @author
    */
    public class Driver {

    public static void main(String[] args) throws InterruptedException {
    int N = 4;

    // 开始装车信号
    CountDownLatch startSignal = new CountDownLatch(1);

    // 装车完毕信号
    CountDownLatch doneSignal = new CountDownLatch(N);

    // 初始化四个搬运工
    for (int i = 0; i < N; ++i) {
    new Thread(new WorkerRunnable(startSignal, doneSignal), "Worker-" + i).start();
    }

    // 司机做准备工作,比如把车开到指定地方
    doSomethingElse();

    // 准备完了,发信号让开始搬运
    startSignal.countDown();

    // 司机等待所有搬运工完成
    doneSignal.await();

    // 完成
    doSomethingElse2();
    }

    static void doSomethingElse() throws InterruptedException {
    Thread.sleep(1000);
    System.out.println("司机准备工作完成");
    }

    static void doSomethingElse2() throws InterruptedException {
    Thread.sleep(1000);
    System.out.println("滴,滴滴~ 老司机发车了");
    }
    }
    import java.util.Random;
    import java.util.concurrent.CountDownLatch;
    
    /**
     * 搬运工
     * @author 15641
     */
    public class WorkerRunnable implements Runnable{
    
        private final CountDownLatch startSignal;
    
        private final CountDownLatch doneSignal;
    
        public WorkerRunnable(CountDownLatch startSignal, CountDownLatch doneSignal) {
            this.startSignal = startSignal;
            this.doneSignal = doneSignal;
        }
    
        @Override
        public void run() {
            try {
                // 搬运工等待准备工作完成
                startSignal.await();
    
                // 开始工作
                doWork();
    
                // 装完之后给司机发个信号
                doneSignal.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        void doWork() throws InterruptedException {
            // 模拟每个工人的装车速度
            Random random = new Random();
            Thread.sleep((long)(random.nextDouble() * 5000));
    
            System.out.println(Thread.currentThread().getName() + "装完了");
        }
    }

    执行结果为

    上述例子是多个主线程等待多个线程全部执行完,第二个例子是使用线程池用一个Runnable重复执行每一部分

    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /**
     * @author 15641
     */
    public class Driver2 {
    
        public static void main(String[] args) throws InterruptedException {
            int N = 4;
            CountDownLatch doneSignal = new CountDownLatch(N);
            ExecutorService service = Executors.newFixedThreadPool(N);
    
            for (int i = 0; i < N; ++i) {
                service.submit(new WorkerRunnable2(doneSignal, i));
            }
    
            doneSignal.await();
        }
    }
    import java.util.Random;
    import java.util.concurrent.CountDownLatch;
    
    /**
     * @author 15641
     */
    public class WorkerRunnable2 implements Runnable{
    
        private final CountDownLatch doneSingal;
    
        private final int i;
    
        public WorkerRunnable2(CountDownLatch doneSingal, int i) {
            this.doneSingal = doneSingal;
            this.i = i;
        }
    
        @Override
        public void run() {
            try {
                doWork(i);
                doneSingal.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
        }
    
        void doWork(int i) throws InterruptedException {
            // 模拟每个工人的装车速度
            Random random = new Random();
            Thread.sleep((long)(random.nextDouble() * 8000));
    
            System.out.println("任务" + i + "完成了");
        }
    }
  • 相关阅读:
    基于jquery后台框架设计(自适应高度,iframe简易版)
    发布mvc遇到的HTTP错误 403.14Forbidden解决办法
    编译器错误消息: CS0012: 类型 在未被引用的程序集中定义。必须添加对程序集 的引用
    jquery获取iframe里的js事件
    js获取浏览器相关尺寸
    CSS半透明兼容写法
    sharepoint 添加解决方案 遇到的问题
    WCF开发小结
    TDD(测试驱动开发/TestDriven Development)
    asp.net 2.0 读取 资源文件
  • 原文地址:https://www.cnblogs.com/LiuFqiang/p/15608390.html
Copyright © 2020-2023  润新知