这是一个非常关键且设计精巧的 定时任务与超时管理组件 ------ GridTimeoutProcessor,它是 Apache Ignite 内核中负责 统一调度和处理所有异步超时事件的核心模块。
🎯 一、核心职责
统一管理所有需要"在某个时间点触发"的任务或超时逻辑。
它相当于 Ignite 内部的 "闹钟中心",用于:
- 执行延迟任务(
schedule(...)) - 监听
Future超时(waitAsync(...)) - 处理各种协议级别的超时(如通信超时、锁等待超时等)
所有实现了 GridTimeoutObject 接口的对象都可以被它管理。
🧱 二、关键字段解析
| 字段 | 类型 | 作用 |
|---|---|---|
timeoutWorker |
TimeoutWorker |
后台线程,负责轮询并触发到期任务 |
timeoutObjs |
GridConcurrentSkipListSet<...> |
按结束时间排序的超时对象集合(核心数据结构) |
mux |
Object |
锁对象,用于 timeoutWorker 线程的等待/唤醒机制 |
🔗 三、核心数据结构:GridConcurrentSkipListSet
java
private final GridConcurrentSkipListSet<GridTimeoutObject> timeoutObjs = ...
- 是一个 线程安全的跳表(Skip List)实现
- 按
endTime()升序排序 - 支持高效的:
- 插入(O(log n))
- 删除(O(log n))
- 查找最早到期任务(
firstx(),接近 O(1))
💡 类似 Java 标准库中的
ConcurrentSkipListSet,但可能是 Ignite 自定义优化版本。
排序规则:
java
Comparator<GridTimeoutObject> {
int res = Long.compare(o1.endTime(), o2.endTime());
if (res != 0) return res;
return o1.timeoutId().compareTo(o2.timeoutId());
}
- 先按 到期时间 排序
- 时间相同时,用
timeoutId()保证顺序唯一(避免equals/hashCode问题)
🧩 四、核心线程:TimeoutWorker
java
private final TimeoutWorker timeoutWorker = new TimeoutWorker();
这是一个 无限循环的工作线程,它的逻辑大致如下:
java
class TimeoutWorker implements Runnable {
public void run() {
while (!isCancelled) {
GridTimeoutObject first = timeoutObjs.firstx();
if (first == null) {
// 没有任务,等待
synchronized (mux) {
mux.wait();
}
}
else {
long now = U.currentTimeMillis();
long waitTime = first.endTime() - now;
if (waitTime <= 0) {
// 已到期,移除并执行
if (timeoutObjs.remove(first))
first.onTimeout();
}
else {
// 未到期,等待一段时间
synchronized (mux) {
mux.wait(waitTime);
}
}
}
}
}
}
✅ 它是一个典型的 "时间轮"简化版 或 "最小堆调度器"。
📥 五、核心方法详解
✅ 1. addTimeoutObject(...):注册一个超时对象
java
public boolean addTimeoutObject(GridTimeoutObject timeoutObj)
流程:
- 检查
endTime是否合法(不能是0或Long.MAX_VALUE) - 添加到
timeoutObjs中 - 如果它是 第一个(最早到期) ,则
notify()唤醒timeoutWorker线程
⚠️ 为什么只
notify()而不是notifyAll()?
- 因为只有一个消费者线程(
timeoutWorker),所以notify()足够且更高效
✅ 2. schedule(...):调度一个延迟/周期任务
java
public CancelableTask schedule(Runnable task, long delay, long period)
delay:首次执行延迟(毫秒)period:周期(毫秒),-1 表示只执行一次- 返回
CancelableTask:可取消任务
内部逻辑:
- 创建
CancelableTask(实现了GridTimeoutObject) - 计算
endTime = now + delay - 调用
addTimeoutObject(...)
当任务到期时,onTimeout() 会被调用,执行 task.run(),如果是周期任务,还会重新调度下一次。
✅ 3. waitAsync(...):带超时的 Future 等待
java
public void waitAsync(final IgniteInternalFuture<?> fut, long timeout, IgniteBiInClosure<...> clo)
这是 异步编程中非常常见的模式 :等待一个 Future 完成,但最多等 timeout 毫秒。
分情况处理:
timeout 值 |
行为 |
|---|---|
-1 |
立即超时 → 直接调用 clo.apply(null, true) |
0 |
无限等待 → 直接监听 fut |
>0 |
创建 WaitFutureTimeoutObject 并注册 |
关键设计:
- 双重监听机制 :
- 如果
Future先完成 → 移除超时对象,回调clo - 如果超时先发生 → 回调
clo并标记timedOut=true
- 如果
- 使用
AtomicBoolean finishGuard防止重复执行回调
🔁 这是典型的 "竞态条件保护" 设计。
✅ 4. removeTimeoutObject(...):取消一个超时任务
java
public boolean removeTimeoutObject(GridTimeoutObject timeoutObj)
- 用于取消尚未触发的任务
- 例如:
Future已提前完成,无需再等待超时
🚀 六、启动与停止流程
start():
java
new IgniteThread(timeoutWorker).start();
- 启动后台线程,开始监听超时事件
stop(boolean cancel):
java
timeoutWorker.cancel();
U.join(timeoutWorker); // 等待线程结束
- 安全关闭,避免资源泄漏
🎨 七、设计亮点总结
| 特性 | 说明 |
|---|---|
| 统一调度中心 | 所有超时逻辑集中管理,避免重复创建 Timer |
| 高并发安全 | 使用 ConcurrentSkipListSet,无锁读写 |
| 低延迟唤醒 | 最早任务变化时立即唤醒 worker |
| 精准定时 | 基于系统时间,支持毫秒级精度 |
| 可取消性 | 所有任务都支持动态取消 |
| 异步友好 | 支持 Future + Timeout 模式,避免阻塞线程 |
🧩 八、GridTimeoutObject 是什么?
这是一个接口,表示"一个会在未来某个时间点触发的对象":
java
interface GridTimeoutObject {
long endTime(); // 到期时间(绝对时间戳)
UUID timeoutId(); // 唯一ID,用于排序去重
void onTimeout(); // 到期时执行的逻辑
}
常见实现:
CancelableTask:周期/延迟任务WaitFutureTimeoutObject:Future 超时监听MessageTimeoutObject:通信消息超时LockTimeoutObject:分布式锁等待超时
📊 九、典型使用场景
场景 1:延迟执行任务
java
timeoutProcessor.schedule(() -> {
System.out.println("3秒后执行");
}, 3000, -1);
场景 2:周期任务(心跳)
java
timeoutProcessor.schedule(heartbeatTask, 0, 1000); // 每秒执行
场景 3:Future 超时控制
java
timeoutProcessor.waitAsync(someFuture, 5000, (err, timedOut) -> {
if (timedOut) {
System.out.println("请求超时");
} else if (err != null) {
System.out.println("请求失败: " + err);
} else {
System.out.println("请求成功");
}
});
🏁 十、总结
GridTimeoutProcessor是 Ignite 的 "定时中枢" ,它通过一个后台线程 + 有序集合的方式,高效、安全地管理了所有异步超时事件。
它的设计体现了:
- 资源复用:一个线程处理所有定时任务
- 线程安全:无锁数据结构 + 最小同步块
- 响应及时:到期立即触发,支持唤醒机制
- 扩展性强 :任何对象只要实现
GridTimeoutObject就可接入
🔔 一句话理解 :
它是一个 轻量级、高性能、集中式的超时调度器,是构建可靠分布式系统不可或缺的基础设施组件。