详解Java线程同步器CountDownLatch
概述
CountDownLatch是Java的一个线程同步器,用途是让一些线程等待直到另一些线程完成一系列操作。它可以让我们控制一个线程在其他一些线程都完成后才开始执行,如保证某些共享变量在多个线程修改后再执行后续操作。
CountDownLatch是通过一个计数器来实现的,计数器初始值为指定的值,每当一个线程完成了指定的操作后,计数器的值就减1,当计数器值为0时,则所有在这个CountDownLatch上等待的线程开始执行。
示例
下面,我们来看两个示例,分别说明如何使用CountDownLatch。
示例一
假设我们有一个需求,要求计算40000个数字的和。为了提高效率,我们可以将这些数字分配给4个线程,并通过CountDownLatch来控制这4个线程全部计算完成后,再将计算结果求和。
我们的实现代码如下:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CountDownLatchDemo {
// 待计算的数字数组
private static int[] nums = new int[40000];
static {
for (int i = 0; i < 40000; i++) {
nums[i] = i + 1;
}
}
// 计算线程数量
private static final int THREAD_COUNT = 4;
// CountDownLatch对象
private static CountDownLatch threadLatch = new CountDownLatch(THREAD_COUNT);
// 每个线程要计算的数字数量
private static final int NUM_PER_THREAD = nums.length / THREAD_COUNT;
// 线程池
private static ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT);
// 等待计算线程全部完成的CountDownLatch对象
private static CountDownLatch mainLatch = new CountDownLatch(THREAD_COUNT);
// 计算结果
private static volatile int result = 0;
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
// 启动计算线程
for (int i = 0; i < THREAD_COUNT; i++) {
int startIndex = i * NUM_PER_THREAD;
int endIndex = (i == THREAD_COUNT - 1) ? nums.length : (i + 1) * NUM_PER_THREAD;
executorService.execute(new Calculator(startIndex, endIndex, threadLatch, mainLatch));
}
// 等待计算线程全部完成
mainLatch.await();
System.out.println("计算结果是:" + result);
System.out.println("耗时:" + (System.currentTimeMillis() - start) + "ms");
// 关闭线程池
executorService.shutdown();
}
/**
* 计算线程
*/
private static class Calculator implements Runnable {
private int startIndex;
private int endIndex;
private CountDownLatch threadLatch;
private CountDownLatch mainLatch;
public Calculator(int startIndex, int endIndex, CountDownLatch threadLatch, CountDownLatch mainLatch) {
this.startIndex = startIndex;
this.endIndex = endIndex;
this.threadLatch = threadLatch;
this.mainLatch = mainLatch;
}
@Override
public void run() {
// 计算本线程负责的数字的和
int sum = 0;
for (int i = startIndex; i < endIndex; i++) {
sum += nums[i];
}
// 将本线程计算的结果加入到总结果中
synchronized (CountDownLatchDemo.class) {
result += sum;
}
// 本线程计算完成后,将CountDownLatch的count减1
threadLatch.countDown();
try {
// 等待其他计算线程完成
threadLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 当所有计算线程都完成后,减少mainLatch的count
mainLatch.countDown();
}
}
}
代码的逻辑很清晰,主线程先启动计算线程,然后等待所有计算线程完成后,将计算结果求和并输出。
示例二
假设我们有一个需求,要求一个线程等待多个线程全部执行完成后再执行。我们可以使用CountDownLatch来实现这个需求。
我们的实现代码如下:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CountDownLatchDemo {
// CountDownLatch对象
private static CountDownLatch threadLatch = new CountDownLatch(3);
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
// 启动3个线程
ExecutorService executorService = Executors.newFixedThreadPool(3);
executorService.execute(new MyThread("线程1", threadLatch));
executorService.execute(new MyThread("线程2", threadLatch));
executorService.execute(new MyThread("线程3", threadLatch));
executorService.shutdown();
// 等待3个线程全部完成
threadLatch.await();
// 所有线程执行完成后输出
System.out.println("所有线程执行完成");
System.out.println("耗时:" + (System.currentTimeMillis() - start) + "ms");
}
/**
* 自定义线程
*/
private static class MyThread implements Runnable {
private String name;
private CountDownLatch threadLatch;
public MyThread(String name, CountDownLatch threadLatch) {
this.name = name;
this.threadLatch = threadLatch;
}
@Override
public void run() {
try {
// 模拟线程执行时间
Thread.sleep((long) (Math.random() * 1000));
System.out.println(name + " 执行完成");
} catch (InterruptedException e) {
e.printStackTrace();
}
// 线程执行完成后,将CountDownLatch的count减1
threadLatch.countDown();
}
}
}
代码的逻辑也很清晰,主线程先启动3个线程后,等待这3个线程全部完成后,输出一句话表示所有线程执行完成。
总结
以上就是CountDownLatch的详细讲解和应用示例,通过这些例子和说明,我们可以看出使用CountDownLatch可以方便地实现一些多线程协作的任务和需求,比如等待多个线程完成后再执行后续操作、分布式任务的执行等。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解Java线程同步器CountDownLatch - Python技术站