MST
星途 面试题库

面试题:Java中CountDownLatch与线程池结合使用的场景及实现

假设你有一个线程池,需要使用CountDownLatch确保线程池中的多个任务完成后再进行后续操作,阐述具体的应用场景,并给出代码实现,同时说明如何处理可能出现的异常情况。
27.1万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

应用场景

在许多实际应用中,我们可能需要等待一组任务全部完成后再执行下一步操作。例如,在数据分析场景中,可能有多个线程分别处理不同部分的数据,只有当所有这些线程的数据处理任务都完成后,才能进行数据汇总和结果分析。又比如在并行计算任务中,多个线程并行计算不同的子问题,全部计算完成后才能整合最终结果。

代码实现

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolWithCountDownLatch {
    public static void main(String[] args) {
        int taskCount = 5;
        CountDownLatch latch = new CountDownLatch(taskCount);
        ExecutorService executorService = Executors.newFixedThreadPool(taskCount);

        for (int i = 0; i < taskCount; i++) {
            executorService.submit(new Task(latch, "Task " + i));
        }

        try {
            latch.await();
            System.out.println("All tasks are completed. Proceed with further operations.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            executorService.shutdown();
        }
    }

    static class Task implements Runnable {
        private final CountDownLatch latch;
        private final String taskName;

        Task(CountDownLatch latch, String taskName) {
            this.latch = latch;
            this.taskName = taskName;
        }

        @Override
        public void run() {
            try {
                System.out.println(taskName + " is starting.");
                // 模拟任务执行
                Thread.sleep(1000);
                System.out.println(taskName + " is completed.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                latch.countDown();
            }
        }
    }
}

异常处理

  1. InterruptedException:在CountDownLatchawait方法处,可能会抛出InterruptedException。这通常是由于当前线程在等待CountDownLatch归零的过程中被中断。在上述代码中,我们捕获了这个异常并打印了堆栈信息。在实际应用中,可以根据具体需求进行更详细的处理,例如记录日志、设置标志位以通知其他部分程序线程被中断等。
  2. 任务执行异常:任务内部可能会抛出各种异常,如IOExceptionRuntimeException等。在上述代码的Task类的run方法中,我们只捕获了InterruptedException。对于其他异常,可以根据具体业务逻辑进行处理。例如,在run方法中添加try - catch块捕获其他异常,记录异常信息,并且在捕获异常后仍然调用latch.countDown()方法,以确保CountDownLatch能够正常归零,避免其他线程无限期等待。如果希望在某个任务异常时中断整个任务组的执行,可以设置一个全局的标志位,在任务捕获异常时设置该标志位,在await之后检查该标志位,如果标志位被设置则不继续执行后续操作。