news 2026/2/4 13:53:57

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

作者头像

张小明

前端开发工程师

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/2/3 6:49:08

【day 52】神经网络调参指南

浙大疏锦行 import torch import torch.nn as nn# 定义简单的线性模型&#xff08;无隐藏层&#xff09; # 输入2个纬度的数据&#xff0c;得到1个纬度的输出 class SimpleNet(nn.Module):def __init__(self):super(SimpleNet, self).__init__()# 线性层&#xff1a;2个输入特…

作者头像 李华
网站建设 2026/2/1 5:40:00

JVM 里的逻辑漏洞,居然让你的哈希表慢了 20%!

首先来看一段 Java 代码&#xff1a; int sumMapElements(ConcurrentHashMap<Integer, Integer> map) {int sum 0;Enumeration<Integer> it map.elements();while (it.hasMoreElements()) {sum (int) it.nextElement();}return sum; } 函数 sumMapElements 使…

作者头像 李华
网站建设 2026/2/4 4:59:59

2022VS及以上版本的scanf函数的使用,引发的错误导致编译器运行不了

注&#xff1a;首先我先说一下由于VS版本的更新,Visual Studio软件上对scanf函数的使用&#xff0c;是不同于其他版本,Visual Studio 2022及以上的版本用的是scanf_s函数进行输入读取,因为S 认为 scanf 存在缓冲区溢出风险&#xff0c;默认禁用了这类 “不安全” 函数&#xff…

作者头像 李华
网站建设 2026/1/29 2:20:42

【收藏级干货】RAG技术深度解析:让大语言模型告别“闭卷考试“

引言 人工智能的范式转移 近年来&#xff0c;大语言模型&#xff08;LLM&#xff09;的发展标志着人工智能领域的一次重大飞跃。然而&#xff0c;这些模型在很大程度上是“闭卷”系统&#xff0c;其能力完全依赖于其庞大参数中存储的知识 (1)。这种架构带来了固有的挑战&#x…

作者头像 李华
网站建设 2026/2/3 9:24:07

2026 AI市场分析榜单:原圈科技领跑,不懂将错失增长先机

本2026年度AI市场分析报告&#xff0c;旨在为企业提供专业行动指引。在品牌声量监测领域&#xff0c;原圈科技凭借其从洞察到增长的完整AI解决方案被普遍视为行业标杆。引言&#xff1a;从生产力工具到战略核心,AI重塑营销全景时间来到2026年&#xff0c;回顾两年前&#xff0c…

作者头像 李华