【线程池的执行流程】

线程池执行任务的过程是一个多阶段协作的精密流程,涉及任务调度、线程管理、资源分配等核心机制。下面通过底层源码解析和流程图解,详细说明其工作原理:


一、线程池执行任务全流程(7个关键步骤)

调用线程ThreadPoolExecutor阻塞队列工作线程1. execute(Runnable command: 1. execute(Runnable command)2. 创建新Worker线程3. 启动线程执行任务4. 尝试入队入队成功5. 创建非核心线程6. 执行拒绝策略alt[线程数未达max][线程数已达max]alt[队列未满][队列已满]alt[核心线程未满][核心线程已满]7. 循环获取任务执行调用线程ThreadPoolExecutor阻塞队列工作线程

二、分步骤深度解析

1. 任务提交(execute方法)
// ThreadPoolExecutor.execute() 源码核心逻辑
public void execute(Runnable command) {
	if (command == null) throw new NullPointerException();
	
	int c = ctl.get(); // 获取控制状态(包含线程数+运行状态)
	
	// 步骤1:核心线程未满 → 创建Worker
	if (workerCountOf(c) < corePoolSize) {
	if (addWorker(command, true)) // true表示核心线程
	return;
	c = ctl.get();
	}
	
	// 步骤2:尝试入队
	if (isRunning(c) && workQueue.offer(command)) {
	int recheck = ctl.get();
	if (!isRunning(recheck) && remove(command))
	reject(command); // 线程池已关闭则回滚
	else if (workerCountOf(recheck) == 0)
	addWorker(null, false); // 保证至少有一个线程
	}
	// 步骤3:队列满且线程未达max → 创建非核心线程
	else if (!addWorker(command, false))
	reject(command); // 步骤4:触发拒绝策略
}
2. Worker线程创建(addWorker)
private boolean addWorker(Runnable firstTask, boolean core) {
	// 检查线程数是否超限(core决定检查corePoolSize还是maxPoolSize)
	if (workerCount >= (core ? corePoolSize : maximumPoolSize))
	return false;
	
	// 创建Worker对象(封装任务和线程)
	Worker w = new Worker(firstTask);
	Thread t = w.thread;
	
	// 将Worker加入HashSet<Worker> workers
	workers.add(w);
	
	// 启动线程(最终调用Worker.run())
	t.start();
	return true;
}
3. Worker执行逻辑(核心循环)
// Worker.run() → runWorker() 源码精简版
final void runWorker(Worker w) {
	Runnable task = w.firstTask;
	w.firstTask = null;
	while (task != null || (task = getTask()) != null) {
	try {
	task.run(); // 执行任务
	} finally {
	task = null; // 清空引用
	}
	}
	processWorkerExit(w); // 线程回收
}

// 从队列获取任务(支持超时控制)
private Runnable getTask() {
	boolean timed = allowCoreThreadTimeOut || workerCount > corePoolSize;
	Runnable r = timed ?
	workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
	workQueue.take();
	return r;
}

三、关键机制详解

1. 线程复用机制
  • while循环+任务队列:Worker线程不会执行完任务就终止,而是通过getTask()从队列获取新任务
  • 阻塞/超时控制
  • 核心线程:默认调用queue.take()永久阻塞
  • 非核心线程:使用queue.poll(keepAliveTime)超时等待
2. 任务调度优先级

执行顺序遵循以下严格优先级

  1. 核心线程(如果未满)
  2. 任务队列(如果未满)
  3. 非核心线程(如果未达max)
  4. 拒绝策略(如果队列和线程全满)
3. 线程回收流程
graph LR
A[getTask()返回null] --> B[减少Worker计数]
B --> C[从workers集合移除]
C --> D[尝试终止线程池]

四、不同队列策略的影响

队列类型行为特点适用场景
SynchronousQueue直接传递任务,不存储高吞吐快速存储
LinkedBlockingQueue无界/有界FIFO队列需要缓冲的任务池(FixedThreadPool)
ArrayBlockingQueue有界FIFO队列控制资源消耗
PriorityBlockingQueue按优先级排序任务有优先级差异

五、异常处理机制

  • 任务异常:被Worker捕获后不影响线程继续运行
try {
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} finally {
afterExecute(task, thrown); // 可重写该方法处理异常
}
  • 线程终止:异常导致线程退出时,会创建新Worker补充

六、生产环境问题诊断

1. 线程池卡死排查
# 使用jstack查看线程状态
jstack <pid> | grep -A 10 <thread_pool_name>

# 典型问题:
# - WAITING on java.util.concurrent.FutureTask@1a2b3c (常见于未设置超时)
# - BLOCKED on lock (线程间死锁)
2. 性能调优参数
// 动态调整线程池参数(需自定义ThreadPoolExecutor)
executor.setCorePoolSize(newSize);
executor.setMaximumPoolSize(newMaxSize);
executor.setRejectedExecutionHandler(newPolicy);

七、完整执行流程图解

提交任务
核心线程
是否已满?
创建核心线程执行
队列
是否已满?
任务入队等待
线程数
创建非核心线程执行
执行拒绝策略
Worker循环获取任务
队列有任务?
执行任务
允许核心超时?
超时后终止线程

理解线程池的任务执行流程,是编写高性能并发程序的基础。建议结合jstack和监控工具实时观察线程池状态,根据业务特点合理配置参数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值