延时队列实现自定义定时服务

1.延时队列元素定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public class DelayTask  implements Delayed {
 
    /**
     * 开始计时时间 不设置则默认为当前系统时间
     */
    private transient Date taskStartTime = new Date();
    /**
     * 过期时间 不设置则默认1分钟
     */
    private  long taskExpiredTime; // = 60 * 1000
    private   Long tId  ;
    /**
     * 初始设置开始计时时间
     * taskStartTime 开始时间 [String] [yyyy-MM-dd HH:mm:ss]
     * taskExpiredTime 过期时间 [long] 单位:s
     * @param taskStartTime
     * @param taskExpiredTime
     */
    public void initTaskTime(String taskStartTime, long taskExpiredTime,Long tId ) {
        this.tId = tId;
        if(!StringUtils.isEmpty(taskStartTime)) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            try {
                this.taskStartTime = sdf.parse(taskStartTime);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        this.taskExpiredTime = taskExpiredTime;
        this.taskExpiredTime += this.taskStartTime.getTime();
    }
 
    @Override
    public long getDelay(TimeUnit unit) {
        long delay  =  unit.convert(taskExpiredTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
//        MyLog.info(this.gettId() + " get delay:"+ delay);
        return delay;
    }
 
    @Override
    public int compareTo(Delayed o) {
        int i =  (this.getDelay(TimeUnit.MILLISECONDS) - ((DelayTask) o).getDelay(TimeUnit.MILLISECONDS)) > 0 ? 1:-1;
 
        MyLog.debug(this.gettId() +"   Leader id =  :" + (i!= 1 ? this.gettId(): ((DelayTask) o).gettId() )   );
        return i ;
     }
 
    public Date getTaskStartTime() {
        return taskStartTime;
    }
 
    public void setTaskStartTime(Date taskStartTime) {
        this.taskStartTime = taskStartTime;
    }
 
    public long getTaskExpiredTime() {
        return taskExpiredTime;
    }
 
    public void setTaskExpiredTime(long taskExpiredTime) {
        this.taskExpiredTime = taskExpiredTime;
    }
 
    public Long gettId() {
        return tId;
    }
 
    public void settId(Long tId) {
        this.tId = tId;
    }
}

  2.实现延时队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
public class DelayQueueHelper {
 
    private static final Logger logger = LoggerFactory.getLogger(DelayQueueHelper.class);
 
 
    private volatile static DelayQueueHelper delayQueueHelper = null;
 
    private DelayQueue<DelayTask> queue = new DelayQueue<DelayTask>();
 
    private DelayQueueHelper() {
    }
 
    public static DelayQueueHelper getInstance() {
        if(delayQueueHelper == null) {
            synchronized(DelayQueueHelper.class) {
                delayQueueHelper = new DelayQueueHelper();
                new Thread(()->{
                    start();
                }).start();
            }
        }
        return delayQueueHelper;
    }
 
    public synchronized void addTask(DelayTask task) {
        queue.offer(task);
//        queue.put(task);
    }
 
    public void removeTask(Long tId ) {
        if(tId == null){
            return;
        }
        for(Iterator<DelayTask> iterator = queue.iterator(); iterator.hasNext();) {
            DelayTask queueTask = (DelayTask) iterator.next();
            if(queueTask.gettId().equals(tId)){
                queue.remove(queueTask);
            }
         }
    }
 
    public DelayQueue<DelayTask> getQueue() {
        return queue;
    }
 
 
    public static void start(){
        DelayQueue queue  = delayQueueHelper.getQueue();
        while (true) {
            DelayTask task = null;
            try {
//                logger.info("等待定时任务");
                //queue.take() ; 阻塞 出现bug 未做优化。。。。改为poll() .非阻塞
                task = (DelayTask) queue.poll();
                if(task == null ){
                    sleep(1000);
                    continue;
                }
                 Long tId =  task.gettId();
                 SchedulerTaskHelper.start(tId);
            } catch (Exception e) {
                e.printStackTrace();
            }
 
        }
    }
 
}

  3.定义任务接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public interface SchedulerTask extends Runnable {
 
    String getDescription();
 
    void setDescription(String description);
 
    Runnable getStopCall();
 
    void setStopCall(Runnable stopCall);
 
    Runnable getBeforeCall();
 
    void setBeforeCall(Runnable excuteCall);
 
    Runnable getAfterCall();
 
    void setAfterCall(Runnable afterCall);
 
    default Long getId() {
        return TaskIdSequnce.creatId();
    }
 
 
    Long getDelayTime();
 
    void setDelayTime(Long delayTime);
 
 
}

  4.抽象任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
public abstract class AbstractSchedulerTask  implements  SchedulerTask{
 
    /**
     * 任务结束后的回调函数
     */
    private  Runnable stopCall = null;
    private  Runnable beforeCall = null;
    private  Runnable afterCall = null;
    /**
     * 切面延时执行时间
     */
    private Long  delayTime = 0l ;
 
 
    private String description;
    public AbstractSchedulerTask(String description ,Long  delayTime){
        this.description= description;
        this.delayTime = delayTime;
    }
 
    public AbstractSchedulerTask(String description ){
        this.description= description;
    }
 
 
 
    private Long id = TaskIdSequnce.creatId() ;
 
    @Override
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public String getDescription() {
        return description;
    }
 
    public void setDescription(String description) {
        this.description = description;
    }
 
    public void setStopCall(Runnable stopCall){
        this.stopCall = stopCall;
    }
 
    public Runnable getStopCall(){
        return this.stopCall;
    }
 
    public Runnable getBeforeCall () {
        return beforeCall;
    }
 
    public void setBeforeCall (Runnable beforeCall) {
        this.beforeCall = beforeCall;
    }
 
    public Runnable getAfterCall() {
        return afterCall;
    }
 
    public void setAfterCall(Runnable afterCall) {
        this.afterCall = afterCall;
    }
 
    public Long getDelayTime() {
        return delayTime;
    }
 
    public void setDelayTime(Long delayTime) {
        this.delayTime = delayTime;
    }
}

  5.定时任务执行时间配置表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
public class SchedulerTaskConf {
    /**
     * 计划id
     */
    private Long id;
    /**
     * 任务列表
     */
    private SchedulerTaskConf[] confs;
    /**
     * 时间周期, 单位ms
     * 0 表示只执行一次
     */
    private Long interval = 0l ;
    /**
     * 开始时间 [String] [yyyy-MM-dd HH:mm:ss]
     */
    private String taskStartTime  = DateUtil.date2String(new Date(),"yyyy-MM-dd HH:mm:ss");
    /**
     *  taskExpiredTime 过期时间 [long] 单位:ms
     */
    private Long taskExpiredTime = 10000l;
    /**
     * 截止时间 [String] [yyyy-MM-dd HH:mm:ss]
     */
    private String taskEndTime ="9999-01-01 01:01:01" ;
    /**
     * 最后一次执行时间戳
     */
    private Long lastExcTime = 0l;
 
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public SchedulerTaskConf[] getConfs() {
        return confs;
    }
 
    public void setConfs(SchedulerTaskConf[] confs) {
        this.confs = confs;
    }
 
    public Long getInterval() {
        return interval;
    }
 
    public void setInterval(Long interval) {
        this.interval = interval;
    }
 
    public String getTaskStartTime() {
        return taskStartTime;
    }
 
    public void setTaskStartTime(String taskStartTime) {
        this.taskStartTime = taskStartTime;
    }
 
    public Long getTaskExpiredTime() {
        return taskExpiredTime;
    }
 
    public void setTaskExpiredTime(Long taskExpiredTime) {
        this.taskExpiredTime = taskExpiredTime;
    }
 
    public String getTaskEndTime() {
        return taskEndTime;
    }
 
    public void setTaskEndTime(String taskEndTime) {
        this.taskEndTime = taskEndTime;
    }
 
    public Long getLastExcTime() {
        return lastExcTime;
    }
 
    public void setLastExcTime(Long lastExcTime) {
        this.lastExcTime = lastExcTime;
    }
 
    public SchedulerTaskConf (String  taskStartTime ,Long taskExpiredTime,Long interval,String taskEndTime){
        //设置开始时间,格式 : yyyy-MM-dd HH:mm:ss
        this.setTaskStartTime(taskStartTime);
        //设置延时执行时间10s
        this.setTaskExpiredTime(taskExpiredTime);
        // 设置发送频率 20s
        this.setInterval(interval);
        //设置定时任务终止时间,格式 : yyyy-MM-dd HH:mm:ss
        if(taskEndTime != null ){
            this.setTaskEndTime(taskEndTime  );
        }
    }
 
    public Long  getFirst(){
        Long nowStamp =  System.currentTimeMillis();
        Long start=  DateUtil.stringToTimestamp(this.getTaskStartTime(),"").getTime();
        Long end ;
        if(StringUtils.isEmpty(this.getTaskEndTime())){
              end = Long.MAX_VALUE;
        }else {
              end = DateUtil.stringToTimestamp(this.getTaskEndTime(),"").getTime();
        }
        if(start+ taskExpiredTime < nowStamp){
            return nowStamp;
        }
        if(start+ taskExpiredTime >  end){
            return 0l;
        }
        Long myStart = start+ taskExpiredTime;
        if(this.getConfs()!= null ){
            SchedulerTaskConf[] confs = this.getConfs();
            for(SchedulerTaskConf  conf:confs){
                Long nodeStart =  conf.getFirst();
                if(nodeStart <= 0l){
                    continue;
                }
                if(myStart >  nodeStart){
                    myStart = nodeStart;
                }
            }
        }
        return myStart;
    }
 
 
    public Long  getNext(){
        Long nowStamp =  System.currentTimeMillis();
        //超过定时截止日期,则直接返回0
        if(!StringUtils.isEmpty(this.getTaskEndTime())    ){
            Long end = DateUtil.stringToTimestamp(this.getTaskEndTime(),"").getTime();
            if(end  < nowStamp ){
                return  0L ;
            }
        }
        if(this.getLastExcTime()< nowStamp ){
            this.setLastExcTime(nowStamp);
        }else {
            return this.getLastExcTime() ;
        }
 
        if(interval <=0 ){
            return  0l ;
        }
        Long next = this.getLastExcTime() + interval;
        if(this.getConfs()!= null ){
            SchedulerTaskConf[] confs = this.getConfs();
            for(SchedulerTaskConf  conf:confs){
                Long nodeNext =  conf.getNext();
                if(nodeNext <= 0l){
                    continue;
                }
                if(next >  nodeNext){
                    next = nodeNext;
                }
            }
        }
        if(next  < this.getLastExcTime() ){
            return  0l ;
        }
        return next;
    }
}

  6.

通过延时队列实现定时任务操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
public class SchedulerTaskHelper {
 
    private static final Logger logger = LoggerFactory.getLogger(SchedulerTaskHelper.class);
 
 
    private volatile static Map<Long,SchedulerTaskConf> confMap = new HashMap<Long,SchedulerTaskConf>();
    private volatile static Map<Long,SchedulerTask> taskMap = new HashMap<Long,SchedulerTask>();
    private static ThreadPool tp = new DefaultThreadPool(1);
 
    public static ThreadPool getThreadPool(){
        return tp;
    }
    /**
     * 任务生成并添加
     * @param schedulerTask
     * @param taskConf
     */
    public static void registryTask(SchedulerTask schedulerTask,SchedulerTaskConf taskConf){
 
        if(!taskMap.containsKey(schedulerTask.getId())){
            synchronized (confMap){
                if(!taskMap.containsKey(schedulerTask.getId())) {
                    taskMap.put(schedulerTask.getId(),schedulerTask);
                }
            }
        }
        if(confMap.containsKey(schedulerTask.getId())){
            logger.error("此任务已经存在定时计划");
//            System.out.println("此任务已经存在定时计划");
        }else {
            synchronized (confMap){
                if(!confMap.containsKey(schedulerTask.getId())){
                     confMap.put(schedulerTask.getId(),taskConf);
                }
            }
        }
        taskInit(schedulerTask,taskConf);
    }
 
    /**
     * 任务第一次添加队列
     * @param schedulerTask
     * @param taskConf
     */
    public static void taskInit(SchedulerTask schedulerTask,SchedulerTaskConf taskConf){
        DelayQueueHelper delayQueueHelper =   DelayQueueHelper.getInstance();
        DelayTask delayTask = new DelayTask();
        Long start =  taskConf.getFirst();
        if(start <= 0l){
            return;
        }
        Long now = System.currentTimeMillis();
        delayTask.initTaskTime(DateUtil.date2String(new Date(),""),start - now , schedulerTask.getId());
        delayQueueHelper.addTask(delayTask);
        logger.info("定时任务初始化成功: id = " + delayTask.gettId());
    }
 
    /**
     * 添加下一次执行任务到队列
     * @param schedulerTask
     * @param taskConf
     */
    public static void taskNextIn(SchedulerTask schedulerTask,SchedulerTaskConf taskConf){
        DelayQueueHelper delayQueueHelper =   DelayQueueHelper.getInstance();
        DelayTask delayTask = new DelayTask();
        Long next = taskConf.getNext();
//        MyLog.info(schedulerTask.getDescription() + "下次执行时间: " + DateUtil.stampToTime(next));
        if(next <= 0l){
            stop(schedulerTask   );
            return;
        }
        Long now = System.currentTimeMillis();
 
        delayTask.initTaskTime(DateUtil.date2String(new Date(),""),next - now , schedulerTask.getId());
//        if(delayTask.gettId() == 1l){
//            System.out.println("任务"+ JSONObject.toJSONString(delayTask));
//            System.out.println("1");
//        }
        MyLog.debug(schedulerTask.getDescription() + " 下次执行时间在: " + (next/1000 - now/1000 ) +"s 后");
//        MyLog.debug( "TaskStartTime: " + DateUtil.date2String(delayTask.getTaskStartTime(),"") +", TaskExpiredTime : "+  DateUtil.stampToTime(delayTask.getTaskExpiredTime()));
        delayQueueHelper.addTask(delayTask);
    }
 
    /**
     * 线程执行任务
     * @param  id
     */
    public static void  start(Long id ){
        SchedulerTaskConf conf = confMap.get(id);
        if(conf == null ){
            logger.error("定时任务时间配置丢失:"+ id);
        }
 
        SchedulerTask schedulerTask =  taskMap.get(id);
        if(schedulerTask == null ){
            logger.error("定时任务丢失:"+ schedulerTask.getDescription());
        }
        logger.info(" 执行定时任务 " +schedulerTask.getDescription() );
        taskNextIn(schedulerTask,conf);
        tp.execute(schedulerTask);
    }
 
    //获取任务类名
    public static String getClassName(Long id ){
        SchedulerTask task  =  taskMap.get(id);
        return task.getClass().getName();
    }
 
    //移除任务
    public static boolean removeTask(Long id  ){
        if(taskMap.containsKey(id)){
            taskMap.remove(id);
            return true;
        }
         return false;
     }
 
    public static boolean stop(SchedulerTask schedulerTask){
        if(schedulerTask.getStopCall() != null ){
            new Thread(schedulerTask.getStopCall()).start();
        }
       return removeTask(schedulerTask.getId()  );
    }
 
}

  7.

任务id生成器,每次+1  唯一性
1
2
3
4
5
6
7
8
9
10
11
public class TaskIdSequnce {
    static Long l = 0l ;
 
    public static Long creatId(){
        synchronized(l){
            //自增1
            l =    l +1l ;
            return l;
        }
    }
}

  8 .线程池接口

1
2
3
4
5
6
7
public interface ThreadPool<Job extends SchedulerTask> {
    void execute(Job job);
    void shutdown();
    void addWorkers(int num);
    void removeWorker(int num);
    int getJobSize();
}

  9.实现线程池

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
public class DefaultThreadPool<Job extends SchedulerTask>  implements ThreadPool<Job> {
    private static final Logger logger = LoggerFactory.getLogger(DefaultThreadPool.class);
 
    private    int MAX_WORKER_SIZE = 10 ;
 
    private    int DEFAULT_WORKER_SIZE = 5;
 
    private    int MIN_WORKER_SIZE = 5;
 
    private List<Worker> workers = Collections.synchronizedList(new ArrayList<Worker>());
 
    private final LinkedList<Job> jobs = new LinkedList<Job>();
 
    private AtomicLong threadNum = new AtomicLong();
 
    private int workerNum = DEFAULT_WORKER_SIZE;
 
    public void execute(Job job) {
        if(job!=null){
            synchronized (jobs){
                jobs.add(job);
                jobs.notify();
            }
        }
    }
 
    public void shutdown() {
        for(Worker  worker:workers){
            worker.shutdown();
        }
 
    }
 
    public void addWorkers(int num) {
        synchronized (jobs){
            if(num + workerNum> MAX_WORKER_SIZE){
                num = MAX_WORKER_SIZE- workerNum;
            }
            initializeWorkers(num);
            workerNum += num;
        }
    }
 
    public void removeWorker(int num) {
        synchronized (jobs){
            if(num > workerNum){
                try {
                    throw new IllegalAccessException("");
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
            int count =0  ;
            while (count< num ){
                Worker worker = workers.get(count);
                if(workers.remove(worker)){
                    worker.shutdown();
                    count++;
                }
            }
            workerNum -= count;
        }
    }
 
    public int getJobSize() {
        return jobs.size();
    }
 
    public DefaultThreadPool( int MAX_WORKER_SIZE, int DEFAULT_WORKER_SIZE,int  MIN_WORKER_SIZE){
        this.MAX_WORKER_SIZE = MAX_WORKER_SIZE;
        this.DEFAULT_WORKER_SIZE = DEFAULT_WORKER_SIZE;
        this.MIN_WORKER_SIZE = MIN_WORKER_SIZE;
        initializeWorkers(DEFAULT_WORKER_SIZE);
    }
 
    public DefaultThreadPool(int num ){
        workerNum = num > MAX_WORKER_SIZE ?MAX_WORKER_SIZE:num< MIN_WORKER_SIZE?MIN_WORKER_SIZE:num ;
        initializeWorkers(workerNum);
    }
 
    private void initializeWorkers(int num){
        for(int i = 0 ; i < num; i ++ ){
            Worker worker = new Worker();
            workers.add(worker);
            Thread thread = new Thread(worker,"ThreadPool-Worker-"+ threadNum.incrementAndGet() );
            thread.start();
 
        }
 
    }
 
    class Worker implements Runnable {
        private  volatile  boolean running = true ;
        public void run() {
            while (running){
                Job job = null ;
                synchronized (jobs){
                    while(jobs.isEmpty()){
                        try {
                            jobs.wait();
                        }catch (Exception e){
                            Thread.currentThread().interrupt();
                            return;
                        }
                    }
                    job = jobs.removeFirst();
                }
                if(job != null ){
                    try {
                        Thread td =Thread.currentThread();
                        try {
                            if(job.getId() != null ){
                                td.setName("Scheduler-Worker-" + threadNum.incrementAndGet() +"-"+ SchedulerTaskHelper.getClassName(job.getId()));
                            }else {
                                td.setName("Scheduler-Worker-" + threadNum.incrementAndGet() +"-" );
                            }
                        }catch (Exception e){
                        }
                        if(job.getBeforeCall()!= null ){
                            try {
                                job.getBeforeCall().run(); ;
                            }catch (Exception e){
                                logger.error("线程池前调错误");
                            }
                        }
                        job.run();
                        if(job.getAfterCall() != null ){
                            try {
                                if(job.getDelayTime()> 0 ){
                                    Object waitO  = new Object();
                                    synchronized (waitO){
                                        waitO.wait(job.getDelayTime());
                                    }
//                                    Thread.sleep();
                                }
                                job.getAfterCall().run();
                            }catch (Exception e){
                                logger.error("线程池后调错误"+ ExceptionUtil.getMessage(e));
                            }
                        }
                    }catch (Exception e){
 
                    }
                }
 
            }
        }
 
        public void  shutdown(){
            running = false ;
        }
    }
}

  

posted @   higsan  阅读(111)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
点击右上角即可分享
微信分享提示