网站首页 > 技术文章 正文
Java实现定时任务有一下几种基本的方法:
1、Timer:这是java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务。使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行。一般用的较少。
2、ScheduledExecutorService:也jdk自带的一个类;是基于线程池设计的定时任务类,每个调度任务都会分配到线程池中的一个线程去执行,也就是说,任务是并发执行,互不影响。
3、Spring Task:Spring3.0以后自带的task,其实它的底层实现也是ScheduledExecutorService。
ScheduledExecutorService是一个接口,它的比较常用的一个实现就是ScheduledThreadPoolExecutor。
今天我们就来解读一下ScheduledThreadPoolExecutor的源码。
构造方法
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue());
}
public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), threadFactory);
}
public ScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), handler);
}
public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), threadFactory, handler);
}
因为ScheduledThreadPoolExecutor类是ThreadPoolExecutor类的子类,所以ScheduledThreadPoolExecutor类的构造方法实际上调用的是ThreadPoolExecutor类的构造方法。
schedule方法
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
//如果传递的Runnable对象和TimeUnit时间单位为空
//抛出空指针异常
if (command == null || unit == null)
throw new NullPointerException();
//装饰任务对象,在decorateTask方法中直接返回ScheduledFutureTask对象
RunnableScheduledFuture<?> t = decorateTask(command,
new ScheduledFutureTask<Void>(command, null, triggerTime(delay, unit)));
//执行延时任务
delayedExecute(t);
//返回任务
return t;
}
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit)
//如果传递的Callable对象和TimeUnit时间单位为空
//抛出空指针异常
if (callable == null || unit == null)
throw new NullPointerException();
//装饰任务对象,在decorateTask方法中直接返回ScheduledFutureTask对象
RunnableScheduledFuture<V> t = decorateTask(callable,
new ScheduledFutureTask<V>(callable, triggerTime(delay, unit)));
//执行延时任务
delayedExecute(t);
//返回任务
return t;
}
schedule的2个方法接收参数不同,内部逻辑都是一样,通过triggerTime计算触发时间,然后新建ScheduledFutureTask,并且经过decorateTask进行装饰后,调用delayedExecute进行延迟执行。
triggerTime方法
// 根据延迟和单位计算延迟时间
private long triggerTime(long delay, TimeUnit unit) {
// unit.toNanos 方法出来最大值是 Long.MAX
return triggerTime(unit.toNanos((delay < 0) ? 0 : delay));
}
// 根据延迟值计算触发时间
long triggerTime(long delay) {
return now() +
((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
}
// 防止延迟过大
private long overflowFree(long delay) {
//获取队列中的节点
Delayed head = (Delayed) super.getQueue().peek();
//获取的节点不为空,则进行后续处理
if (head != null) {
//从队列节点中获取延迟时间
long headDelay = head.getDelay(NANOSECONDS);
//如果从队列中获取的延迟时间小于0,并且传递的delay
//值减去从队列节点中获取延迟时间小于0
if (headDelay < 0 && (delay - headDelay < 0))
//将delay的值设置为Long.MAX_VALUE + headDelay
delay = Long.MAX_VALUE + headDelay;
}
//返回延迟时间
return delay;
}
这边需要关注的是overflowFree方法,因为ScheduledThreadPoolExecutor使用的DelayedWorkQueue,是根据time的大小进行排序。如果当前列表头(即将执行的那个任务,暂时称呼为head)的time = now() - 100,而新增的任务(暂时称呼为add)的time = Long.MAX + now(),那么 add.time - head.time 溢出变成了负数,间接导致列表的排序异常。overflowFree保证了这边不会发生溢出,还是刚才的例子,head.time = now() - 100,head.delay = -100,满足了if条件,那么这个时候,add.delay = Long.MAX_VALUE - 100,add.time = Long.MAX_VALUE - 100 + now(),add.time - head.time = Long.MAX_VALUE,完美解决了溢出的问题。
猜你喜欢
- 2024-11-21 Java 线程池 | ThreadPoolExecutor 原理分析
- 2024-11-21 面试侃集合 | DelayQueue篇
- 2024-11-21 springboot-如何配置线程池实现定时任务
- 2024-11-21 ThreadPoolExecutor源码解析
- 2024-11-21 心跳与超时:高并发高性能的时间轮超时器
- 2024-11-21 Java线程池ThreadPoolExecutor 线程池
- 2024-11-21 8 个线程池的深渊巨坑,使用不当直接生产事故!!!
- 2024-11-21 java线程池核心类ThreadPoolExecutor的应用
- 2024-11-21 Java线程池:ExecutorService 开发入门
- 2024-11-21 面试官:你给我说一下什么是时间轮吧?
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)