Java线程池是一种预先创建并管理一组线程的机制,它通过复用已创建的线程来执行多个任务,而不是为每个任务都新建一个线程。Java线程池的工作原理是其高效管理并发任务的核心,其本质是一个基于池化思想和生产者-消费者模型的复杂调度系统。其工作流程可以概括为:任务提交后,线程池根据当前状态(核心线程数、队列容量、最大线程数)决定是创建新线程执行、放入队列缓冲,还是直接拒绝。
一、工作流程
Java线程池的工作流程是一个生产者-消费者模型,其核心在于对任务和线程进行解耦管理,通过预创建的线程池来高效处理并发任务,避免频繁创建和销毁线程带来的性能损耗。其完整流程可以概括为任务提交、队列缓冲、线程调度、任务执行和资源回收几个核心阶段。
1.任务提交与初始判断:当通过 execute(Runnable command) 或 submit(Callable task) 方法提交一个新任务时,线程池首先会判断当前活动线程数(workers)是否小于核心线程数(corePoolSize)。如果小于,则无论是否有空闲线程,线程池都会立即创建一个新的工作线程(Worker)来执行这个任务。这一步确保了核心线程的快速启动。
2.核心线程已满,任务进入队列:如果当前活动线程数已经达到或超过了 corePoolSize ,新提交的任务不会立即创建新线程,而是尝试进入任务队列(workQueue)进行缓冲等待。只要队列未满,任务就会被成功放入队列中排队。
3.队列已满,尝试扩容线程:如果任务队列也已满(对于有界队列而言),线程池会判断当前线程数是否小于最大线程数(maximumPoolSize)。如果小于,线程池会突破核心线程数的限制,创建新的非核心线程来立即执行这个新任务。这些非核心线程用于应对突发的高负载。
4.达到最大容量,执行拒绝策略:如果当前线程数已经达到了 maximumPoolSize ,并且任务队列也已满,意味着线程池的负载能力已达到上限。此时,新提交的任务将无法被处理,线程池会触发配置的拒绝策略(RejectedExecutionHandler)。常见的策略有:直接抛出异常(AbortPolicy)、由调用者线程自己执行(CallerRunsPolicy)、丢弃队列中最老的任务(DiscardOldestPolicy)或默默丢弃新任务(DiscardPolicy)。
5.任务执行与线程复用:在线程池内部,工作线程(Worker)会不断地从任务队列中获取任务来执行。一个线程执行完一个任务后,不会立即销毁,而是会继续从队列中获取下一个任务执行,实现了线程的复用。这是降低资源消耗的关键。
6.空闲线程回收:为了节省资源,当线程池中的线程数量超过 corePoolSize 时,那些空闲时间超过存活时间(keepAliveTime)的非核心线程将会被终止回收,直到线程数量回落到 corePoolSize 。默认情况下,核心线程即使空闲也会一直保持存活,除非设置了 allowCoreThreadTimeOut(true)
二、参数
线程池的运作行为由ThreadPoolExecutor的几个关键参数决定,它们共同构成了其工作原理的规则基础:
1.核心线程数 (corePoolSize):指线程池中需要长期维持的最小线程数量,即使这些线程处于空闲状态,也不会被销毁(除非设置了allowCoreThreadTimeOut为true)。当有新任务提交时,如果当前运行的线程数小于corePoolSize,线程池会优先创建一个新的核心线程来执行任务,而不是将任务放入队列。
2.最大线程数:指线程池允许创建的最大线程总数。当核心线程都在忙碌,并且任务队列(workQueue)已满时,线程池才会创建新的非核心线程(即“应急线程”)来处理任务,但线程总数不会超过此限制
3.空闲线程存活时间 (keepAliveTime) 与单位 (unit):keepAliveTime定义了当线程池中线程数量超过corePoolSize时,多余的空闲线程在等待新任务时的最长存活时间。超过这个时间,这些空闲线程将被终止,以减少资源消耗。unit则是这个时间的计量单位,如秒、毫秒等。
4.任务队列 (workQueue):任务队列是用于缓存待执行任务的阻塞队列,当运行的线程数达到核心线程数后,新提交的任务会进入此队列等待。不同的队列实现会极大地影响线程池的行为,JDK主要提供了以下几种:
ArrayBlockingQueue:一个有界的、基于数组的先进先出(FIFO)阻塞队列。可以防止因任务无限堆积导致的内存溢出,是资源可控的常用选择;
LinkedBlockingQueue:一个无界(默认容量为Integer.MAX_VALUE)的、基于链表的阻塞队列,同样遵循FIFO原则。由于它几乎不会被填满,因此使用此队列时,maximumPoolSize参数通常无效,线程池的规模将基本维持在corePoolSize。
SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等待另一个线程的移除操作,反之亦然。这意味着新任务到来时,如果没有空闲线程,就会直接创建新线程执行(如果未达maximumPoolSize),否则执行拒绝策略。它通常用于需要快速响应的场景,如Executors.newCachedThreadPool()就使用了此队列。
PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。任务可以按照优先级顺序被取出执行,而非默认的FIFO顺序。
5.线程工厂 (threadFactory): 用于创建新线程的工厂类。通过实现ThreadFactory接口,可以自定义线程的名称、是否为守护线程、优先级等属性。
6. 拒绝策略 (handler): 当线程池中的线程数已达到maximumPoolSize,并且任务队列也已满时,对新提交任务采取的处理策略。JDK内置了四种策略:
AbortPolicy(默认策略):直接抛出RejectedExecutionException异常,阻止系统继续运行
CallerRunsPolicy:让调用者线程(即提交任务的线程)自己执行该任务。这提供了一个简单的反馈机制,能降低新任务的提交速度。
DiscardOldestPolicy:丢弃队列中最早的一个任务,然后尝试重新提交当前任务。
DiscardPolicy:直接丢弃新提交的任务,不做任何处理也不抛出异常。
三、线程池的创建与使用
1.使用 ThreadPoolExecutor:ThreadPoolExecutor 是 Java 并发包(java.util.concurrent)中 最核心、最灵活的线程池实现类,它允许你精细控制线程池的行为。理解并正确使用 ThreadPoolExecutor 对构建高性能、稳定的并发程序至关重要。
ThreadPoolExecutor 的构造函数:
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 非核心线程空闲存活时间
TimeUnit unit, // 时间单位
BlockingQueue<Runnable> workQueue, // 任务队列
ThreadFactory threadFactory, // 线程工厂(可选)
RejectedExecutionHandler handler // 拒绝策略(可选)
)
完整实例:
import java.util.concurrent.*;
public class ProductionThreadPool {
public static void main(String[] args) {
int core = Runtime.getRuntime().availableProcessors(); // 获取 CPU 核心数
ThreadPoolExecutor executor = new ThreadPoolExecutor(
core, // corePoolSize
core * 2, // maximumPoolSize
60L, // keepAliveTime
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(100), // 有界队列,防止 OOM
new ThreadFactory() {
private final AtomicInteger seq = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "Biz-Worker-" + seq.getAndIncrement());
}
},
new ThreadPoolExecutor.CallerRunsPolicy() // 让调用方线程执行,起到限流作用
);
// 提交任务
for (int i = 0; i < 200; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println(taskId + " running on " + Thread.currentThread().getName());
try { Thread.sleep(500); } catch (InterruptedException e) { }
});
}
// 优雅关闭
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
2.使用 Executors 工厂类:Executors 是 Java 并发包(java.util.concurrent)中的一个工具类,提供了多个静态工厂方法,用于快速创建常见的线程池。虽然使用简单,但在生产环境中存在严重风险,需谨慎对待。
Executors 提供的常用方法:
- newFixedThreadPool(int n):返回类型为 ExecutorService,固定线程数,使用无界队列,问题为任务持续提交但处理慢,堆内存被占满OOM
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FixedThreadPoolExample {
public static void main(String[] args) {
// 创建一个包含 3 个线程的固定线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("Task " + taskId + " running on " + Thread.currentThread().getName());
try {
Thread.sleep(1000); // 模拟耗时操作
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
executor.shutdown(); // 关闭线程池
}
}
- newCachedThreadPool():返回类型为 ExecutorService,线程数无限大(最大Integer.MAX_VALUE),空闲60秒回收,问题为瞬间高并发时创建成千上万个线程系统崩溃
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CachedThreadPoolExample {
public static void main(String[] args) {
// 创建一个可缓存线程池(线程数动态调整)
ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("Task " + taskId + " on " + Thread.currentThread().getName());
try {
Thread.sleep(100); // 短任务
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
executor.shutdown();
}
}
- newSingleThreadExecutor():返回类型为 ExecutorService,单线程 + 无界队列,缺点为:同
newFixedThreadPool(1),有 OOM 风险
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SingleThreadExecutorExample {
public static void main(String[] args) {
// 创建单线程线程池(保证任务顺序执行)
ExecutorService executor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("Task " + taskId + " executed sequentially on " + Thread.currentThread().getName());
});
}
executor.shutdown();
}
}
- newScheduledThreadPool(int n):返回类型为 ScheduledExecutorService,支持定时/周期任务,最大线程数无限,缺点有高频任务可能耗尽资源
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledThreadPoolExample {
public static void main(String[] args) {
// 创建支持定时任务的线程池(2个线程)
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
// 延迟 1 秒后执行一次
scheduler.schedule(() -> {
System.out.println("Delayed task executed at " + System.currentTimeMillis());
}, 1, TimeUnit.SECONDS);
// 每隔 2 秒执行一次(初始延迟 0)
scheduler.scheduleAtFixedRate(() -> {
System.out.println("Periodic task running at " + System.currentTimeMillis());
}, 0, 2, TimeUnit.SECONDS);
// 10秒后关闭(避免程序无限运行)
scheduler.schedule(scheduler::shutdown, 10, TimeUnit.SECONDS);
}
}
170万+

被折叠的 条评论
为什么被折叠?



