Java线程池详解与实践
Java从JDK 5开始提供了线程池支持,开发者可以通过API直接使用,无需关注底层实现细节。其中最核心的类是ThreadPoolExecutor,其构造函数如下:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
各参数含义如下:
- corePoolSize: 核心线程数,即使空闲也会保留
- maximumPoolSize: 最大线程数限制
- keepAliveTime: 非核心线程的存活时间
- unit: 存活时间单位
- workQueue: 任务等待队列
- handler: 拒绝策略处理器
当线程数达到上限且队列已满时,新任务会被拒绝。ThreadPoolExecutor提供了四种内置拒绝策略:
- CallerRunsPolicy: 由调用线程执行任务
- AbortPolicy: 抛出异常拒绝任务
- DiscardPolicy: 直接丢弃不报错
- DiscardOldestPolicy: 移除最旧任务后执行新任务
任务提交时的处理流程:
- 线程数少于核心数时,直接创建新线程
- 核心线程满但队列未满时,加入等待队列
- 队列满且线程数未达上限时,创建临时线程
- 线程数已达上限时,触发拒绝策略
以下示例演示了线程池的基本使用:
import java.util.concurrent.*;
class TaskWorker implements Runnable {
@Override
public void run() {
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + " 执行中...");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public class PoolDemo {
private static final int CORE_SIZE = 2;
private static final int MAX_SIZE = 4;
private static final long TIMEOUT = 3;
private static final int TASK_COUNT = 10;
public static void main(String[] args) {
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(2);
ThreadPoolExecutor executor = new ThreadPoolExecutor(
CORE_SIZE, MAX_SIZE, TIMEOUT, TimeUnit.SECONDS,
queue, new ThreadPoolExecutor.DiscardOldestPolicy());
for (int i = 0; i < TASK_COUNT; i++) {
try {
executor.execute(new TaskWorker());
} catch (Exception e) {
System.err.println("任务执行异常: " + e.getMessage());
}
}
executor.shutdown();
}
}
线程池相关类结构:
- Executor: 顶层执行接口
- ExecutorService: 标准线程池接口
- ScheduledExecutorService: 支持定时任务的线程池
- ThreadPoolExecutor: 基础实现类
- ScheduledThreadPoolExecutor: 定时任务实现
Executors工厂类提供了常用的线程池创建方法:
- newSingleThreadExecutor: 单线程串行执行
- newFixedThreadPool: 固定大小线程池
- newCachedThreadPool: 动态调节的缓存线程池
- newScheduledThreadPool: 支持定时任务的线程池
自定义线程池实现示例:
public class CustomThreadPool {
private ExecutorService service;
public void initialize(int size, int limit) {
service = new ThreadPoolExecutor(
size, size, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(),
new SemaphoreHandler(limit));
}
public boolean submit(Runnable task) {
try {
service.execute(task);
return true;
} catch (Exception e) {
System.err.println("任务提交失败: " + e.getMessage());
return false;
}
}
public void shutdown() {
service.shutdown();
try {
if (!service.awaitTermination(30, TimeUnit.SECONDS)) {
service.shutdownNow();
if (!service.awaitTermination(10, TimeUnit.SECONDS)) {
System.err.println("线程池关闭超时");
}
}
} catch (InterruptedException e) {
service.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
使用线程池的主要优势包括:
- 降低线程创建和销毁的开销
- 提高系统资源利用率
- 避免因线程过多导致的内存溢出
- 提供更好的系统响应性能
对于需要返回结果的异步任务,可以使用Callable接口:
public interface Callable<V> {
V call() throws Exception;
}
通过合理配置线程池参数,可以有效控制系统并发度,在保证性能的同时避免资源耗尽问题。