当前位置: 首页 > news >正文

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

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

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那种集群下的分布式任务。

http://www.jsqmd.com/news/253814/

相关文章:

  • Java swing mysql实现的酒店管理系统_javswing酒店管理系统mysql,零基础入门到精通,收藏这篇就够了
  • Commons-io工具包与Hutool工具包
  • MySQL性能优化:从底层原理到实战落地的全维度方案
  • 【课程设计/毕业设计】基于SpringBoot保护濒危野生动物公益救助交流平台基于SpringBoot濒危物种公益救助交流平台【附源码、数据库、万字文档】
  • JVM 里的逻辑漏洞,居然让你的哈希表慢了 20%!
  • 构建智能Agent的三大支柱:上下文工程、会话管理与记忆系统
  • 收藏备用!AI+多领域变革全解析:大模型如何重塑产业生态
  • 收藏备用|RAG技术架构三阶段演进全解析(从入门到进阶,小白也能懂)
  • 毕业论文通关秘籍:宏智树 AI 教你避开 80% 写作坑
  • AI 写论文哪个软件最好?实测封神!宏智树 AI 堪称毕业论文通关外挂
  • 写论文软件哪个好?实测宏智树 AI:毕业论文的全流程效率神器
  • 吐血推荐9个一键生成论文工具,本科生毕业论文轻松搞定!
  • 西门子SMART触摸屏与两台变频器的Modbus RTU通讯实战
  • 春节年货节营销冲刺!AI工具助力快速生成品牌VI全套设计
  • 低成本拿捏高级感|国潮礼盒 AI 渲染工具,年货节设计神器
  • Cesium中的CZML
  • Langchain如何和业务项目集成:LangChain 入门 (二)
  • COMSOL氩气等离子体显示板模型(PDP)探索
  • 潜航者指南:深入探索PyTorch核心API的七大维度
  • 收藏必备!LLM与LMM大模型全解析:从零到精通的学习指南
  • Cesium中的 Entity、Terrain、DataSource开发场景示例
  • MindSpore开发之路:MindSpore Lite实战:在端侧部署AI应用
  • 灵敏度随电池电量下降就会变得不灵敏, 有的时候电机或舵机不工作
  • Chroma向量数据库:超越`client = chromadb.Client()`的深度探索与生产实践
  • Cyber Triage 3.16 发布 - 通过 Cyber Triage Enterprise 更快开展调查
  • 导师严选2026 TOP8 AI论文写作软件:本科生毕业论文全攻略
  • Vue3 + Element Plus 表格复选框踩坑记录
  • 【收藏级干货】RAG技术深度解析:让大语言模型告别“闭卷考试“
  • 前后端分离靓车汽车销售网站系统|SpringBoot+Vue+MyBatis+MySQL完整源码+部署教程
  • 信号不太好,有什么要优化的地方