Timer和ScheduledThreadPoolExecutor的区别
Timer
基于单线程、系统时间实现的延时、定期任务执行类。具体可以看下面红色标注的代码。
public class Timer {
/**
* The timer task queue. This data structure is shared with the timer
* thread. The timer produces tasks, via its various schedule calls,
* and the timer thread consumes, executing timer tasks as appropriate,
* and removing them from the queue when they're obsolete.
*/
private final TaskQueue queue = new TaskQueue();
/**
* The timer thread.*/
private final TimerThread thread = new TimerThread(queue);
class TimerThread extends Thread {
/**
* This flag is set to false by the reaper to inform us that there
* are no more live references to our Timer object. Once this flag
* is true and there are no more tasks in our queue, there is no
* work left for us to do, so we terminate gracefully. Note that
* this field is protected by queue's monitor!
*/
boolean newTasksMayBeScheduled = true;
/**
* Our Timer's queue. We store this reference in preference to
* a reference to the Timer so the reference graph remains acyclic.
* Otherwise, the Timer would never be garbage-collected and this
* thread would never go away.
*/
private TaskQueue queue;
TimerThread(TaskQueue queue) {
this.queue = queue;
}
public void run() {
try {
mainLoop();
} finally {
// Someone killed this Thread, behave as if Timer cancelled
synchronized(queue) {
newTasksMayBeScheduled = false;
queue.clear(); // Eliminate obsolete references
}
}
}
/**
* The main timer loop. (See class comment.)
*/
private void mainLoop() {
while (true) {
try {
TimerTask task;
boolean taskFired;
synchronized(queue) {
// Wait for queue to become non-empty
while (queue.isEmpty() && newTasksMayBeScheduled)
queue.wait();
if (queue.isEmpty())
break; // Queue is empty and will forever remain; die
// Queue nonempty; look at first evt and do the right thing
long currentTime, executionTime;
task = queue.getMin();
synchronized(task.lock) {
if (task.state == TimerTask.CANCELLED) {
queue.removeMin();
continue; // No action required, poll queue again
}
currentTime = System.currentTimeMillis();
executionTime = task.nextExecutionTime;
if (taskFired = (executionTime<=currentTime)) {
if (task.period == 0) { // Non-repeating, remove
queue.removeMin();
task.state = TimerTask.EXECUTED;
} else { // Repeating task, reschedule
queue.rescheduleMin(
task.period<0 ? currentTime - task.period
: executionTime + task.period);
}
}
}
if (!taskFired) // Task hasn't yet fired; wait
queue.wait(executionTime - currentTime);
}
if (taskFired) // Task fired; run it, holding no locks
task.run();
} catch(InterruptedException e) {
}
}
}
}
Timer延时、定时任务的实现采用单线程,在主循环(mainLoop)中循环遍历任务队列(TaskQueue),如果执行时间小于等于当前系统时间则执行任务,否则继续等待(执行时间-当前时间)。
ScheduledThreadPoolExecutor
基于多线程、JVM时间实现的延时、定期任务执行类。具体可以看下面红色标注的代码。
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
DelayedWorkQueue中的take方法
public RunnableScheduledFuture<?> take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (;;) {
RunnableScheduledFuture<?> first = queue[0];
if (first == null)
available.await();
else {
long delay = first.getDelay(NANOSECONDS);
if (delay <= 0)
return finishPoll(first);
first = null; // don't retain ref while waiting
if (leader != null)
available.await();
else {
Thread thisThread = Thread.currentThread();
leader = thisThread;
try {
available.awaitNanos(delay);
} finally {
if (leader == thisThread)
leader = null;
}
}
}
}
} finally {
if (leader == null && queue[0] != null)
available.signal();
lock.unlock();
}
}
public long getDelay(TimeUnit unit) {
return unit.convert(time - now(), NANOSECONDS);
}
/**
* Returns current nanosecond time.
*/
final long now() {
return System.nanoTime();
}
ThreadPoolExecutor执行流程
submit(task)->execute(task)
->1.当前线程数<核心线程数: addWorker(核心工作者线程)->runWorker-> 循环【getTask(workQueue.take)->task.run】
->2.当前线程数>=核心线程数:排队任务成功:task add to workQueue(BlockingQueue)->addWorker(非核心工作者线程)......
->3.当前线程数>=核心线程数:排队任务失败:尝试添加新线程执行任务 addWorker(非核心工作者线程)......
ScheduledThreadPoolExecutor执行延时、定期任务,核心代码就在runWorker,循环获取任务队列中的任务然后执行,在获取任务的时候如果任务的执行时间没到,则进行等待。延时时间的计算都是基于System.nanoTime(),即JVM时间。
优缺点:
1.Timer单线程,执行周期任务时,一次出错,则TimerThread线程终止, 所有任务将无法执行。而且任务的执行时间可能会影响周期的准确性。
2.Timer基于系统时间,系统时间的修改会影响任务的执行。在以系统时间为准的场景中(public void schedule(TimerTask task, Date time))使用非常合适,使用周期性任务则受到极大影响,因为时间间隔被破坏!
3.ScheduledThreadPoolExecutor多线程,任务的执行不会相互影响,且能保证执行时间间隔的准确性。
4.ScheduledThreadPoolExecutor基于JVM时间,该时间本身无任何意义,仅用来计算时间间隔,不受系统时间影响。所以用来计算周期间隔特别合适,而且单位是纳秒更加精确。因此延时任务、周期任务采用它比Timer更加靠谱!
总结:
Timer的使用场景,仅在基于系统时间为准的场景中非常合适(依赖当前系统时间进行判断任务的执行)。
ScheduledThreadPoolExecutor的使用场景则更为广泛,对延时任务、周期任务使用此类更靠谱(依赖时间间隔(JVM时间差值计算得到)进行判断任务的执行)。基于系统时间执行的任务则无法精确(因为系统时间可以随时调整)!
Timer和ScheduledThreadPoolExecutor的区别的更多相关文章
- 使用Timer和ScheduledThreadPoolExecutor执行定时任务
Java使用Timer和ScheduledThreadPoolExecutor执行定时任务 定时任务是在指定时间执行程序,或周期性执行计划任务.Java中实现定时任务的方法有很多,主要JDK自带的一些 ...
- java定时任务调度工具Timer与Quartz的区别
Timer与Quartz的区别有三点: 1.出身不同:Timer由jdk直接提供,调用方式简单粗暴,不需要其它jar包支持.Quartz并非jdk自带,需要引入相应的jar包 2.能力区别:主要体现在 ...
- Timer与ScheduledThreadPoolExecutor的比较
推荐还是用第二种方法,即用ScheduledThreadPoolExecutor,因为它不需要像timer那样需要在里面再用一个线程池来保证计时的准确.(前提是线程池必须要大于1个线程) 1.time ...
- timer和ScheduledThreadPoolExecutor定时任务和每日固定时间执行
//ScheduledThreadPoolExecutor每三秒执行一次 public static void main(String[] args) { ScheduledThread ...
- Java任务调度开源框架quartz学习
一.quartz学习 Java框架介绍:Quartz从入门到进阶 http://edu.yesky.com/edupxpt/233/2209233.shtml 1.例子:http://javacraz ...
- 【高并发】ScheduledThreadPoolExecutor与Timer的区别和简单示例
JDK 1.5开始提供ScheduledThreadPoolExecutor类,ScheduledThreadPoolExecutor类继承ThreadPoolExecutor类重用线程池实现了任务的 ...
- 实例分析Scheduled Thread Pool Executor与Timer的区别
摘要:JDK 1.5开始提供Scheduled Thread PoolExecutor类,Scheduled Thread Pool Executor类继承Thread Pool Executor类重 ...
- .NET中的三种Timer的区别和用法
最近正好做一个WEB中定期执行的程序,而.NET中有3个不同的定时器.所以正好研究研究.这3个定时器分别是: //1.实现按用户定义的时间间隔引发事件的计时器.此计时器最宜用于 Windows 窗体应 ...
- .NET中的三种Timer的区别和用法(转)
最近正好做一个WEB中定期执行的程序,而.NET中有3个不同的定时器.所以正好研究研究.这3个定时器分别是: //1.实现按用户定义的时间间隔引发事件的计时器.此计时器最宜用于 Windows 窗 ...
随机推荐
- Dubbo 学习笔记
分布式基础理论 1. 什么是分布式系统? 分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个系统 2. 应用架构演变 单一应用架构 当网站流量很小时,只需一个应用,将所有功能都部署在一起 ...
- 【PostgreSQL】入门学习笔记
前言: 以下内容为前几天在备考PostgreSQL入门考试时候做的笔记,经过了全职的两天的奋战与实验,并最终顺利通过了PCA初级认证考试.现在把我学习的笔记分享给大家,文中有对应的思维导图图片可供 ...
- 使用 bitnami/postgresql-repmgr 镜像快速设置 PostgreSQL HA
什么是 PostgreSQL HA? 此 PostgreSQL 集群解决方案包括 PostgreSQL 复制管理器(replication manager),这是一种用于管理 PostgreSQL 集 ...
- python数据处理-matplotlib入门(2)-利用随机函数生成变化图形2
鉴于上一篇中最后三个问题: 1.上述程序是否能进行优化(比如功能相同的) 2.创建三个3个实例,用了3个语句,能否建一个函数,只输入一个数n,就自动创建n个实例?同时,每个实例的num_times随机 ...
- git 配置别名简化命令行和删除别名
废话不多说直接上添加别名语法 加上--global是针对当前用户起作用的,如果不加,那只针对当前的仓库起作用. git config --global alias.<自己想要的命令行> & ...
- .NET ORM 仓储层必备的功能介绍之 FreeSql Repository 实现篇
写在开头 2018年11月的某一天,头脑发热开启了 FreeSql 开源项目之旅,时间一晃已经四年多,当初从舒服区走向一个巨大的坑,回头一看后背一凉.四年时间从无到有,经历了数不清的日夜奋战(有人问我 ...
- 图片查看器——viewer.js
使用简介 https://github.com/FNNDSC/viewerjs(需要点击遮罩层关闭弹框的复制下面内容) https://www.jianshu.com/p/d98db3815823 v ...
- 关于Spring中的useSuffixPatternMatch
背景 spring-boot的版本是2.1.4.RELEASE,spring的版本是5.1.6.RELEASE 一个例子如下: @Configuration @Import(WebMvcAutoCon ...
- 零基础学Java第四节(字符串相关类)
本篇文章是<零基础学Java>专栏的第四篇文章,文章采用通俗易懂的文字.图示及代码实战,从零基础开始带大家走上高薪之路! String 本文章首发于公众号[编程攻略] 在Java中,我们经 ...
- ElasticSearch7.3学习(二十七)----聚合概念(bucket和metric)及其示例
一.两个核心概念:bucket和metric 1.1 bucket 有如下数据 city name 北京 张三 北京 李四 天津 王五 天津 赵六 天津 王麻子 划分出来两个bucket,一个是北 ...