這裏使用了delayed 來實現延遲隊列。
1. 定義函數接口
@FunctionalInterface
public interface EventFunction {
void apply();
}
這個是用於執行函數,Java自帶的有 Consumer 和 Function 等其他,因爲我這邊不需要入參和結果,所以我自己重新定義了一個。
2. 定義實體類
public class DelayedEntity implements Delayed {
private final String id;
private final long expireTime;
private final EventFunction function;
public DelayedEntity(long expireTime, EventFunction function) {
super();
this.expireTime = expireTime;
this.function = function;
// HuTool工具自動生成id,用於排查問題
this.id = IdUtil.fastSimpleUUID();
}
public void execute() {
function.apply();
}
@Override
public long getDelay(TimeUnit unit) {
return expireTime - System.currentTimeMillis();
}
@Override
public int compareTo(Delayed o) {
return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
}
public String getId() {
return id;
}
}
3. 定義消費者
@Slf4j
@Component
public class DelayEventConsumer implements Runnable {
private final DelayQueue<DelayedEntity> queue = new DelayQueue<>();
public DelayEventConsumer() {
}
public void submit(long expireTime, EventFunction function) {
queue.put(new DelayedEntity(expireTime, function));
}
@Override
public void run() {
DelayedEntity entity = null;
while (true) {
try {
entity = queue.poll();
if (entity == null) {
continue;
}
log.info("延遲隊列 [{}] 執行消息", entity.getId());
entity.execute();
log.info("延遲隊列 [{}] 執行完畢", entity.getId());
} catch (Exception e) {
log.error(String.format("延遲隊列 [%s] 執行報錯", entity != null ? entity.getId() : "null"), e);
}
}
}
}
4. 定義線程池
定義一個只有一個線程的線程池,在程序啓動的時候執行。
@Component
public class ApplicationStartListener implements ApplicationListener<ApplicationStartedEvent> {
@Autowired
private DelayEventConsumer delayEventConsumer;
@Override
public void onApplicationEvent(@NotNull ApplicationStartedEvent event) {
// HuTool工具生成只有一個線程的線程池,將消費者放進去執行
ThreadUtil.newSingleExecutor().submit(delayEventConsumer);
}
}
5. 測試
寫了個接口用來測試
@Slf4j
@RestController
@RequestMapping("/test")
@RequiredArgsConstructor
public class TestController {
private final DelayEventConsumer delayEventConsumer;
private final UserTagService userTagService;
@GetMapping("/testDelayQueue")
public void testDelayQueue() {
log.info("提交事件");
// 延遲2秒執行
delayEventConsumer.submit(System.currentTimeMillis() + 2000, () -> {
List<UserTags> userTags = userTagService.randomRobot();
log.info(JsonUtil.toJsonStr(userTags));
});
}
}
結果
2023-03-08 17:27:49.631 INFO 16792 --- [ool-13-thread-1] net.vitalblog.Logger : 提交事件
2023-03-08 17:27:51.755 INFO 16792 --- [ool-13-thread-1] net.vitalblog.Logger : 延遲隊列 [c195406b95a048f7b27825f6839dbe98] 執行消息
2023-03-08 17:27:52.475 INFO 16792 --- [ool-13-thread-1] net.vitalblog.Logger : [{"country":"IN","createTime":1677764575237,"id":4976,"level":20,"nickname":"👑 ptB_Colin","sid":104485,"type":"robot","userId":1368812591190769664}]
2023-03-08 17:27:52.476 INFO 16792 --- [ool-13-thread-1] net.vitalblog.Logger : 延遲隊列 [c195406b95a048f7b27825f6839dbe98] 執行完畢