面试题答案
一键面试可能出现的问题
- 死锁风险:如果在任务线程内部使用
join
等待其他线程完成,而这些线程又依赖当前任务线程的执行结果,就可能形成死锁。例如,线程A等待线程B,线程B等待线程A,这就会导致死锁。 - 线程池资源耗尽:若大量任务线程都使用
join
等待,可能使线程池中所有线程都处于等待状态,导致新任务无法执行,线程池资源耗尽。
合理利用join方法实现任务调度与同步需求
- 分析:为了避免死锁和资源耗尽问题,可以通过控制任务的依赖关系,确保不会出现循环等待。同时,要注意任务提交到线程池的顺序以及使用
join
的时机。 - 示例代码:
import java.util.concurrent.*;
public class ThreadPoolJoinExample {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
Future<Integer> future1 = executorService.submit(() -> {
System.out.println("Task 1 is running");
return 10;
});
Future<Integer> future2 = executorService.submit(() -> {
try {
int result1 = future1.get();
System.out.println("Task 2 depends on Task 1 result: " + result1);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
System.out.println("Task 2 is running");
return 20;
});
Future<Integer> future3 = executorService.submit(() -> {
try {
int result2 = future2.get();
System.out.println("Task 3 depends on Task 2 result: " + result2);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
System.out.println("Task 3 is running");
return 30;
});
try {
int finalResult = future3.get();
System.out.println("Final result: " + finalResult);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
executorService.shutdown();
}
}
在这个示例中,通过 Future
来获取任务的执行结果,从而实现任务之间的依赖关系,避免了直接使用 join
可能带来的问题。Future
的 get
方法类似于 join
,会阻塞当前线程直到任务完成并获取结果。这样既实现了任务的调度与同步,又不会导致死锁和线程池资源耗尽的问题。