当前位置: 首页 > 编程笔记 >

详解Java多线程编程中CountDownLatch阻塞线程的方法

冉弘化
2023-03-14
本文向大家介绍详解Java多线程编程中CountDownLatch阻塞线程的方法,包括了详解Java多线程编程中CountDownLatch阻塞线程的方法的使用技巧和注意事项,需要的朋友参考一下

直译过来就是倒计数(CountDown)门闩(Latch)。倒计数不用说,门闩的意思顾名思义就是阻止前进。在这里就是指 CountDownLatch.await() 方法在倒计数为0之前会阻塞当前线程。
CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
CountDownLatch 的作用和 Thread.join() 方法类似,可用于一组线程和另外一组线程的协作。例如,主线程在做一项工作之前需要一系列的准备工作,只有这些准备工作都完成,主线程才能继续它的工作。这些准备工作彼此独立,所以可以并发执行以提高速度。在这个场景下就可以使用 CountDownLatch 协调线程之间的调度了。在直接创建线程的年代(Java 5.0 之前),我们可以使用 Thread.join()。在 JUC 出现后,因为线程池中的线程不能直接被引用,所以就必须使用 CountDownLatch 了。
CountDownLatch类是一个同步计数器,构造时传入int参数,该参数就是计数器的初始值,每调用一次countDown()方法,计数器减1,计数器大于0 时,await()方法会阻塞程序继续执行。 CountDownLatch可以看作是一个倒计数的锁存器,当计数减至0时触发特定的事件。利用这种特性,可以让主线程等待子线程的结束。 下面以一个模拟运动员比赛的例子加以说明。
CountDownLatch的一个非常典型的应用场景是:有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行。假如我们这个想要继续往下执行的任务调用一个CountDownLatch对象的await()方法,其他的任务执行完自己的任务后调用同一个CountDownLatch对象上的countDown()方法,这个调用await()方法的任务将一直阻塞等待,直到这个CountDownLatch对象的计数值减到0为止。

CountDownLatch函数列表

CountDownLatch(int count)
构造一个用给定计数初始化的 CountDownLatch。
// 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。
void await()
// 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。
boolean await(long timeout, TimeUnit unit)
// 递减锁存器的计数,如果计数到达零,则释放所有等待的线程。
void countDown()
// 返回当前计数。
long getCount()
// 返回标识此锁存器及其状态的字符串。
String toString()

CountDownLatch数据结构
CountDownLatch的UML类图如下:

CountDownLatch的数据结构很简单,它是通过"共享锁"实现的。它包含了sync对象,sync是Sync类型。Sync是实例类,它继承于AQS。


CountDownLatch的使用示例
下面通过CountDownLatch实现:"主线程"等待"5个子线程"全部都完成"指定的工作(休眠1000ms)"之后,再继续运行。

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;

public class CountDownLatchTest1 {

 private static int LATCH_SIZE = 5;
 private static CountDownLatch doneSignal;
 public static void main(String[] args) {

  try {
   doneSignal = new CountDownLatch(LATCH_SIZE);

   // 新建5个任务
   for(int i=0; i<LATCH_SIZE; i++)
    new InnerThread().start();

   System.out.println("main await begin.");
   // "主线程"等待线程池中5个任务的完成
   doneSignal.await();

   System.out.println("main await finished.");
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
 }

 static class InnerThread extends Thread{
  public void run() {
   try {
    Thread.sleep(1000);
    System.out.println(Thread.currentThread().getName() + " sleep 1000ms.");
    // 将CountDownLatch的数值减1
    doneSignal.countDown();
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
 }
}

运行结果:

main await begin.
Thread-0 sleep 1000ms.
Thread-2 sleep 1000ms.
Thread-1 sleep 1000ms.
Thread-4 sleep 1000ms.
Thread-3 sleep 1000ms.
main await finished.

结果说明:主线程通过doneSignal.await()等待其它线程将doneSignal递减至0。其它的5个InnerThread线程,每一个都通过doneSignal.countDown()将doneSignal的值减1;当doneSignal为0时,main被唤醒后继续执行。

PS:CountDownLatch和CyclicBarrier的区别:
(1) CountDownLatch的作用是允许1或N个线程等待其他线程完成执行;而CyclicBarrier则是允许N个线程相互等待。
(2) CountDownLatch的计数器无法被重置;CyclicBarrier的计数器可以被重置后使用,因此它被称为是循环的barrier。

 类似资料:
  • 我有4-5个工作线程处理大型消息队列。我还有另一段代码,它使用2-3个worker运行。我想在处理大型消息队列时阻止所有其他工作者。 我正在使用JDK6和Jms 编辑: 队列进程工作者从未终止。当没有消息时,它们阻塞队列。这些工作者由执行器线程池管理,如果我使用读写锁,其中一个工作者也会被阻塞。此外,如果使用循环屏障,那么我必须终止线程,以便重新传递阻塞的第二个进程。由于工作者是由线程池管理的,所

  • 摘要 本文描述了使用 QEMU 运行 RT-Thread 提供的基于多线程的非阻塞 socket 编程示例。 简介 随着物联网的发展,越来越多产品需要基于网络进行数据传输。在实际开发中,往往要求网络传输时不能阻塞当前线程,以致无法及时处理其他消息。在用户无法直接套用简单的 socket demo 时,RT-Thread 提供基于多线程的非阻塞 socket 编程示例,方便用户进行应用程序开发。 在

  • 本文向大家介绍详解Java线程同步器CountDownLatch,包括了详解Java线程同步器CountDownLatch的使用技巧和注意事项,需要的朋友参考一下   Java程序有的时候在主线程中会创建多个线程去执行任务,然后在主线程执行完毕之前,把所有线程的任务进行汇总,以前可以用线程的join方法,但是这个方法不够灵活,我们可以使用CountDownLatch类,实现更优雅,而且使用线程池的

  • 本文向大家介绍Java countDownLatch如何实现多线程任务阻塞等待,包括了Java countDownLatch如何实现多线程任务阻塞等待的使用技巧和注意事项,需要的朋友参考一下 我这里需要通过多线程去处理数据,然后在所有数据都处理完成后再往下执行。这里就用到了CountDownLatch。把countdownlatch作为参数传入到每个线程类里,在线程中处理完数据后执行countdo

  • 本文向大家介绍详解Python中的多线程编程,包括了详解Python中的多线程编程的使用技巧和注意事项,需要的朋友参考一下 一、简介        多线程编程技术可以实现代码并行性,优化处理能力,同时功能的更小划分可以使代码的可重用性更好。Python中threading和Queue模块可以用来实现多线程编程。 二、详解 1、线程和进程        进程(有时被称为重量级进程)是程序的一次执行。

  • 我正在尝试用Python编写一个程序。我想写的是一个脚本,它会立即向用户返回一条友好的消息,但会在后台生成一个长的子进程,它会处理几个不同的文件,并将它们写入一个祖父文件。我已经做了一些关于线程和处理的教程,但我遇到的是,无论我尝试什么,程序都会一直等待,直到子进程完成,然后才会向用户显示前面提到的友好消息。以下是我尝试过的: 线程示例: 我读过这些关于多线程的SO帖子如何在Python中使用线程