Java使用 Delayed 实现延迟任务

创建一个 Delayed 抽象类并且实现Runnable接口

/**
 * 延迟任务抽象
 */
public abstract class Task implements Delayed, Runnable{
    private String id = "";
    private long start = 0;

    /**
     *
     * @param id 任务ID, 用于区分不同任务
     * @param delayInMilliseconds 延迟毫秒
     */
    public Task(String id, long delayInMilliseconds){
        this.id = id;
        this.start = System.currentTimeMillis() + delayInMilliseconds;
    }

    public String getId() {
        return id;
    }

    @Override
    public long getDelay(TimeUnit unit) {
        long diff = this.start - System.currentTimeMillis();
        return unit.convert(diff, TimeUnit.MILLISECONDS);
    }

    @Override
    public int compareTo(Delayed o) {
        System.out.println(" this.start = " + this.start);
        System.out.println(" Delayed.start = " + ((Task) o).start);
        return Ints.saturatedCast(this.start - ((Task) o).start);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null) return false;
        if (!(o instanceof Task)) {
            return false;
        }
        Task t = (Task)o;
        return this.id.equals(t.getId());
    }

    @Override
    public int hashCode() {
        return this.id.hashCode();
    }
}

创建一个 延迟任务队列

/**
 * 延迟任务队列
 */
@Component
public class TaskService {
    private TaskService taskService;
    private DelayQueue<Task> delayQueue =  new DelayQueue<Task>();

    @PostConstruct
    private void init() {
        // 当前类初始化执行这个方法, 循环取 队列中的任务
        taskService = this;

        Executors.newSingleThreadExecutor().execute(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Task task = delayQueue.take();
                        task.run();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }

    public void addTask(Task task){
        if(delayQueue.contains(task)){
            return;
        }
        delayQueue.add(task);
    }

    public void removeTask(Task task){
        delayQueue.remove(task);
    }

}

使用

1、创建一个 延迟10秒发送 消息的任务

@Slf4j
public class SendMessageTask extends Task {
    /**
     * 用户ID
     */
    private Integer userId = -1;
    public OrderTimeOutTask(Integer id, long delayInMilliseconds) {
        super("OrderTimeOutTask-" + id , delayInMilliseconds);
        this.orderId = id;
    }
    @Override
    public void run() {
        log.info("延迟10秒向用户ID: 【{}】 发送消息", this.userId );
    }
}

2、创建延迟任务

    @Autowired
    private TaskService taskService;
    
	@Test
	public void test(){
	    // 延迟10 秒
	    LocalDateTime now = LocalDateTime.now();
	    LocalDateTime nowB = now.plusSeconds(10);
	    // 计算两个时间相差毫秒数
	    long betweenMillis =  ChronoUnit.MILLIS.between(now , nowB );
	    // 新增一个延迟任务到队列中
		taskService.addTask(new SendMessageTask(12580, betweenMillis ));
	}

后期考虑到系统重启后任务会丢失,可以在系统启动的时候把所有任务重新加入到队列中

示例

/**
 * 用于处理 程序重启 之后 继续处理延迟任务
 */
@Component
@Order(1)
public class TaskStartupRunner implements ApplicationRunner {

    private static Logger log = LoggerFactory.getLogger(TaskStartupRunner.class);

    @Autowired
    private TaskService taskService;


    @Override
    public void run(ApplicationArguments args) throws Exception {
        ThreadUtil.execAsync(new Runnable() {
            @Override
            public void run() {
                SendMessageTask();
            }
        });
    }

    public void SendMessageTask(){
            if(消息创建时间 大于当前时间){
                // 立即执行延迟任务
                taskService.addTask(new SendMessageTask(12580, 0));
            }else{
                // 消息创建时间 还没有超出 延迟时间,计算出当前时间和延迟时间
                long betweenMs =  ChronoUnit.MILLIS.between(now , nowB);
                taskService.addTask(new OrderTimeOutTask(12580, betweenMs));
            }
        
    }


}

你可能感兴趣的:(java,SpringBoot,java,开发语言,后端)