1.整体链路
Kafka → RocksDB → SystemTimer → TimingWheel → Kafka
Java
public void sendDelay(long delayMs, String topic, String message) {
try {
DelayMessage delayMessage = new DelayMessage(delayMs, topic, message);
rocksDB.put(delayMessage.getKey(), delayMessage.toJson().getBytes());
systemTimer.add(delayMessage);
} catch (Exception e) {
log.error("sendDelayMessage error delayMs:{}, topic:{}, message:{}", delayMs, topic, message, e);
throw new RuntimeException(e);
}
}
- Kafka 生产者调用自定义延迟消息方法
- 延迟消息入库(RocksDB)
- 封装任务加入时间轮
- 时间轮触发
- run方法执行,将消息发送kafka,清除RocksDB
2.DelayMessage:延迟任务的最小数据模型
抽象类 TimerTask 的一种任务实现
Java
private final String message; // 消息体
private final long expireTime; // 绝对延迟时间 currentTimeMillis + delayMs
private final String topic; // 主题
private final Long partitionKey; // 分区
private final long delayMs; // 相对延迟时间
3.RocksDB:消息持久化组件
- 服务恢复后重新加载延迟任务
- 删除超出延迟上限的任务
- 4.SystemTimer:延迟任务调度入口
1.systemTimer.add(delayMessage)
将 DelayMessage/TimerTask 封装为 TimerTaskEntry,
也就是环形数组中,每个桶下面的链表中的一个节点对象
2.advanceClock() 触发 bucket
定时任务线程池,每个500ms检查一次 delayQueue
如果队列中有链表到期(桶的左边界),则推进时间轮,并执行槽内任务
5.TimerTask / TimerTaskEntry:任务包装结构
- TimerTask:最终执行逻辑(调用 KafkaTemplate 发送)
- TimerTaskEntry:环形双向链表节点 + expirationMs(具体的延迟时间)
TimerTask 与 TimerTaskEntry 双向绑定
TimerTask 持有 TimerTaskEntry 的引用
TimerTaskEntry 持有 TimerTask 的引用
1.取消任务
TimerTask 取消任务时,会将持有的 TimerTaskEntry 任务条目从链表中移除,并将引用置为空,
判断是否取消任务时,会根据 TimerTask 持有的引用是否 == this 来判断
2.加入时间轮与时间轮降级
bucket.add(timerTaskEntry) 时,需要先移除当前任务条目在链表中的旧引用,防止重复执行
3.保证线程安全
setTimerTaskEntry 设置条目时,synchronized 加锁,保证一个任务只属于一个条目
6.TimerTaskList:槽位结构与过期时间机制

