Java CountDownLatch –一个不错的同步助手

时间:2020-02-23 14:34:58  来源:igfitidea点击:

Java CountDownLatch类是Concurrency API的一部分。
它允许我们创建一个同步,其中一个线程等待直到倒数为0。
当我们希望一个线程在有限数量的其他线程上等待完成处理时,这很有用。

CountDownLatch如何工作?

  • 使用给定的计数创建CountDownLatch实例。

  • 当线程调用CountDownLatch await()方法时,它将等待直到计数为0。

  • 完成后,其他线程有责任调用CountDownLatch countDown()方法。
    每次调用countDown()方法都会使计数值减少1。

  • 当所有其他线程都调用countDown()方法时,计数变为0,并且由于await()而等待的线程将开始执行。

  • count的值无法重置,因此一旦CountDownLatch工作完成,我们将无法重用同一实例。
    进一步调用await()将不会导致线程阻塞。

Java CountDownLatch示例

让我们看一个多线程应用程序中CountDownLatch的简单示例。

package com.theitroad.concurrency;

import java.util.Random;
import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {

	public static void main(String[] args) {
		CountDownLatch latch = new CountDownLatch(3);
		Random random = new Random();

		WorkerThread wt1 = new WorkerThread(latch, random.nextInt(5000));
		WorkerThread wt2 = new WorkerThread(latch, random.nextInt(5000));
		WorkerThread wt3 = new WorkerThread(latch, random.nextInt(5000));

		new Thread(wt1, "WT-11").start();
		new Thread(wt2, "WT-22").start();
		new Thread(wt3, "WT-33").start();

		try {
			latch.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.out.println("Finishing the Main Method");
	}

}

class WorkerThread implements Runnable {

	private CountDownLatch latch;
	private int delay;

	public WorkerThread(CountDownLatch latch, int delay) {
		this.latch = latch;
		this.delay = delay;
	}

	@Override
	public void run() {
		String name = Thread.currentThread().getName();
		int delay = this.delay;

		System.out.println(name + " sleeping for " + delay + " milliseconds.");
		try {
			Thread.sleep(delay);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.latch.countDown();
		System.out.println(name + " finished");

	}

}
  • 我们有3个工作线程,我们希望我们的主线程等待,直到全部完成。
    因此,我们使用count 3初始化CountDownLatch。

  • 在辅助线程中,我们在CountDownLatch实例上调用countDown()方法。
    因此,当所有3个工作线程都完成处理后,计数将变为0,并且由于await()而等待的主线程将开始执行。

  • 主线程由于CountDownLatch await()调用而被阻塞。
    一旦计数变为0,它将开始执行。

  • 在CountDownLatch同步机制的帮助下,我们确保在完成主线程之前执行所有辅助线程。

上述程序的可能输出如下:

WT-33 sleeping for 2962 milliseconds.
WT-22 sleeping for 3874 milliseconds.
WT-11 sleeping for 1746 milliseconds.
WT-11 finished
WT-33 finished
WT-22 finished
Finishing the Main Method

CountDownLatch await()

有两种版本的await()方法。

  • await():无限期地等待计数变为0,除非线程被中断。

  • await(长超时,TimeUnit单位):使用给定的超时值等待计数变为0。
    如果发生超时,则该方法停止阻塞并返回false。

CountDownLatch与CyclicBarrier

  • CountDownLatch提供了一种机制来等待计数变为0,而CyclicBarrier提供了一种机制来创建每个线程await()调用都会到达的公共屏障"计数"。

  • CountDownLatch操作是不可逆的,一旦计数为0,对await()的任何进一步调用都不会阻塞线程。
    就像CyclicBarrier所提示的那样,它本质上是循环的,并且在释放等待线程之后,屏障会再次使用。

  • 当我们要等待一组特定的线程执行时,CountDownLatch很有用。
    当我们有多个线程并且仅在执行一定数量的线程时才等待时,CyclicBarrier很有用。