startThread() 方法完整解析
一、方法调用链
execute(task)
↓
startThread()
↓
doStartThread()
↓
executor.execute(runnable)
↓
创建并启动 Thread
↓
执行 run() 方法(死循环)
二、startThread() 方法源码
private void startThread() {
// 1. 检查状态:只有在未启动状态才会启动
if (state == ST_NOT_STARTED) {
// 2. CAS 操作:确保只有一个线程能成功启动
if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
try {
// 3. 真正的启动逻辑
doStartThread();
} catch (Throwable cause) {
// 4. 启动失败,恢复状态
STATE_UPDATER.set(this, ST_NOT_STARTED);
PlatformDependent.throwException(cause);
}
}
}
// 5. 如果状态不是 ST_NOT_STARTED,直接返回(什么都不做)
}
三、关键点详解
1. 状态检查
if (state == ST_NOT_STARTED) {
// 只有未启动状态才会进入
}
状态常量:
private static final int ST_NOT_STARTED = 1; // 未启动
private static final int ST_STARTED = 2; // 已启动
private static final int ST_SHUTTING_DOWN = 3; // 正在关闭
private static final int ST_SHUTDOWN = 4; // 已关闭
private static final int ST_TERMINATED = 5; // 已终止
为什么要检查状态?
- 避免重复启动线程
- 如果已经启动过,直接返回
- 性能优化:不需要进入 CAS 操作
2. CAS 操作(关键!)
if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
// 只有一个线程能成功执行到这里
}
STATE_UPDATER 是什么?
private static final AtomicIntegerFieldUpdater<SingleThreadEventExecutor> STATE_UPDATER =
AtomicIntegerFieldUpdater.newUpdater(SingleThreadEventExecutor.class, "state");
CAS 的作用:
- Compare And Set:比较并设置
- 原子操作,线程安全
- 只有一个线程能成功将状态从
ST_NOT_STARTED改为ST_STARTED
为什么需要 CAS?
假设没有 CAS,可能出现:
线程 A 线程 B
| |
|--state == ST_NOT_STARTED|
| |--state == ST_NOT_STARTED
| |
|--doStartThread() |
| |--doStartThread() ❌ 重复启动!
有了 CAS:
线程 A 线程 B
| |
|--state == ST_NOT_STARTED|
| |--state == ST_NOT_STARTED
| |
|--CAS 成功 ✓ |
| |--CAS 失败 ✓(状态已变)
| |
|--doStartThread() |--直接返回
3. 异常处理
try {
doStartThread();
} catch (Throwable cause) {
// 启动失败,恢复状态
STATE_UPDATER.set(this, ST_NOT_STARTED);
PlatformDependent.throwException(cause);
}
为什么要恢复状态?
- 如果启动失败,允许下次重试
- 保持状态的一致性
四、doStartThread() 方法(核心)
private void doStartThread() {
// 断言:确保 thread 为 null
assert thread == null;
// executor 是 ThreadPerTaskExecutor,会创建新线程
executor.execute(new Runnable() {
@Override
public void run() {
// ===== 这里是新线程的执行体 =====
// 1. 将当前线程设置为 EventLoop 的线程
thread = Thread.currentThread();
// 2. 处理中断标志
if (interrupted) {
thread.interrupt();
}
boolean success = false;
updateLastExecutionTime();
try {
// 3. 执行 EventLoop 的 run() 方法(死循环)
SingleThreadEventExecutor.this.run();
success = true;
} catch (Throwable t) {
logger.warn("Unexpected exception from an event executor: ", t);
} finally {
// 4. 清理工作(后面详细说明)
// ...
}
}
});
}
五、executor.execute() 做了什么?
executor 是 ThreadPerTaskExecutor:
public final class ThreadPerTaskExecutor implements Executor {
private final ThreadFactory threadFactory;
public ThreadPerTaskExecutor(ThreadFactory threadFactory) {
this.threadFactory = threadFactory;
}
@Override
public void execute(Runnable command) {
// 每次创建一个新线程并启动
threadFactory.newThread(command).start();
}
}
关键点:
- 每次调用
execute()都会创建一个新线程 - 立即调用
thread.start()启动线程 - 新线程会执行传入的
Runnable
threadFactory 是什么?
// 在 NioEventLoopGroup 初始化时创建
ThreadFactory threadFactory = new DefaultThreadFactory("nioEventLoop");
// DefaultThreadFactory 的实现
public class DefaultThreadFactory implements ThreadFactory {
private final String prefix;
private final AtomicInteger nextId = new AtomicInteger();
@Override
public Thread newThread(Runnable r) {
// 创建线程,名字类似:nioEventLoop-1-1
Thread t = new Thread(r, prefix + "-" + nextId.incrementAndGet());
t.setDaemon(false); // 非守护线程
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
六、新线程的执行流程
executor.execute(new Runnable() {
@Override
public void run() {
// ===== 步骤 1:保存线程引用 =====
thread = Thread.currentThread();
// ===== 步骤 2:处理中断 =====
if (interrupted) {
thread.interrupt();
}
boolean success = false;
updateLastExecutionTime();
try {
// ===== 步骤 3:执行 run() 方法(死循环)=====
SingleThreadEventExecutor.this.run();
success = true;
} catch (Throwable t) {
logger.warn("Unexpected exception from an event executor: ", t);
} finally {
// ===== 步骤 4:清理工作 =====
// 4.1 更新状态为 SHUTTING_DOWN
for (;;) {
int oldState = state;
if (oldState >= ST_SHUTTING_DOWN ||
STATE_UPDATER.compareAndSet(this, oldState, ST_SHUTTING_DOWN)) {
break;
}
}
// 4.2 检查是否正确调用了 confirmShutdown()
if (success && gracefulShutdownStartTime == 0) {
logger.error("Buggy implementation; confirmShutdown() must be called");
}
try {
// 4.3 执行剩余任务和关闭钩子
for (;;) {
if (confirmShutdown()) {
break;
}
}
} finally {
try {
// 4.4 清理资源
cleanup();
} finally {
// 4.5 移除 FastThreadLocal
FastThreadLocal.removeAll();
// 4.6 更新状态为 TERMINATED
STATE_UPDATER.set(this, ST_TERMINATED);
// 4.7 释放信号量
threadLock.release();
// 4.8 检查任务队列
if (!taskQueue.isEmpty()) {
logger.warn("terminated with non-empty task queue");
}
// 4.9 设置终止 Future 为成功
terminationFuture.setSuccess(null);
}
}
}
}
});
七、NioEventLoop 的 run() 方法
@Override
protected void run() {
// 死循环,直到 EventLoop 关闭
for (;;) {
try {
// 1. select 操作(可能阻塞)
switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {
case SelectStrategy.CONTINUE:
continue;
case SelectStrategy.SELECT:
select(wakenUp.getAndSet(false));
if (wakenUp.get()) {
selector.wakeup();
}
default:
}
cancelledKeys = 0;
needsToSelectAgain = false;
final int ioRatio = this.ioRatio;
if (ioRatio == 100) {
try {
// 2. 处理 IO 事件
processSelectedKeys();
} finally {
// 3. 处理任务队列
runAllTasks();
}
} else {
final long ioStartTime = System.nanoTime();
try {
// 2. 处理 IO 事件
processSelectedKeys();
} finally {
// 3. 根据 ioRatio 限制任务执行时间
final long ioTime = System.nanoTime() - ioStartTime;
runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
}
}
} catch (Throwable t) {
handleLoopException(t);
}
// 4. 检查是否需要关闭
try {
if (isShuttingDown()) {
closeAll();
if (confirmShutdown()) {
return; // 退出循环
}
}
} catch (Throwable t) {
handleLoopException(t);
}
}
}
八、完整流程图
main 线程
|
|--eventLoop.execute(register0)
|
|--startThread()
| |
| |--state == ST_NOT_STARTED? ✓
| |
| |--CAS(ST_NOT_STARTED -> ST_STARTED) ✓
| |
| |--doStartThread()
| |
| |--executor.execute(new Runnable)
| |
| |--threadFactory.newThread(runnable)
| |
| |--thread.start()
| |
| +--> 新线程(nioEventLoop-1-1)
| |
| |--thread = Thread.currentThread()
| | (保存线程引用)
| |
| |--run() 死循环开始
| |
| |--for (;;) {
| | // 1. select IO 事件
| | select();
| |
| | // 2. 处理 IO 事件
| | processSelectedKeys();
| |
| | // 3. 处理任务队列
| | runAllTasks();
| | |
| | |--pollTask()
| | | 从 taskQueue 取出 register0
| | |
| | |--safeExecute(register0)
| | | 执行 register0 任务
| | }
| |
| |--循环继续...
|
|--返回(不等待线程执行完成)
九、关键设计点
1. 懒加载
// 构造方法中不创建线程
public NioEventLoop(...) {
// 只初始化属性
this.thread = null; // 线程为 null
}
// 第一次调用 execute() 时才创建
eventLoop.execute(task); // 触发 startThread()
好处:
- 节省资源:不用的 EventLoop 不会创建线程
- 延迟初始化:只在需要时创建
2. 单次启动保证
// 通过状态 + CAS 保证只启动一次
if (state == ST_NOT_STARTED) { // 第一道防线
if (CAS(ST_NOT_STARTED, ST_STARTED)) { // 第二道防线
doStartThread();
}
}
即使多个线程同时调用 execute(),也只会启动一个线程。
3. 线程引用保存
// 在新线程中保存自己的引用
thread = Thread.currentThread();
作用:
- 后续
inEventLoop()方法需要用到 - 判断当前线程是否是 EventLoop 线程
十、实际应用示例
示例 1:首次提交任务
// main 线程
EventLoopGroup group = new NioEventLoopGroup(1);
NioEventLoop eventLoop = (NioEventLoop) group.next();
// 此时 eventLoop.thread == null
// 第一次提交任务
eventLoop.execute(() -> {
System.out.println("第一个任务");
});
// 执行流程:
// 1. startThread() 被调用
// 2. 创建新线程 "nioEventLoop-1-1"
// 3. 新线程开始执行 run() 方法
// 4. 从 taskQueue 取出任务并执行
示例 2:第二次提交任务
// 第二次提交任务
eventLoop.execute(() -> {
System.out.println("第二个任务");
});
// 执行流程:
// 1. startThread() 被调用
// 2. state != ST_NOT_STARTED,直接返回
// 3. 任务加入队列
// 4. EventLoop 线程从队列取出并执行
十一、总结
startThread() 的核心逻辑
- 检查状态:只有未启动状态才会启动
- CAS 保证:确保只有一个线程能成功启动
- 创建线程:通过 ThreadPerTaskExecutor 创建新线程
- 保存引用:将新线程保存到 thread 变量
- 执行循环:新线程进入 run() 方法的死循环
关键设计
- 懒加载:第一次提交任务时才创建线程
- 单次保证:通过状态 + CAS 保证只启动一次
- 线程安全:使用 AtomicIntegerFieldUpdater 保证并发安全
- 异常处理:启动失败会恢复状态,允许重试
为什么这样设计?
- 性能优化:不用的 EventLoop 不创建线程
- 资源节省:避免创建不必要的线程
- 线程安全:通过 CAS 避免重复启动
- 简洁高效:一次启动,终身使用
183



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



