delayed学习详解

图标

豆瓜

豆瓜网

豆瓜网专栏

首发
豆瓜 图标 2020-07-18 09:31:59

1.DelayedQueue是一个无界的阻塞队列,其内的元素是实现了Delayed接口的元素。

Delayed,一种混合风格的接口,用来标记那些应该在给定延迟时间之后执行的对象。此接口的实现必须定义一个 compareTo 方法,该方法提供与此接口的 getDelay 方法一致的排序。

getDelay的方法返回时剩余的延迟时间。

创建一个Delayed接口的实现类,该元素是要放入到QueueDelayed队列中的。

 MyDelayedEvent

其中Task是要执行的任务。创建一个Task接口,我们的任务都实现该接口,表示是一个任务调度到期后要执行的任务。

 Task

下面是我们实现的其中一个任务

 StudentTask

 

上面的类创建完毕后,我们需要创建一个守护线程来后台执行任务调度是否到到期的查询,时间到了后执行。getDelay()返回剩余的时间,

 MyDelayedService

 MyDelayedService的实现类

 

 MyDelayedServiceImp

 

通过测试可知,设置同一时刻的多个任务调度时,在时间到了之后,会全部进行执行。

 Test Code

 当要执行的线程数大于线程池的最大数目时,会进行等待。

 

?如何移除我们要取消的任务呢。

首先我们的任务是存放如QueueDelayed队列中的,在本文中。他存放于类MyDelayedServiceImp中的 queue变量中。其内存放是实现了delayed接口的元素。通过查看DelayedQueue的文档可知。

其通过remove(Object o)来移除,o是我们的元素。通过查看remove的实现可知。其内是通过equals比较两个对象是否相等来判断是否是同一个delayed。所以我们需要在我们的QueueDelayed中实现我们的equals方法,使其两个对象之间的相等能够进行判断。

内部实现:

复制代码

    /**
     * Removes a single instance of the specified element from this
     * queue, if it is present, whether or not it has expired.     */
    public boolean remove(Object o) {        final ReentrantLock lock = this.lock;
        lock.lock();        try {            return q.remove(o);//进入该方法
        } finally {
            lock.unlock();
        }
    }

复制代码

复制代码

public boolean remove(Object o) {        int i = indexOf(o);        if (i == -1)            return false;        else {
            removeAt(i);            return true;
        }
    }private int indexOf(Object o) {        if (o != null) {            for (int i = 0; i < size; i++)                if (o.equals(queue[i]))  //比较                    return i;
        }        return -1;
    }

复制代码

 

我们的实现;实现我们的Delayed元素的equals 和hashCode。

复制代码

package com.zimo.mybaties.delayed;import org.springframework.transaction.annotation.Transactional;import org.springframework.util.StringUtils;import java.util.concurrent.Delayed;import java.util.concurrent.TimeUnit;public class MyDelayedEvent implements Delayed{    //要执行的任务
    private Task task;    private String uniqueKey; //该uniqueKey的生成规则根据业务来进行确定。只需要确保uniqueKey是唯一标识的
    private Long endTime;    public MyDelayedEvent(Task task, Long endTime) {        this.task = task;        this.endTime = endTime;
    }    public MyDelayedEvent(Task task, Long endTime, Integer targetClassId) {        this.task = task;        this.endTime = endTime;
        setUniqueKey(targetClassId);
        System.out.println("unique key : "+getUniqueKey());
    }    //获取剩余的时间,为0获取负数时取出    //TimeUnit.NANOSECONDS 毫微妙    @Override    public long getDelay(TimeUnit unit) {//        return unit.convert(endTime,TimeUnit.MILLISECONDS) - unit.convert(System.currentTimeMillis(),TimeUnit.MILLISECONDS);
        return unit.convert(endTime,TimeUnit.NANOSECONDS) - unit.convert(System.currentTimeMillis(),TimeUnit.NANOSECONDS);
    }

    @Override    public int compareTo(Delayed o) {        if (this == o)            return 1;        if (o==null)            return -1;        long diff = this.getDelay(TimeUnit.NANOSECONDS) - o.getDelay(TimeUnit.NANOSECONDS);        return diff<0?-1:(diff==0?0:1);
    }

    @Override    public int hashCode() {        final int prime = 31; //hashCode就是用的31
        int result = 1;
        result = prime*result + endTime.hashCode();
        result = prime*result + ((uniqueKey==null)?0:uniqueKey.hashCode());        //我这里因为Task也是一个对象,为了简便,所以不用task作为hashCode生成对象。而是新增加一个uniqueKey。
        return result;
    }

    @Override    public boolean equals(Object obj) {        if (this==obj)            return true;        if (obj == null)            return false;        if (getClass()!=obj.getClass())            return false;
        MyDelayedEvent o = (MyDelayedEvent)obj;        //Long对象的比较,判断值是否相同也是通过equals
        if (!getEndTime().equals(o.getEndTime()))            return false;        if (!getUniqueKey().equals(o.getUniqueKey()))            return false;        return true;
    }    public String getUniqueKey() {        return uniqueKey;
    }    public void setUniqueKey(Integer targetClassId) {        //uniqueKey生成规则
        this.uniqueKey = new StringBuffer().append(task.getClass()).append(targetClassId).append(endTime).toString();
    }    public Task getTask() {        return task;
    }    public void setTask(Task task) {        this.task = task;
    }    public Long getEndTime() {        return endTime;
    }    public void setEndTime(Long endTime) {        this.endTime = endTime;
    }
}

复制代码

 后面有需要新的定时任务需求的时候,只需要新增一个实现了Task接口的实现类即可。

复制代码

public class AssistantTask implements Task {

    @Override    public void executeTask() {
        System.out.println("assistant task run ");
    }
}

复制代码

MyDelayedEvent delayed_assistant = new MyDelayedEvent(new AssistantTask(),nowTime+delay*1000+1000,2);
            myDelayedService.put(delayed_assistant);


本文由豆瓜网专栏作家 豆瓜 投稿发布,并经过豆瓜网编辑审核。

转载此文章须经作者同意,并附上出处(豆瓜网)及本页链接。

若稿件文字、图片、视频等内容侵犯了您的权益,请联系本站进行 投诉处理

相关搜索

delayed
图标 图标

豆瓜

豆瓜网

豆瓜网专栏

  • delayed学习详解

    图标
    豆瓜 图标 · 今天 09:31:59 · 2浏览
  • 决策树算法详解

    图标
    豆瓜 图标 · 今天 09:31:19 · 2浏览
  • 详细设计模板

    图标
    豆瓜 图标 · 今天 09:30:37 · 4浏览
  • 全部评论

    豆瓜

    豆瓜网

    豆瓜网专栏

  • delayed学习详解
  • 决策树算法详解
  • 详细设计模板
  • constants类详解
  • 01背包问题详解
  • 我来说两句