延时队列实现自定义定时服务
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 ;
}
}
}

浙公网安备 33010602011771号