无意看到一个延时队列的方式 比之前的要好用 哈哈哈 贴出来
首先 定义一个Task 任务类 记录唯一标示、过期时间等信息 其他信息可以自己加
public abstract class Task implements Delayed, Runnable
{
//唯一标示
private String id = "";
//过期时间
private long expire = 0;
public Task(String id, long delayInMilliseconds){
this.id = id;
this.expire = System.currentTimeMillis() + delayInMilliseconds;
}
public String getId() {
return id;
}
@Override
public long getDelay(TimeUnit unit) {
long diff = this.expire - System.currentTimeMillis();
return unit.convert(diff, TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed o) {
return Ints.saturatedCast(this.expire - ((Task) o).expire);
}
@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();
}
}
再就是 加入任务队列的服务类 TaskService
@Component
public class TaskService
{
private TaskService taskService;
private DelayQueue<Task> delayQueue = new DelayQueue<Task>();
@PostConstruct
private void init()
{
taskService = this;
Executors.newSingleThreadExecutor().execute(() ->
{
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);
}
}
再就是 处理需要过期的任务的 执行类 MaterialUnpaidTask
@Slf4j
public class MaterialUnpaidTask extends Task
{
private int materialId = -1;
public MaterialUnpaidTask(Integer materialId, long delayInMilliseconds)
{
super("MaterialUnpaidTask-" + materialId, delayInMilliseconds);
this.materialId = materialId;
}
public MaterialUnpaidTask(Integer materialId)
{
super("MaterialUnpaidTask-" + materialId, ParamKey.taskConf.MATERIAL_UNPAID * 60 * 1000);
this.materialId = materialId;
}
@Override
public void run()
{
log.info("系统开始处理延时任务---检查素材是否加入回收站,没有在回收站就移除---");
MaterialMapper materialMapper = ApplicationContextProvider.getBean(MaterialMapper.class);
//这里是拿到需要删除的素材 然后 删除
Material material = materialMapper.selectMaterialById(this.materialId);
if(material!=null&&material.getIsDelete()==1)
{
materialMapper.deleteMaterialById(material.getMaterialId());
log.info("线程:"+Thread.currentThread().getName()+",素材:");
}
log.info("系统结束处理延时任务---检查素材是否加入回收站,没有在回收站就移除---");
}
}
其中 MaterialMapper 是自己的 dao层方法 替换为自己的就可以了 逻辑也是一样 替换成自己的
最后 一个 就是 启动项目就需要进行的启动队列的类 TaskStartupRunner
@Component
public class TaskStartupRunner implements ApplicationRunner
{
@Autowired
private TaskService taskService;
@Autowired
private MaterialMapper materialMapper;
@Override
public void run(ApplicationArguments args)
{
//循环回收站 获取状态 addTask();
//启动的时候找到回收站的素材 不区分店铺
List<Material> materialList = materialMapper.selectGarbage(null);
for(Material material : materialList)
{
LocalDateTime add = LocalDateTimeUtil.ofUTC(material.getDeleteTime());
LocalDateTime now = LocalDateTime.now();
LocalDateTime expire = add.plusSeconds(90);
if(expire.isBefore(now))
{
// 已经过期,则加入延迟队列
taskService.addTask(new MaterialUnpaidTask(material.getMaterialId(), 0));
}
else{
// 还没过期,则加入延迟队列
long delay = ChronoUnit.MILLIS.between(now, expire);
taskService.addTask(new MaterialUnpaidTask(material.getMaterialId(), delay));
}
}
}
}
一样的 相关代码 替换成 自己的就可以了
到这里基本就OK了 之前也有过一个 那个 启动有些问题 但是我用了这个 问题就没有了 很神奇 虽然 我也不是 超级理解 这个延时队列 但 用起来真的香 哈哈 好了 不懂就问我哦 vx AiMyHear