Java實現通用本地隊列

這裏使用了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] 執行完畢

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章