题目
如何使用Java线程池执行一个简单的异步任务?
信息
- 类型:问答
- 难度:⭐
考点
线程池创建,任务提交,Runnable接口
快速回答
使用Java线程池执行异步任务的步骤如下:
- 通过
Executors.newFixedThreadPool()创建固定大小的线程池 - 实现
Runnable接口定义异步任务逻辑 - 使用
execute()方法提交任务到线程池 - 调用
shutdown()关闭线程池(非强制)
原理说明
线程池通过复用线程减少创建/销毁开销,核心组件包括:
- 工作队列:存储待执行任务(
BlockingQueue) - 线程集合:真正执行任务的线程
- 线程工厂:定制线程创建
- 拒绝策略:处理超负荷任务
代码示例
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolDemo {
public static void main(String[] args) {
// 1. 创建固定大小为2的线程池
ExecutorService executor = Executors.newFixedThreadPool(2);
// 2. 定义Runnable任务
Runnable task = () -> {
System.out.println("任务执行线程: " + Thread.currentThread().getName());
try {
Thread.sleep(1000); // 模拟耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
};
// 3. 提交3个任务(线程池会复用线程)
for (int i = 0; i < 3; i++) {
executor.execute(task);
}
// 4. 优雅关闭线程池(不再接受新任务,等待已有任务完成)
executor.shutdown();
}
}最佳实践
- 选择合适线程数:CPU密集型任务建议
N_threads = N_cores,I/O密集型可适当增加 - 始终关闭线程池:避免资源泄漏,使用
shutdown()而非shutdownNow()(除非需要强制中断) - 优先使用Runnable:相比
Callable,Runnable更简单且无需返回值
常见错误
- 忘记关闭线程池:导致JVM无法退出
- 错误捕获异常:线程池内异常需在任务内部处理,否则会丢失
- 滥用
newCachedThreadPool:可能创建大量线程导致OOM,适合短生命周期任务
扩展知识
- 线程池参数:
corePoolSize(核心线程数)、maximumPoolSize(最大线程数)、keepAliveTime(空闲线程存活时间) - 任务队列类型:
LinkedBlockingQueue(无界队列)、SynchronousQueue(直接传递队列) - 拒绝策略:
AbortPolicy(默认抛异常)、CallerRunsPolicy(用调用者线程执行)