面试题答案
一键面试应用场景
在许多实际应用中,我们可能需要等待一组任务全部完成后再执行下一步操作。例如,在数据分析场景中,可能有多个线程分别处理不同部分的数据,只有当所有这些线程的数据处理任务都完成后,才能进行数据汇总和结果分析。又比如在并行计算任务中,多个线程并行计算不同的子问题,全部计算完成后才能整合最终结果。
代码实现
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();
}
}
}
}
异常处理
InterruptedException
:在CountDownLatch
的await
方法处,可能会抛出InterruptedException
。这通常是由于当前线程在等待CountDownLatch
归零的过程中被中断。在上述代码中,我们捕获了这个异常并打印了堆栈信息。在实际应用中,可以根据具体需求进行更详细的处理,例如记录日志、设置标志位以通知其他部分程序线程被中断等。- 任务执行异常:任务内部可能会抛出各种异常,如
IOException
、RuntimeException
等。在上述代码的Task
类的run
方法中,我们只捕获了InterruptedException
。对于其他异常,可以根据具体业务逻辑进行处理。例如,在run
方法中添加try - catch
块捕获其他异常,记录异常信息,并且在捕获异常后仍然调用latch.countDown()
方法,以确保CountDownLatch
能够正常归零,避免其他线程无限期等待。如果希望在某个任务异常时中断整个任务组的执行,可以设置一个全局的标志位,在任务捕获异常时设置该标志位,在await
之后检查该标志位,如果标志位被设置则不继续执行后续操作。