应手动构造threadpoolexecutor而非executors快捷方法,因其可控制核心线程数、最大线程数、有界队列及拒绝策略;submit()返回future便于异常感知,execute()更轻量但异常不传播;shutdown()等待任务完成,shutdownnow()尝试中断并清空队列;必须显式shutdown,gc不会自动调用。
ExecutorService 不是拿来直接 new 的,它必须通过 Executors 工厂类或 ForkJoinPool 等具体实现类获得;盲目用 Executors.newFixedThreadPool() 在高并发场景下容易 OOM,这是最常踩的坑。
怎么选合适的线程池创建方式
Java 8+ 推荐优先使用 ThreadPoolExecutor 手动构造,而不是 Executors 的快捷方法。因为后者隐藏了关键参数,比如:
-
newFixedThreadPool(n)底层用的是无界LinkedBlockingQueue,任务持续提交会无限堆积,吃光堆内存 -
newCachedThreadPool()允许创建无限线程(60 秒空闲后回收),突发流量下可能创建成千上万个线程,触发OutOfMemoryError: unable to create native thread -
newSingleThreadExecutor()同样用无界队列,且单点故障风险高
正确做法是明确指定核心线程数、最大线程数、队列容量和拒绝策略:
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, // corePoolSize
4, // maxPoolSize
60L, // keepAliveTime
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(100), // 有界队列
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝时由调用线程执行
);
submit() 和 execute() 到底该用哪个
区别不在“能不能扔任务”,而在于返回值和异常处理机制:
立即学习“Java免费学习笔记(深入)”;