延时队列实现自定义定时服务
1.延时队列元素定义
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.实现延时队列
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.定义任务接口
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.抽象任务
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.定时任务执行时间配置表
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.
通过延时队列实现定时任务操作
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 唯一性
public class TaskIdSequnce { static Long l = 0l ; public static Long creatId(){ synchronized(l){ //自增1 l = l +1l ; return l; } } }
8 .线程池接口
public interface ThreadPool<Job extends SchedulerTask> { void execute(Job job); void shutdown(); void addWorkers(int num); void removeWorker(int num); int getJobSize(); }
9.实现线程池
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 ; } } }