news 2026/7/23 4:33:46

定时任务简单源码思路手撕实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
定时任务简单源码思路手撕实现

定时任务简单源码思路手撕实现

importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;importjava.util.concurrent.PriorityBlockingQueue;importjava.util.concurrent.locks.LockSupport;publicclassScheduleService{Triggertrigger=newTrigger();ExecutorServiceexecutorService=Executors.newFixedThreadPool(6);voidschedule(Runnabletask,longdelay){Jobjob=newJob();job.setTask(task);//定时任务的第一次执行也是定的那个时间开始之后job.setStartTime(System.currentTimeMillis()+delay);job.setDelay(delay);trigger.queue.offer(job);//新提交一个任务就要唤醒看看这个任务的开始时间有没有可能是最小trigger.wakeUp();}classTrigger{PriorityBlockingQueue<Job>queue=newPriorityBlockingQueue<>();Threadthread=newThread(()->{while(true){while(queue.isEmpty()){LockSupport.park();}Jobpeek=queue.peek();if(peek.getStartTime()<System.currentTimeMillis()){peek=queue.poll();executorService.execute(peek.getTask());Joblast=newJob();last.setTask(peek.getTask());last.setStartTime(System.currentTimeMillis()+peek.getDelay());last.setDelay(peek.getDelay());queue.offer(last);}else{LockSupport.parkUntil(peek.getStartTime());}}});{thread.start();System.out.println("触发器启动");}voidwakeUp(){LockSupport.unpark(thread);}}}

定时任务这里主要是有一个trigger线程把任务提交给线程池执行,这样异步执行也防止trigger被阻塞,没有任务就用阻塞队列来阻塞防止cpu空转,而阻塞的时间就看当前的最小就行所以使用优先队列阻塞队列,通过拿最小的时间和现在的时间来比较没到点就用parkutil精确阻塞,到了就提交给线程池并把下一次还要进行的这个任务放进优先阻塞队列。提交完再睡上定时的时间就可以这一步是用添加新的任务来实现的只是修改开始时间别的参数继续传递。而在添加新的任务的时候要唤醒一下防止这个是新的最小但是trigger还被阻塞,在从优先阻塞队列拿任务的时候的peek可能和poll不一样因为多线程,但是只要poll在后面就行反正都是最小的。

publicclassJobimplementsComparable<Job>{privateRunnabletask;privatelongstartTime;privatelongdelay;publicJob(){}publicJob(Runnabletask,longstartTime,longdelay){this.task=task;this.startTime=startTime;this.delay=delay;}/** * 获取 * @return task */publicRunnablegetTask(){returntask;}/** * 设置 * @param task */publicvoidsetTask(Runnabletask){this.task=task;}/** * 获取 * @return startTime */publiclonggetStartTime(){returnstartTime;}/** * 设置 * @param startTime */publicvoidsetStartTime(longstartTime){this.startTime=startTime;}/** * 获取 * @return delay */publiclonggetDelay(){returndelay;}/** * 设置 * @param delay */publicvoidsetDelay(longdelay){this.delay=delay;}@OverridepublicintcompareTo(Jobo){returnLong.compare(this.startTime,o.startTime);}}

这里主要别忘了维护delay,好传递下去。

importjava.time.LocalDateTime;importjava.time.format.DateTimeFormatter;publicclassMain{publicstaticvoidmain(String[]args)throwsInterruptedException{ScheduleServicescheduleService=newScheduleService();DateTimeFormatterdateTimeFormatter=DateTimeFormatter.ofPattern("HH:mm:ss SSS");scheduleService.schedule(()->{System.out.println(LocalDateTime.now().format(dateTimeFormatter)+"逻辑门1");},100);Thread.sleep(50);scheduleService.schedule(()->{System.out.println(LocalDateTime.now().format(dateTimeFormatter)+"逻辑门2");},100);}}

这里就是把任务和定时时间传进去来执行,这里复现的知只是单机定时任务来理解原理,不是xxl-job那种集群下的分布式任务。

importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;importjava.util.concurrent.PriorityBlockingQueue;importjava.util.concurrent.locks.LockSupport;publicclassScheduleService{Triggertrigger=newTrigger();ExecutorServiceexecutorService=Executors.newFixedThreadPool(6);voidschedule(Runnabletask,longdelay){Jobjob=newJob();job.setTask(task);//定时任务的第一次执行也是定的那个时间开始之后job.setStartTime(System.currentTimeMillis()+delay);job.setDelay(delay);trigger.queue.offer(job);//新提交一个任务就要唤醒看看这个任务的开始时间有没有可能是最小trigger.wakeUp();}classTrigger{PriorityBlockingQueue<Job>queue=newPriorityBlockingQueue<>();Threadthread=newThread(()->{while(true){while(queue.isEmpty()){LockSupport.park();}Jobpeek=queue.peek();if(peek.getStartTime()<System.currentTimeMillis()){peek=queue.poll();executorService.execute(peek.getTask());Joblast=newJob();last.setTask(peek.getTask());last.setStartTime(System.currentTimeMillis()+peek.getDelay());last.setDelay(peek.getDelay());queue.offer(last);}else{LockSupport.parkUntil(peek.getStartTime());}}});{thread.start();System.out.println("触发器启动");}voidwakeUp(){LockSupport.unpark(thread);}}}

定时任务这里主要是有一个trigger线程把任务提交给线程池执行,这样异步执行也防止trigger被阻塞,没有任务就用阻塞队列来阻塞防止cpu空转,而阻塞的时间就看当前的最小就行所以使用优先队列阻塞队列,通过拿最小的时间和现在的时间来比较没到点就用parkutil精确阻塞,到了就提交给线程池并把下一次还要进行的这个任务放进优先阻塞队列。提交完再睡上定时的时间就可以这一步是用添加新的任务来实现的只是修改开始时间别的参数继续传递。而在添加新的任务的时候要唤醒一下防止这个是新的最小但是trigger还被阻塞,在从优先阻塞队列拿任务的时候的peek可能和poll不一样因为多线程,但是只要poll在后面就行反正都是最小的。

publicclassJobimplementsComparable<Job>{privateRunnabletask;privatelongstartTime;privatelongdelay;publicJob(){}publicJob(Runnabletask,longstartTime,longdelay){this.task=task;this.startTime=startTime;this.delay=delay;}/** * 获取 * @return task */publicRunnablegetTask(){returntask;}/** * 设置 * @param task */publicvoidsetTask(Runnabletask){this.task=task;}/** * 获取 * @return startTime */publiclonggetStartTime(){returnstartTime;}/** * 设置 * @param startTime */publicvoidsetStartTime(longstartTime){this.startTime=startTime;}/** * 获取 * @return delay */publiclonggetDelay(){returndelay;}/** * 设置 * @param delay */publicvoidsetDelay(longdelay){this.delay=delay;}@OverridepublicintcompareTo(Jobo){returnLong.compare(this.startTime,o.startTime);}}

这里主要别忘了维护delay,好传递下去。

importjava.time.LocalDateTime;importjava.time.format.DateTimeFormatter;publicclassMain{publicstaticvoidmain(String[]args)throwsInterruptedException{ScheduleServicescheduleService=newScheduleService();DateTimeFormatterdateTimeFormatter=DateTimeFormatter.ofPattern("HH:mm:ss SSS");scheduleService.schedule(()->{System.out.println(LocalDateTime.now().format(dateTimeFormatter)+"逻辑门1");},100);Thread.sleep(50);scheduleService.schedule(()->{System.out.println(LocalDateTime.now().format(dateTimeFormatter)+"逻辑门2");},100);}}

这里就是把任务和定时时间传进去来执行,这里复现的知只是单机定时任务来理解原理,不是xxl-job那种集群下的分布式任务。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/22 7:34:01

告别文献堆砌!宏智树 AI:手把手教你写出有灵魂的文献综述

作为深耕论文写作科普的教育博主&#xff0c;后台每天都被粉丝的文献综述难题刷屏&#xff1a;“读了 30 篇文献&#xff0c;写出来的综述还是‘观点大乱炖’”“引用格式改到崩溃&#xff0c;导师说我是‘学术搬运工’”“研究空白找不到&#xff0c;论文创新点无从谈起”。 …

作者头像 李华
网站建设 2026/7/19 6:52:42

COMSOL氩气等离子体显示板模型(PDP)探索

&#xff3b;COMSOL氩气等离子体显示板模型&#xff08;pdp&#xff09;&#xff3d;&#xff0c;与Journal of applied physics文献基本一致&#xff0c;有需要的可以拿去参考。嘿&#xff0c;大家好&#xff01;今天来聊聊 COMSOL 里的氩气等离子体显示板模型&#xff08;PDP…

作者头像 李华
网站建设 2026/7/22 1:22:46

当大模型成为生产力,知识付费行业如何迎接价值兑现时代?

近日&#xff0c;智谱AI作为全球大模型第一股在港交所上市的消息引发行业热议。这一标志性事件不仅代表着技术概念的成熟&#xff0c;更意味着AI正从实验室走向产业应用&#xff0c;从技术探索走向价值兑现。对于知识付费与在线教育行业而言&#xff0c;这背后隐藏着怎样的机遇…

作者头像 李华
网站建设 2026/7/22 1:23:38

当AI成为标准配置,知识服务者如何构建新竞争力?

智谱AI的上市不仅是一家企业的里程碑&#xff0c;更是整个AI产业从技术探索走向商业成熟的分水岭。对于知识付费与在线教育行业而言&#xff0c;这意味着AI技术已从“可选配件”转变为“标准配置”。在这样的背景下&#xff0c;教育从业者应当如何重新思考自身的核心竞争力&…

作者头像 李华