
一、为什么要用线程池在 Java 开发中频繁创建和销毁线程会带来显著的性能开销。线程池的核心优势有两点线程复用避免频繁创建/销毁线程提升响应速度资源管控限制线程数量防止资源耗尽并提供任务队列缓冲机制。此外ThreadPoolExecutor还提供任务数统计、拒绝策略、动态调整参数等高级能力。虽然Executors工厂类提供了newFixedThreadPool、newCachedThreadPool等快捷方法但实际生产环境更推荐直接使用ThreadPoolExecutor以便明确控制队列与线程数量。二、ThreadPoolExecutor 核心构造器public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueueRunnable workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)参数说明参数含义corePoolSize核心线程数即使空闲也不会被回收除非设置allowCoreThreadTimeOutmaximumPoolSize最大线程数keepAliveTime非核心线程空闲存活时间unit时间单位workQueue任务阻塞队列threadFactory线程创建工厂handler拒绝策略构造器校验逻辑源码if (corePoolSize 0 || maximumPoolSize 0 || maximumPoolSize corePoolSize || keepAliveTime 0) throw new IllegalArgumentException(); if (workQueue null || threadFactory null || handler null) throw new NullPointerException();三、线程池状态与生命周期线程池内部通过AtomicInteger ctl同时保存“运行状态”和“线程数量”高 3 位线程池状态低 29 位工作线程数五种状态状态含义RUNNING接受新任务处理队列任务SHUTDOWN不接受新任务继续处理队列任务STOP不接受新任务不处理队列任务中断正在执行的任务TIDYING所有任务已终止线程数为 0准备执行terminated()TERMINATEDterminated()执行完成状态转换四、任务执行流程关键当调用execute(task)时线程池执行以下逻辑当前线程数 corePoolSize→ 直接创建新线程执行任务即使有空闲线程也会新建。当前线程数 ≥ corePoolSize→ 尝试将任务放入阻塞队列入队成功 → 等待工作线程处理入队失败队列满 → 进入步骤 3尝试创建非核心线程如果当前线程数 maximumPoolSize则创建新线程执行任务否则触发拒绝策略。注意线程池内部不区分核心/非核心线程仅通过线程数量与corePoolSize/maximumPoolSize的对比来控制回收行为。五、阻塞队列常见类型队列特性适用场景SynchronousQueue无容量直接提交需要无限扩展线程配合maximumPoolSize较大ArrayBlockingQueue有界FIFO资源控制严格防止队列无限增长LinkedBlockingQueue有界/无界链表结构常用作无界队列配合FixedThreadPoolPriorityBlockingQueue支持优先级任务需按优先级处理六、实战案例自定义线程工厂我们通过一个自定义ThreadFactory来观察线程的创建时机。自定义线程工厂public class CustomThreadFactory implements ThreadFactory { private static final AtomicInteger poolNumber new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber new AtomicInteger(1); private final String namePrefix; public CustomThreadFactory() { SecurityManager s System.getSecurityManager(); group (s ! null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); namePrefix pool- poolNumber.getAndIncrement() -thread-; } Override public Thread newThread(Runnable r) { String name namePrefix threadNumber.getAndIncrement(); Thread t new Thread(group, r, name, 0); System.out.println(线程池创建线程名称为 name); if (t.isDaemon()) t.setDaemon(false); if (t.getPriority() ! Thread.NORM_PRIORITY) t.setPriority(Thread.NORM_PRIORITY); return t; } }测试代码public class ThreadPoolTest { public static void main(String[] args) { ExecutorService executorService new ThreadPoolExecutor( 5, // corePoolSize 10, // maximumPoolSize 60L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue(5), // 有界队列 new CustomThreadFactory() // 自定义工厂 ); for (int i 0; i 15; i) { int index i; executorService.execute(() - { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(由线程 Thread.currentThread().getName() 执行任务完成 index); }); } } }运行结果分析前 5 个任务 → 直接创建 5 个核心线程接下来 5 个任务 → 进入ArrayBlockingQueue(5)队列等待队列满后第 11 个任务起 → 创建非核心线程直到 max10剩余任务 → 触发拒绝策略本例未设置会抛异常从打印可以看出共创建 10 个线程5 核心 5 非核心成功执行 15 个任务5 队列缓冲 10 并行七、拒绝策略当线程数 maximumPoolSize且队列满时触发拒绝策略策略行为AbortPolicy抛出RejectedExecutionException默认CallerRunsPolicy由调用线程执行任务DiscardPolicy静默丢弃任务DiscardOldestPolicy丢弃队首任务重试提交八、总结与建议线程池是并发编程中的核心工具掌握其参数与状态转换是高性能系统设计的基础。生产环境中不要使用Executors创建无界队列线程池避免内存溢出。优先使用ArrayBlockingQueue或自定义LinkedBlockingQueue容量明确资源边界。自定义ThreadFactory可方便线程追踪与故障排查。选择合适的拒绝策略必要时实现自定义RejectedExecutionHandler。