时间轮(TimingWheel)是一个 存储定时任务的环形队列,
底层采用数组实现,数组中的每个元素可以存放一个定时任务列表(TimerTaskList)。
TimerTaskList 是一个环形的双向链表,
链表中的每一项表示的都是定时任务条目(TimerTaskEntry),其中封装了真正的定时任务 TimerTask。
ReentrantReadWriteLock 读写锁
✅添加任务时,加读锁,禁止并发写(flush)干扰。
✅推进时间轮时,flush执行槽内任务时,加写锁,禁止并发读(add)写(flush)修改结构。
7.TimingWheel:时间轮核心实现
基本属性组成
C++
private Long tickMs; // 时间轮每一格的时间间隔(基本时间跨度)
private Integer wheelSize; // 时间轮的格子数
private Long interval; // 时间轮一圈的总体时间跨度
private Long startMs; // 时间轮的起始时间
private AtomicInteger taskCounter; // 全局待执行任务计数器
private DelayQueue<TimerTaskList> queue; // 多层时间轮任务共享队列
private Long currentTime; // 时间轮当前指针指向的时间,是 tickMs 的整数倍
private volatile TimingWheel overflowWheel; // 上一轮(基本时间跨度是当前轮的总体时间跨度)
private TimerTaskList[] buckets; // 环形数组
add 方法
expiration:任务的绝对到期时间 (delayMs + Time.getHiresClockMs())
1.expiration < currentTime + tickMs:任务到期,如果没有取消,交由线程池执行
2.expiration < currentTime + interval:任务落到主轮,未到期,加入时间轮,设置到期时间,加入队列
3.expiration >= currentTime + interval:任务超过主轮覆盖范围,加入上一轮(递归调用 add)
advanceClock 方法
尝试推进时间轮,当 timeMs >= currentTime + tickMs 时,
任务条目绝对到期时间 >= 当前时间 + 基本时间跨度,更新时间轮,
如果有父轮,递归尝试推进父轮,父轮的一格,通常等于主轮的一圈。
8.多层时间轮:任务降级流程
假设有三层时间轮
主轮:tickMs(1s)wheelSize(20s)interval(20s)
父轮:tickMs(20s)wheelSize(20s)interval(400s)
爷轮:tickMs(400s)wheelSize(20s)interval(8000s)
📌第一次插入
- expireTime = 450s
- 主轮覆盖 0~20s → 放不下
- 调父轮(20~400s)仍放不下
- 调爷轮(400~8000s)命中
- 爷轮 slot = 400 (覆盖 400~800)
- 插入成功
📌到 400s 时触发 flush
- 链表销毁重建,从爷轮回溯到父轮
- 任务剩余:450 - 400 = 50s
📌重新 add → 回溯至父轮
- currentTime = 400s,父轮覆盖 400~800
- 剩余 50s 落入父轮
- slot 覆盖范围 40~60s
- 插入成功
📌到 440s 时触发 flush
- 任务剩余:50 - 40 = 10s
- 剩余 10s 落入主轮
- Slot 覆盖范围 9~10s
- 插入成功
📌主轮在 450s 触发 flush
- 执行 TimerTask
- 通过 IrcpKafkaTemplate 发送 Kafka
9.服务重启恢复机制:RocksDB → SystemTimer
- RocksIterator 扫描所有 DelayMessage
- 判定是否超出最大延迟
- 加入时间轮
- 删除过期 Key
10.代码实现
IrcpKafkaTemplate (自定义kafka工具类)
Java
@Service
@Slf4j
public class IrcpKafkaTemplate {
private static KafkaTemplate<String, Object> staticKafkaTemplate;
private static RocksDB rocksDB;
private final RocksDBManager rocksdbManager;
private final SystemTimer systemTimer;
private final ScheduledExecutorService executorService;
@Value("${delay.mq.max.delay.time:86400000}")
private long delayMqMaxDelayTime; // 消息从rocksdb中恢复时,若过期时间超过了配置,则会丢弃
@Resource
private KafkaTemplate<String, Object> kafkaTemplate;
@Autowired
public IrcpKafkaTemplate(RocksDBManager rocksdbManager) {
this.rocksdbManager = rocksdbManager;
this.systemTimer = new SystemTimer("kafka-delay-timer");
this.executorService = Executors.newSingleThreadScheduledExecutor();
}
@PostConstruct
public void init() throws RocksDBException {
rocksDB = rocksdbManager.getRocksDB();
staticKafkaTemplate = kafkaTemplate;
// 服务启动时,从RocksDB恢复数据到时间轮
List<byte[]> keysToDelete = new ArrayList<>();
try (RocksIterator it = rocksDB.newIterator()) {
long l = System.currentTimeMillis();
for (it.seekToFirst(); it.isValid(); it.next()) {
String json = new String(it.value());
DelayMessage delayMessage = DelayMessage.fromJson(json);
if (delayMessage.getExpireTime() - l > delayMqMaxDelayTime) {
log.warn("recover from rocksdb will discard. expireTime:{} - currentTimeMillis:{} > configMaxDelayTime:{}, delayMessage:{}", delayMessage.getExpireTime(), l, delayMqMaxDelayTime, delayMessage.toJson());
keysToDelete.add(delayMessage.getKey());
continue;
}
log.info("recover from rocksdb delayMessage:{}", delayMessage.toJson());
systemTimer.add(delayMessage);
}
}
keysToDelete.forEach(key -> {
try {
rocksDB.delete(key);
} catch (RocksDBException e) {
log.error("failed to delete key from RocksDB. key:{}", key, e);
}
});
executorService.scheduleAtFixedRate(() -> {
try {
systemTimer.advanceClock(200);
} catch (Exception e) {
log.error("advanceClock error", e);
}
}, 5000, 500, TimeUnit.MILLISECONDS);
}
public static KafkaTemplate<String, Object> getKafkaTemplate() {
return staticKafkaTemplate;
}
/**
* 消息延迟发送
*
* @param delayMs 延迟时间(毫秒), 延迟时间最低1000ms,建议一般 >=5s
* @param topic 需要发送的主题
* @param message 需要发送的消息
*/
public void sendDelay(long delayMs, String topic, String message) {
try {
DelayMessage delayMessage = new DelayMessage(delayMs, topic, message);
rocksDB.put(delayMessage.getKey(), delayMessage.toJson().getBytes());
// 多态
systemTimer.add(delayMessage);
} catch (Exception e) {
log.error("sendDelayMessage error delayMs:{}, topic:{}, message:{}", delayMs, topic, message, e);
throw new RuntimeException(e);
}
}
/**
* 消息延迟发送 且 指定分区
*
* @param delayMs 延迟时间, 延迟时间最低1000ms,建议一般 >=5s
* @param topic 需要发送的主题
* @param partitionKey 根据key计算分区
* @param message 需要发送的消息
*/
public void sendDelay(long delayMs, String topic, Long partitionKey, String message) {
try {
DelayMessage delayMessage = new DelayMessage(delayMs, topic, partitionKey, message);
rocksDB.put(delayMessage.getKey(), delayMessage.toJson().getBytes());
systemTimer.add(delayMessage);
} catch (Exception e) {
log.error("sendDelayMessage error delayMs:{}, topic:{}, partitionKey:{}, message:{}", delayMs, topic, partitionKey, message, e);
throw new RuntimeException(e);
}
}
/**
* 消息正常发送
*
* @param topic 主题
* @param message 消息
*/
public void send(String topic, String message) {
kafkaTemplate.send(topic, message);
}
/**
* 消息正常发送 且 指定分区
*
* @param topic 主题
* @param partitionKey 根据key计算分区
* @param message 消息
*/
public void send(String topic, Long partitionKey, String message) {
kafkaTemplate.send(topic, String.valueOf(partitionKey), message);
}
public static void removeFromRocksdb(DelayMessage delayMessage) throws RocksDBException {
rocksDB.delete(delayMessage.getKey());
}
@PreDestroy
public void stop() {
rocksdbManager.close();
executorService.shutdown();
try {
if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
log.error("stop executorService error", e);
executorService.shutdownNow();
}
}
}
DelayMessage
Java
@Slf4j
public class DelayMessage extends TimerTask {
public static final String EXPIRE_TIME = "expireTime";
public static final String PARTITION_KEY = "partitionKey";
public static final String TOPIC = "topic";
public static final String MESSAGE = "message";
public static final String DELAY_MS = "delayMs";
// 延迟任务信息
private final String message;
private final long expireTime;
private final String topic;
private final Long partitionKey;
private final long delayMs;
public DelayMessage(long delay, String topic, String message) {
this.delayMs = delay < 1000 ? 1000 : delay;
this.expireTime = System.currentTimeMillis() + delayMs;
this.topic = topic;
this.message = message;
this.partitionKey = null;
}
public DelayMessage(long delay, String topic, Long partitionKey, String message) {
this.delayMs = delay < 1000 ? 1000 : delay;
this.expireTime = System.currentTimeMillis() + delayMs;
this.topic = topic;
this.partitionKey = partitionKey;
this.message = message;
}
public DelayMessage(long delay, long expireTime, String topic, Long partitionKey, String message) {
this.delayMs = delay;
this.expireTime = expireTime;
this.topic = topic;
this.partitionKey = partitionKey;
this.message = message;
}
public String getTopic() {
return topic;
}
public String getMessage() {
return message;
}
public byte[] getKey() {
return MD5Util.getMd5Str(toJson()).getBytes(StandardCharsets.UTF_8);
}
public byte[] getValue() {
return message.getBytes(StandardCharsets.UTF_8);
}
public long getExpireTime() {
return expireTime;
}
@Override
public Long getDelayMs() {
return delayMs;
}
@Override
public void run() {
log.info("sendToKafka delayMessage: {}", toJson());
try {
if (partitionKey == null) {
IrcpKafkaTemplate.getKafkaTemplate().send(topic, message);
} else {
IrcpKafkaTemplate.getKafkaTemplate().send(topic, String.valueOf(partitionKey), message);
}
try {
IrcpKafkaTemplate.removeFromRocksdb(this);
} catch (Exception e) {
log.error("after send kafka, remove from rocksdb error message:{}", toJson(), e);
}
} catch (Exception e) {
log.error("sendToKafka error delayMessage: {}", toJson(), e);
}
}
public String toJson() {
Map<String, String> map = new HashMap<>();
map.put(MESSAGE, message);
map.put(TOPIC, topic);
if (partitionKey != null) {
map.put(PARTITION_KEY, String.valueOf(partitionKey));
}
map.put(EXPIRE_TIME, String.valueOf(expireTime));
map.put(DELAY_MS, String.valueOf(delayMs));
return JSONUtil.toJsonStr(map);
}
public static DelayMessage fromJson(String json) {
Map<String, String> map = JSONUtil.toBean(json, Map.class);
long delayMs = Long.parseLong(map.get(DELAY_MS));
long expireTime = Long.parseLong(map.get(EXPIRE_TIME));
String topic = map.get(TOPIC);
String message = map.get(MESSAGE);
Long partitionKey = map.get(PARTITION_KEY) == null ? null : Long.parseLong(map.get(PARTITION_KEY));
return new DelayMessage(delayMs, expireTime, topic, partitionKey, message);
}
}
SystemTimer
Java
@Slf4j
public class SystemTimer implements Timer, Function<TimerTaskEntry, Void> {
private ExecutorService taskExecutor; // 执行任务线程池
private Long tickMs; // 基本时间跨度
private Integer wheelSize; // 时间轮的格子数
private Long startMs; // 时间轮的起始时间
private DelayQueue<TimerTaskList> delayQueue = new DelayQueue<>();
private AtomicInteger taskCounter = new AtomicInteger(0); // 记录待执行任务的数量
private TimingWheel timingWheel; // 时间轮对象(管理所有任务的分配和延迟触发)
private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 读锁用于添加任务
private final ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
// 写锁用于推进时间轮,flush执行任务
private final ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
public SystemTimer(String executeName) {
// 每格1s,总共60格
tickMs = 1000L;
wheelSize = 60;
startMs = Time.getHiresClockMs();
taskExecutor = new ThreadPoolExecutor(10, 20,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(Integer.MAX_VALUE), r -> new Thread(r, executeName));
timingWheel = new TimingWheel(tickMs, wheelSize, startMs, taskCounter, delayQueue);
// 每30s打印一次当前待执行任务数量
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {
log.info("delay message for number of tasks pending execution: {}", size());
}, 0, 30, TimeUnit.SECONDS);
}
@Override
public void add(TimerTask timerTask) {
readLock.lock();
try {
// 将 timerTask 封装为 TimerTaskEntry,记录到期时间
addTimerTaskEntry(new TimerTaskEntry(timerTask, timerTask.getDelayMs() + Time.getHiresClockMs()));
} finally {
readLock.unlock();
}
}
@Override
public boolean advanceClock(long timeoutMs) {
try {
TimerTaskList bucket = delayQueue.poll(timeoutMs, TimeUnit.MILLISECONDS);
if (bucket != null) {
// 推进时间轮,不允许写
writeLock.lock();
try {
while (bucket != null) {
timingWheel.advanceClock(bucket.getExpiration());
// 执行槽内任务
bucket.flush(this);
bucket = delayQueue.poll();
}
} finally {
writeLock.unlock();
}
return true;
} else {
return false;
}
} catch (InterruptedException e) {
log.error("advanceClock interrupted", e);
}
return false;
}
@Override
public int size() {
return taskCounter.get();
}
@Override
public void shutdown() {
taskExecutor.shutdown();
}
private void addTimerTaskEntry(TimerTaskEntry timerTaskEntry) {
if (!timingWheel.add(timerTaskEntry)) {
// 任务没被取消,直接提交线程池执行
if (!timerTaskEntry.cancelled()) {
taskExecutor.submit(timerTaskEntry.getTimerTask());
}
}
}
@Override
public Void apply(TimerTaskEntry timerTaskEntry) {
addTimerTaskEntry(timerTaskEntry);
return null;
}
}
TimingWheel
Java
public class TimingWheel {
private Long tickMs; // 时间轮每一格的时间间隔(基本时间跨度)
private Integer wheelSize; // 时间轮的格子数
private Long interval; // 时间轮一圈的总体时间跨度
private Long startMs; // 时间轮的起始时间
private AtomicInteger taskCounter; // 全局待执行任务计数器
private DelayQueue<TimerTaskList> queue; // 多层时间轮任务共享队列
private Long currentTime; // 时间轮当前指针指向的时间,是 tickMs 的整数倍
private volatile TimingWheel overflowWheel; // 上一轮(基本时间跨度是当前轮的总体时间跨度)
private TimerTaskList[] buckets; // 环形数组
public TimingWheel(Long tickMs, Integer wheelSize, Long startMs, AtomicInteger taskCounter, DelayQueue<TimerTaskList> queue) {
this.tickMs = tickMs;
this.wheelSize = wheelSize;
this.startMs = startMs;
this.taskCounter = taskCounter;
this.queue = queue;
this.interval = tickMs * wheelSize;
this.currentTime = startMs - (startMs % tickMs);
this.buckets = new TimerTaskList[wheelSize];
for (int i = 0; i < buckets.length; i++) {
buckets[i] = new TimerTaskList(taskCounter);
}
}
/**
* 将一个任务加入时间轮
*/
public boolean add(TimerTaskEntry timerTaskEntry) {
long expiration = timerTaskEntry.getExpirationMs();
// 如果任务已经取消,则不加入
if (timerTaskEntry.cancelled()) {
// Cancelled
return false;
}
// 任务到期(到期时间 < 当前轮+下一格时间)
else if (expiration < currentTime + tickMs) {
// Already expired
return false;
} else if (expiration < currentTime + interval) {
// 计算任务应该落入哪一个槽位
long virtualId = expiration / tickMs;
TimerTaskList bucket = buckets[(int) (virtualId % wheelSize)];
bucket.add(timerTaskEntry);
// 设置槽位的到期时间
if (bucket.setExpiration(virtualId * tickMs)) {
queue.offer(bucket);
}
return true;
}
// 任务超出当前轮覆盖范围,放入父轮
else {
// Out of the interval. Put it into the parent timer
if (overflowWheel == null) {
// 创建父轮,一格时间 = 主轮一圈时间
addOverflowWheel();
}
return overflowWheel.add(timerTaskEntry);
}
}
/**
* 尝试推进时间轮的时钟(更新时间轮当前的时钟)
*/
public void advanceClock(Long timeMs) {
if (timeMs >= currentTime + tickMs) {
// 更新为目标格子的左边界
currentTime = timeMs - (timeMs % tickMs);
if (overflowWheel != null) {
// 推进父轮
overflowWheel.advanceClock(currentTime);
}
}
}
private void addOverflowWheel() {
synchronized (this) {
if (overflowWheel == null) {
overflowWheel = new TimingWheel(interval, wheelSize, currentTime, taskCounter, queue);
}
}
}
}
TimerTask
Java
public abstract class TimerTask implements Runnable {
protected Long delayMs = 3000L;
protected TimerTaskEntry timerTaskEntry; // 当前任务所在链表节点
public void cancel() {
synchronized (this) {
if (timerTaskEntry != null) {
timerTaskEntry.remove(); // 从时间轮桶移除
}
timerTaskEntry = null;
}
}
/**
* 双向绑定
* TimerTask 持有 TimerTaskEntry 的引用
* TimerTaskEntry 持有 TimerTask 的引用
* <p>
* TimerTaskEntry:封装了 TimerTask 和它的调度信息(到期时间 expirationMs、所在桶 list 等).
* TimerTask:实际要执行的任务,可能是 DelayMessage、DelayMessage2 等.
* </p>
* 作用:
* 1.取消任务 cancelled() ,通过引用指向判断是否被取消
* 2.重入时间轮 SystemTimer#apply(),需要根据 timerTask.remove() --> timerTask.getTimerTaskEntry() 找到旧条目,从原桶中移除,然后再把任务加入新的桶中
* 3.保证线程安全,set 方法锁 this,保证一个任务同时只属于一个条目
*/
public void setTimerTaskEntry(TimerTaskEntry entry) {
synchronized (this) {
if (timerTaskEntry != null && timerTaskEntry != entry) {
timerTaskEntry.remove();
}
timerTaskEntry = entry;
}
}
@Override
public void run() {}
public TimerTaskEntry getTimerTaskEntry() {
return timerTaskEntry;
}
public Long getDelayMs() {
return delayMs;
}
}
TimerTaskEntry
Java
public class TimerTaskEntry implements Comparable<TimerTaskEntry> {
private volatile TimerTaskList list; // 当前所在桶
public TimerTaskEntry next; // 前驱
public TimerTaskEntry prev; // 后继
private TimerTask timerTask; // 包含的任务
private Long expirationMs; // 到期时间,用于排序
public TimerTaskEntry() {}
public TimerTaskEntry(TimerTask timerTask, Long expirationMs) {
if (timerTask != null) {
timerTask.setTimerTaskEntry(this);
}
this.timerTask = timerTask;
this.expirationMs = expirationMs;
}
/**
* 每个 timerTask 内部会持有一个引用 timerTaskEntry,表示当前任务被哪个条目管理
* 如果当前任务被取消,则 timerTaskEntry 会被设置为 null,或者 timerTaskEntry 会被设置为其他 timerTaskEntry
* @return
*/
public boolean cancelled() {
return timerTask.getTimerTaskEntry() != this;
}
public void remove() {
TimerTaskList currentList = list;
while (currentList != null) {
currentList.remove(this);
currentList = list;
}
}
@Override
public int compareTo(TimerTaskEntry that) {
if (that == null) {
throw new NullPointerException("TimerTaskEntry is null");
}
Long expirationMs1 = this.expirationMs;
Long expirationMs2 = that.expirationMs;
if (expirationMs1 < expirationMs2) {
return -1;
}
if (expirationMs1 > expirationMs2) {
return 1;
}
return 0;
}
public Long getExpirationMs() {
return expirationMs;
}
public TimerTask getTimerTask() {
return timerTask;
}
public TimerTaskList getList() {
return list;
}
public void setList(TimerTaskList list) {
this.list = list;
}
}
TimerTaskList
Java
class TimerTaskList implements Delayed {
private AtomicInteger taskCounter; // 桶内任务数量计数器
private TimerTaskEntry root; // 哨兵节点,形成循环双向链表
private AtomicLong expiration; // 桶的过期时间(每个格子的左边界)
public TimerTaskList() {}
public TimerTaskList(AtomicInteger taskCounter) {
this.taskCounter = taskCounter;
this.root = new TimerTaskEntry(null, -1L);
this.root.next = root;
this.root.prev = root;
this.expiration = new AtomicLong(-1L);
}
public boolean setExpiration(Long expirationMs) {
return expiration.getAndSet(expirationMs) != expirationMs;
}
public Long getExpiration() {
return expiration.get();
}
public synchronized void foreach(Function<TimerTask, Void> f) {
TimerTaskEntry entry = root.next;
// 遍历循环链表
while (entry != root) {
TimerTaskEntry nextEntry = entry.next;
// 任务未被取消
if (!entry.cancelled()) {
f.apply(entry.getTimerTask());
}
entry = nextEntry;
}
}
public void add(TimerTaskEntry timerTaskEntry) {
boolean done = false;
// 循环直到成功加入链表(主要是为了处理并发情况下的重试)
while (!done) {
// 先移除任务在链表中旧的引用,防止重复执行
timerTaskEntry.remove();
// 锁桶
synchronized (this) {
// 锁住任务条目本身,防止多线程操作统一条目
synchronized (timerTaskEntry) {
// 检查任务是否已经绑定到桶
if (timerTaskEntry.getList() == null) {
// 插入到链表尾部(root.prev 指向尾)
TimerTaskEntry tail = root.prev;
timerTaskEntry.next = root;
timerTaskEntry.prev = tail;
// 绑定任务和当前桶
timerTaskEntry.setList(this);
tail.next = timerTaskEntry;
root.prev = timerTaskEntry;
// 任务数 + 1
taskCounter.incrementAndGet();
done = true;
}
}
}
}
}
public void remove(TimerTaskEntry timerTaskEntry) {
synchronized (this) {
synchronized (timerTaskEntry) {
if (timerTaskEntry.getList() == this) {
timerTaskEntry.next.prev = timerTaskEntry.prev;
timerTaskEntry.prev.next = timerTaskEntry.next;
timerTaskEntry.next = null;
timerTaskEntry.prev = null;
timerTaskEntry.setList(null);
taskCounter.decrementAndGet();
}
}
}
}
/**
* slot【销毁-->重建】
* 循环链表判断每个节点是否可以执行
* 如果不能执行,降级到下一层时间轮,重新加入链表,否则提交线程池执行
*/
public void flush(Function<TimerTaskEntry, Void> f) {
synchronized (this) {
TimerTaskEntry head = root.next;
while (head != root) {
remove(head);
f.apply(head);
head = root.next;
}
// 重置桶过期时间
expiration.set(-1L);
}
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(Long.max(getExpiration() - Time.getHiresClockMs(), 0), TimeUnit.MILLISECONDS);
}
/**
* 按桶的到期时间排序
*/
@Override
public int compareTo(Delayed d) {
TimerTaskList other;
if (d instanceof TimerTaskList) {
other = (TimerTaskList) d;
} else {
throw new ClassCastException("can not cast to TimerTaskList");
}
if (getExpiration() < other.getExpiration()) {
return -1;
} else if (getExpiration() > other.getExpiration()) {
return 1;
} else {
return 0;
}
}
}
RocksDBManager(管理 RocksDB 实例)
Java
@Component
@Slf4j
public class RocksDBManager {
private final RocksDB rocksDB;
public RocksDBManager(@Value("${rocksdb.path}") String rocksPath) throws RocksDBException {
RocksDB.loadLibrary();
Options options = new Options();
options.setCreateIfMissing(true);
String dbPath = rocksPath;
log.info("RocksDBManager get dbPath:{}", dbPath);
if (dbPath == null) {
dbPath = "rocksdb";
}
File dbFile = new File(dbPath);
if (!dbFile.exists()) {
if (!dbFile.mkdirs()) {
throw new RuntimeException("Failed to create rocksdb.path directory: " + dbPath);
}
}
rocksDB = RocksDB.open(options, dbPath);
}
public RocksDB getRocksDB() {
return rocksDB;
}
public void close() {
try {
rocksDB.close();
log.info("rocksDB closed.");
} catch (Exception e) {
log.error("close RocksDB error", e);
}
}
}
Timer
Java
public interface Timer {
void add(TimerTask timerTask);
boolean advanceClock(long timeoutMs);
int size();
void shutdown();
}
Time
Java
public class Time {
public static Long getHiresClockMs() {
return TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
}
}