关于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的不足之处了吧!

   
 
 
原文地址:https://www.cnblogs.com/gosaint/p/9557662.html