关于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

时间: 2024-10-09 11:00:43

关于CountDownLatch控制线程的执行顺序的相关文章

如何控制线程的执行顺序

错误示例: 1 public class Test { 2 public static void main(String[] args){ 3 thread1.start(); 4 thread2.start(); 5 thread3.start(); 6 } 7 8 static Thread thread1 = new Thread(new Runnable() { 9 @Override 10 public void run() { 11 System.out.println("threa

线程的执行顺序

线程的执行完全是自发的去抢CPU时间片,谁先抢到谁就先去执行package com.pers.xiancheng; public class Test implements Runnable { int count;//默认是0 static Object obj = new Object(); @Override public void run() { //synchronized块锁定的是整个对象 synchronized (obj) {//synchronized 是用来获得对象锁,只有获

采用闭锁(CountDownLatch)控制线程的先后顺序(一)

CountDownLatch俗称闭锁,可以初始化一个值,每执行一次countDown()操作,值减一,减为0时,在闭锁前等待的线程即可执行,但是闭锁的值不能恢复,即一次性.下面是api文档中的介绍: A CountDownLatch is initialized with a given count. The await methods block until the current count reaches zero due to invocations of the countDown()

采用闭锁(CountDownLatch)控制线程的先后顺序(二)

还是上一篇的应用场景,将小明与小强持有的闭锁,合二为一,优化后的代码如下: package com.smikevon.concurrent.tools; import java.util.concurrent.CountDownLatch; /** * @description: 要求:妈妈炒菜,但是这个时候还没买菜,也没有酱油了.为了更快的吃上饭,妈妈,小明,小强,分别行动, * 妈妈负责敲响做饭铃(铃响之前不许动),兄弟二人就可以出发,然后妈妈收拾厨房调好料,小明负责买菜,小强负责买酱油,协

如何保证线程的执行顺序

示例代码 static Thread t1 = new Thread(new Runnable() { public void run() { System.out.println("Thread1"); } }); static Thread t2 = new Thread(new Runnable() { public void run() { System.out.println("Thread2"); } }); static Thread t3 = new

如何控制多线程的执行顺序

问题描述: Thread thread1 = new Thread(new Runnable() { public void run() { for (int i = 0; i < 1000; i++) { System.out.println(Thread.currentThread().getName() + "...." + i); } } }); Thread thread2 = new Thread(new Runnable() { public void run()

Servlet 3.0 之@WebFilter怎么控制多个filter的执行顺序

之前我们控制多个filter的执行顺序是通过web.xml中控制filter的位置来控制的,放在上面的会比放在下面的先执行,如下“用户登录检查过滤器”会比“接口日志过滤器”先执行   <!-- 用户登录检测过滤器 -->    <filter> <filter-name>UserLoginFilter</filter-name>         <filter-class>net.tfgzs.demo.filter.UserLoginFilter

多线程总结三:控制线程

Java的线程支持提供了一些便捷的工具方法,通过这些便捷的工具方法可以很好的控制线程的执行. 1.join线程:join 当某个程序执行流中调用其他线程的join()方法时,执行中的线程会被阻塞,直到被join()方法加入的join线程执行完为止.join()方法将大问题划分为许多小问题,每个小问题分配一个线程,当所有的小问题都得到处理以后,再调用主线程来进一步操作. 1 /** 2 * @Title: JoinThread.java 3 * @Package 4 * @author 任伟 5

Java 控制线程

Java 的线程支持提供了一些便捷的工具方法,通过这些便捷的工具方法可以很好地控制线程的执行. join 线程 Thread 提供了让一个线程等待另一个线程完成的方法—— join() 方法.当在某个程序执行流中调用其他线程的join()方法时,调用线程将被阻塞,直到被 join() 方法加入的 join 线程执行完为止. join() 方法通常由使用线程的程序调用,以将大问题划分成许多小问题,每个小问题分配一个线程.当所有的小问题都得到处理后,再调用主线程来进一步操作. public clas