当多个线程需求协调和同步履行使命时,Java 中的 CountDownLatch(倒计时门闩)是一个常用的工具类。它能够协助开发者完结线程之间的同步,确保某些线程在其他线程完结使命后再持续履行。本文将介绍 CountDownLatch 的基本原理、用法以及示例代码。

CountDownLatch 的基本原理

CountDownLatch 是根据计数器的原理完结的,它内部保护了一个整型的计数器。创立一个 CountDownLatch 目标时,需求指定一个初始计数值,该计数值表明需求等候的线程数量。每逢一个线程完结了其使命,它调用 CountDownLatch 的 countDown() 办法,计数器的值就会减一。当计数器的值变成 0 时,等候的线程就会被唤醒,持续履行它们的使命。

CountDownLatch 的用法

CountDownLatch 在多线程编程中有广泛的运用场景,例如主线程等候一切子线程完结使命后再持续履行,多个线程协同完结一个使命等。以下是 CountDownLatch 的基本用法:

  1. 创立 CountDownLatch 目标,并指定初始计数值。
CountDownLatch latch = new CountDownLatch(3); // 初始计数值为 3
  1. 创立需求等候的线程,线程完结使命后调用 countDown() 办法。
Runnable task = new Runnable() {
    @Override
    public void run() {
        // 线程使命逻辑
        // ...
        latch.countDown(); // 完结使命后调用 countDown()
    }
};
  1. 创立等候线程,等候计数器的值变成 0 后再持续履行。
try {
    latch.await(); // 等候计数器的值变成 0
    // 持续履行需求等候的线程后续逻辑
} catch (InterruptedException e) {
    // 处理中断异常
    e.printStackTrace();
}

CountDownLatch 示例

下面经过一个简略的示例代码来演示 CountDownLatch 的用法。假设有一个需求,需求三个工人协同完结一项使命,主线程需求等候三个工人完结使命后才干持续履行。示例代码如下:

import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
    public static void main(String[] args) {
        final int workerCount = 3;
        final CountDownLatch latch = new CountDownLatch(workerCount);
        // 创立并发动三个工人线程
        for (int i = 0; i < workerCount; i++) {
            Worker worker = new Worker(latch, "Worker " + (i + 1));
            new Thread(worker).start();
        }
        try {
            System.out.println("Main thread is waiting for workers to finish...");
            latch.await(); // 主线程等候三个工人线程完结使命
            System.out.println("All workers have finished, main thread continues...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    static class Worker implements Runnable {
        private final CountDownLatch latch;
        private final String name;
        public Worker(CountDownLatch latch, String name) {
            this.latch = latch;
            this.name = name;
        }
        @Override
        public void run() {
            System.out.println(name + " starts working...");
            // 模仿工作耗时
            try {
                Thread.sleep((long) (Math.random() * 10000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name + " finishes working.");
            latch.countDown(); // 工人完结使命后调用 countDown()
        }
    }
}

在上述代码中,首先创立了一个 CountDownLatch 目标,并指定初始计数值为 3。然后创立了三个工人线程并发动,每个工人线程模仿完结一项工作后调用 countDown() 办法,计数器的值减一。最后,主线程调用 await() 办法等候计数器的值变成 0,表明一切工人都完结使命后再持续履行。

运转该程序后,输出成果如下:

Worker 1 starts working...
Worker 2 starts working...  
Worker 3 starts working...  
Main thread is waiting for workers to finish...  
Worker 2 finishes working.  
Worker 1 finishes working.  
Worker 3 finishes working.  
All workers have finished, main thread continues...

能够看到,主线程在三个工人线程完结使命后才持续履行,而且一切工人线程的完结次序是不确定的,但主线程会一向等候直到一切工人完结使命。

扩展:上面的worker线程运转是没有次序的,咱们能够运用join()来使线程有序等候上一个线程运转完毕。

public static void main(String[] args) throws InterruptedException {
    final int workerCount = 3;
    final CountDownLatch latch = new CountDownLatch(workerCount);
    System.out.println("Main thread is waiting for workers to finish...");
    // 创立并发动三个工人线程
    for (int i = 0; i < workerCount; i++) {
        Worker worker = new Worker(latch, "Worker " + (i + 1));
        Thread t = new Thread(worker);
        t.start();
        t.join(); // 等候上一个线程履行完结
    }
    try {
        latch.await(); // 主线程等候三个工人线程完结使命
        System.out.println("All workers have finished, main thread continues...");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

输出成果:

Main thread is waiting for workers to finish...
Worker 1 starts working...
Worker 1 finishes working.
Worker 2 starts working...
Worker 2 finishes working.
Worker 3 starts working...
Worker 3 finishes working.
All workers have finished, main thread continues...

CountDownLatch 和 join 的效果和运用方式不同。CountDownLatch 用于等候多个线程完结使命后再持续履行,而 join 用于等候一个线程履行完毕后再持续履行。别的,CountDownLatch 是根据计数器的完结,能够灵敏地控制线程的数量和完结次序;而 join 办法只能等候单个线程履行完毕。

总结

CountDownLatch 是一个非常有用的线程同步工具,在多线程编程中有着广泛的运用。它根据计数器的原理完结,经过等候计数器的值变成 0 来完结线程的同步和协作。在运用 CountDownLatch 时,需求注意初始计数值的设定和 countDown() 和 await() 办法的运用。 本文介绍了 CountDownLatch 的基本原理和用法,并经过示例代码演示了它的运用。期望本文能够协助读者更好地理解和运用 CountDownLatch,在实际的项目中进步多线程编程的效率和质量。