• 关于CountDownLatch控制线程的执行顺序


      在上一篇文章中说过使用thread.join()方法、newSingleThreadExecutor单线程池来控制线程执行顺序。在文章的末尾我提出了一种构想,可否使用经典的生产者和消费者模型来控制执行顺序。在本文中,我将使用CountDownLatch来解决这个问题。

            上图是countDownLatch的原理示意图。官方文档给出的解释是:CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程执行完后再执行。上图中线程A调用方法await()之后,进行阻塞,然后线程1执行任务完毕,数量减1,到最后线程2、3执行完毕,count=0。那么此时线程A等待了所有的线程执行完毕了任务。线程A状态复位,开始继续执行任务。

    实现过程如下:

    public class ThreadOrderTest {
    
        public static void main(String[] args) {
            /**
             * 创建线程类的时候,将上一个计数器和本线程计数器传入。运行前业务执行上一个计数器.await, 执行后本计数器.countDown。
             */
    
            CountDownLatch num0 = new CountDownLatch(0);// 在这里count为0,表示该线程立马复位执行
            CountDownLatch num1 = new CountDownLatch(1);// 在这里count为0,表示该线程立马复位执行
            CountDownLatch num2 = new CountDownLatch(1);// 在这里count为0,表示该线程立马复位执行
            Thread t1 = new Thread(new Count(num0, num1));
            Thread t2 = new Thread(new Count(num1, num2));
            Thread t3 = new Thread(new Count(num2, num2));
    
            t1.start();
            t2.start();
            t3.start();
    
        }
    
        static class Count implements Runnable {
    
            CountDownLatch num1;
            CountDownLatch num2;
    
            /**
             * 该构造器传递了上一个线程的计数器和当前线程的计数器
             * 
             * @param num0
             * @param num1
             */
            public Count(CountDownLatch num1, CountDownLatch num2) {
                super();
                this.num1 = num1;
                this.num2 = num2;
            }
    
            @Override
            public void run() {
                try {
                    // 等待线程1执行完毕线程2开始执行,因为线程1开始立马就会执行(count=0)
                    num1.await();
                    System.out.println("开始执行线程:" + Thread.currentThread().getName());
                    num2.countDown();// 本线程计数器减少
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
            }
    
        }
    
    }
     

            具体是怎么实现的呢:首先在创建线程的时候传递了Runnable对象,而该对象设置了两个参数,第一个参数保存了前一个线程的计数器,第二个线程保存了当前线程的计数器。线程1初始化的时候设置了线程的计数器为0,也就是说会立马执行任务,执行完毕,线程2 的计数器调用countdown()方法,立马从初始化的1变为0,同样开始执行,那么此时执行完毕,线程3计数器也减去1,开始执行任务。这样保证了三个线程的执行顺序。

     

            下面是执行的结果:

    开始执行线程:Thread-0
    开始执行线程:Thread-1
    开始执行线程:Thread-2

            要说明的是,CountDownLatch存在不足的地方在于,要创建该对象的时候,我们会传递计数器的初始值,但是这个值一经设置,就再也无法修改了,因此计数器的使用时一次性的。这就是java.util.CountDownLatch的不足之处了吧!

       
     
     
  • 相关阅读:
    C 标准库
    C 标准库
    C 标准库
    C 标准库
    Chrome内核保存为mhtml(单网页)
    C 标准库
    C 标准库
    【转】AOP
    [转]控制反转与依赖注入模式
    [转]乐观锁、悲观锁、死锁的区别
  • 原文地址:https://www.cnblogs.com/gosaint/p/9557662.html
Copyright © 2020-2023  润新知