代码实现
import java.util.concurrent.*;
public class AsyncTasks {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(4);
// 任务A
Future<Integer> taskA = executorService.submit(() -> {
// 模拟任务A的执行
TimeUnit.SECONDS.sleep(1);
System.out.println("Task A completed");
return 10;
});
// 任务B依赖任务A的结果
Future<Integer> taskB = executorService.submit(() -> {
try {
int resultA = taskA.get();
// 模拟任务B的执行
TimeUnit.SECONDS.sleep(1);
System.out.println("Task B completed");
return resultA * 2;
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
return -1;
}
});
// 任务C依赖任务B的结果
Future<Integer> taskC = executorService.submit(() -> {
try {
int resultB = taskB.get();
// 模拟任务C的执行
TimeUnit.SECONDS.sleep(1);
System.out.println("Task C completed");
return resultB + 5;
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
return -1;
}
});
// 任务D与任务C并行执行
Future<Integer> taskD = executorService.submit(() -> {
// 模拟任务D的执行
TimeUnit.SECONDS.sleep(1);
System.out.println("Task D completed");
return 20;
});
// 任务E需要等待任务D和任务C都完成后才能执行
Future<Integer> taskE = executorService.submit(() -> {
try {
int resultC = taskC.get();
int resultD = taskD.get();
// 模拟任务E的执行
TimeUnit.SECONDS.sleep(1);
System.out.println("Task E completed");
return resultC + resultD;
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
return -1;
}
});
try {
System.out.println("Task E result: " + taskE.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
executorService.shutdown();
}
}
}
可能遇到的问题及解决方案
- 线程池资源耗尽:
- 问题:如果同时提交大量异步任务,可能导致线程池中的线程全部被占用,新任务无法立即执行,从而影响系统性能。
- 解决方案:合理设置线程池的大小,根据系统的硬件资源(如CPU核心数、内存等)和任务的特性(如I/O密集型还是CPU密集型)来调整线程池的核心线程数和最大线程数。例如,对于CPU密集型任务,线程池大小可以设置为CPU核心数;对于I/O密集型任务,可以适当增大线程池大小。
- 任务执行异常处理:
- 问题:在异步任务执行过程中,如果某个任务抛出异常,可能会导致后续依赖该任务结果的任务无法正确执行,且异常可能不会及时被发现。
- 解决方案:在每个任务中使用try - catch块捕获异常,并进行适当的处理,如记录日志、返回默认值等。在获取任务结果时,也需要处理
InterruptedException
和ExecutionException
,以便及时发现和处理任务执行过程中的异常。
- 死锁问题:
- 问题:如果任务之间的依赖关系设计不当,可能会出现死锁。例如,任务A等待任务B的结果,而任务B又等待任务A的结果。
- 解决方案:仔细设计任务之间的依赖关系,确保不存在循环依赖。在复杂的依赖场景下,可以使用有向无环图(DAG)来表示任务依赖关系,在提交任务前检查是否存在环,以避免死锁。
- 资源竞争:
- 问题:如果多个异步任务共享某些资源(如文件、数据库连接等),可能会出现资源竞争问题,导致数据不一致或程序出错。
- 解决方案:对共享资源的访问进行同步控制,可以使用
synchronized
关键字、Lock
接口等方式来保证同一时间只有一个任务可以访问共享资源。另外,也可以考虑使用线程安全的资源访问方式,如使用线程池提供的线程本地变量(ThreadLocal
)来避免资源竞争。