• CountDownLatch线程阻塞用法实例


    在编写多线程的工作中,有个常见的问题:主线程(main) 启动好几个子线程(task)来完成并发任务,主线程要等待所有的子线程完成之后才继续执行main的其它任务。

    默认主线程退出时其它子线程不会停,如果想让main退出时其它子线程终止,可以用subThread.setDaemon(true) 设置子线程为“守护线程”。

    如果要在主线程等待所有子线程完成后,还要执行其它操作(比如:结果合并).可以用join()方法来等待所有子线程完成后,才继续执行。如下:

    实例1:Join实现

    public class TestRunnable implements Runnable{
    
        /** 线程名 */
        private String threadName;
    
    
        public TestRunnable(String threadName) {
            this.threadName = threadName;
        }
    
    
        @Override
        public void run() {
            System.out.println( "[" + threadName + "] Running !" );
        }
    
        public static void main(String[] args) throws InterruptedException {
            List<Thread> lists = new ArrayList<Thread>();
            for(int i=0; i<5; i++){
                Thread thread = new Thread(new TestRunnable("子线程" + (i + 100)));
                lists.add(thread);
                thread.start();
            }
            System.out.println("主线程阻塞,等待所有子线程执行完成");
            for(Thread thread : lists){
                // 如果注释掉thread.join(),启动后 main线程 与 所有子线程 thread并发工作,并不会等待子线程完成后再执行
                thread.join();
            }
            System.out.println("所有线程执行完成!");
        }
    }

    此外可以用java.util.concurrent.CountDownLatch更简洁的实现这种场景.

    CountDownLatch 的作用和 Thread.join() 方法类似,可用于一组线程和另外一组线程的协作。

    例如:主线程在做一项工作之前需要一系列的准备工作,只有这些准备工作都完成,主线程才能继续它的工作,这些准备工作彼此独立,所以可以并发执行以提高速度。在这个场景下就可以使用 CountDownLatch 协调线程之间的调度了。

    在直接创建线程的年代(Java 5.0 之前),我们可以使用 Thread.join().在 JUC 出现后,因为线程池中的线程不能直接被引用,所以就必须使用 CountDownLatch 了。

    CountDownLatch 是能使一组线程等另一组线程都跑完了再继续跑 ,CountDownLatch.await() 方法在倒计数为0之前会阻塞当前线程.

    实例2:CountDownLatch实现

    public class TestRunnable implements Runnable{
    
        /** 处理main线程阻塞(等待所有子线程) */
        private CountDownLatch countDown;
    
        /** 线程名字 */
        private String  threadName;
    
    
        public TestRunnable(CountDownLatch countDownLatch, String threadName) {
            this.countDown = countDownLatch;
            this.threadName = threadName;
        }
    
        @Override
        public void run() {
            System.out.println( "[" + threadName + "] Running ! [countDownLatch.getCount() = " + countDown.getCount() + "]." );
            // 每个独立子线程执行完后,countDownLatch值减1
            countDown.countDown();
        }
    
        public static void main(String [] args) throws InterruptedException {
            int countNum = 5;
            CountDownLatch countDownLatch = new CountDownLatch(countNum);
            for(int i=0; i<countNum; i++){
                new Thread(new TestRunnable(countDownLatch,"子线程" + (i+100))).start();
            }
            System.out.println("主线程阻塞,等待所有子线程执行完成");
            //endLatch.await()使得主线程(main)阻塞直到endLatch.countDown()为零才继续执行
            countDownLatch.await();
            System.out.println("所有线程执行完成!");
        }
    }

    执行结果:

    对于countDownLatch我们需要注意:CountDownLatch.await() 方法在倒计数为0之前会阻塞当前线程.
    a)在不适用await()的时候:

    执行结果如下:

    此时我们看到,主线程和子线程并发执行,主线程执行完后子线程还在执行,没有实现我们需要的场景.

    b)CountDownLatch.await() 方法在倒计数不为0时

    执行结果:

    如图,可以看到,子线程执行完成了,但是countDownLatch的倒记数的值不为0,进入持续等待中,并没有唤醒主线程来执行.所以countDownLatch.await()生效必须保证计数值变为0.

    转载请注明出处:[http://www.cnblogs.com/dennisit/p/4340611.html]

  • 相关阅读:
    解析CIDR表示的IP段表示的范围
    [Python] 使用乘号复制变量引起的问题
    [Python] 字典dict添加二级键值的问题
    [Java] [刷题] 连续自然数和
    [Java] [刷题] 多个整数连接为最大整数问题
    [CentOS] 编译安装Python3后pip3安装的库如何在命令行调用
    [CentOS] 宝塔面板与Python3的恩怨情仇
    [易语言] 两种字节序的直观比较
    [Java] [刷题] Excel地址转换
    [Java] 运算精度
  • 原文地址:https://www.cnblogs.com/dennisit/p/4340611.html
Copyright © 2020-2023  润新知