您的位置:首页 >Java线程池如何使用ExecutorService管理
发布于2026-03-03 阅读(0)
扫一扫,手机访问
不能直接 new Thread().start() 是因为频繁创建销毁线程开销大且易失控,ExecutorService 通过线程复用、队列缓冲、拒绝策略和统一关闭实现任务与执行者解耦,避免 OOM 和系统崩溃。

频繁创建销毁线程开销大,且容易失控——比如 100 个请求就起 100 个线程,可能直接打爆系统内存或 CPU。ExecutorService 提供复用、排队、拒绝策略、生命周期控制等能力,本质是把「任务」和「执行者」解耦。
常见错误现象:OutOfMemoryError: unable to create new native thread,往往就是没走线程池、裸写 new Thread() 导致的。
LinkedBlockingQueue),而非立即失败RejectedExecutionHandler,比如丢弃、抛异常、交由调用线程执行shutdown() 和 awaitTermination() 能安全等待已有任务完成Executors 提供的静态方法看似方便,但多数有隐患。最典型的是 Executors.newFixedThreadPool(int) —— 它用的是无界队列 LinkedBlockingQueue,一旦任务提交速度持续大于处理速度,队列会无限增长,最终 OOM。
真正该用的,是显式构造 ThreadPoolExecutor,自己控制核心参数:
ThreadPoolExecutor executor = new ThreadPoolExecutor(
4, // corePoolSize
8, // maximumPoolSize
60L, // keepAliveTime
TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(100), // 有界队列,防 OOM
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝时由提交线程自己执行
);
corePoolSize:常驻线程数,即使空闲也不会被回收(除非设置 allowCoreThreadTimeOut(true))maximumPoolSize:仅当队列满且当前线程数 < 小于该值时,才新建线程ArrayBlockingQueue(有界)、SynchronousQueue(不存任务,直接移交,适合 cached 场景)AbortPolicy(抛 RejectedExecutionException)、CallerRunsPolicy(降级到调用方线程执行)更可控execute(Runnable) 是 void 方法,任务里抛出的异常会被吞掉(只打日志,调用方完全感知不到);而 submit(Runnable) 或 submit(Callable) 返回 Future,能主动检查异常或获取结果。
典型踩坑:用 execute() 提交含数据库操作的任务,SQL 异常静默丢失,业务逻辑“看似成功”实则失败。
submit() + future.get()(注意 get() 会阻塞)execute() 更轻量submit(Callable<T>)Future.get() 抛出的不是原始异常,而是包装在 ExecutionException 中,需调用 getCause() 获取根本原因shutdown() 只是停止接收新任务,已提交任务(包括队列里的)仍会继续执行;shutdownNow() 会尝试中断正在运行的线程,并清空队列返回未执行任务列表——但「中断」不等于「终止」,线程是否响应取决于它自身是否检查 Thread.interrupted()。
正确关闭流程必须带超时等待:
executor.shutdown();
try {
if (!executor.awaitTermination(30, TimeUnit.SECONDS)) {
executor.shutdownNow(); // 强制终止
if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
System.err.println("线程池未正常关闭");
}
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
awaitTermination() 是阻塞调用,必须在 shutdown() 后调用shutdownNow(),可能打断还在跑的关键任务Socket.setSoTimeout())才能响应中断线程池不是一次性的,尤其在 Web 应用中,应作为单例长期持有;反复创建销毁反而增加 GC 压力。真正复杂的地方在于:队列容量、拒绝策略、任务超时设计,这些都得贴着你的业务吞吐模型来调,而不是套个 newFixedThreadPool(10) 就完事。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
9