当前位置:首页 > 旅游指南

classtimer JDK 中定时器是如何实现的

转自:简书作者:Fooisart

https://www.jianshu.com/p/e21eb60a2c41

jdk中实现定时器功能大致有三种方式:

java.util.Timer

Java . util . concurrent . Delayqueue

Java . util . concurrent . scheduledthreadpoolexecutor

静下心来,我们一个一个去探索。

I. java.util.Timer

示例代码:

/**

*安排指定的任务在指定的时间第一次开始重复执行固定速率周期

*每天中午12点

*

* @ authorFooisart

*创建于2019年1月14日21:46

*/

publicclassTimerDemo{

public static void main(String[]args){

Timer timer = newTimer

calendar calendar = calendar . getinstance;

日历。设置(日历。HOUR_OF_DAY,12);//控制时间

日历。设置(日历。MINUTE,0);//控制分钟

日历。设置(日历。SECOND,0);//控制秒

日期时间= calendar.getTime//执行时间为12:00:00

//每天12:00,每2秒执行一次操作

timer.schedule( newTimerTask {

@覆盖

publicvoidrun{

通过System.out.println( newDate+”执行任务。。。");

}

},时间,1000 * 2);

}

}

Demo中使用Timer实现一个定时任务,每天12点开始,每2秒执行一次。

偷换:在看源代码的时候偶然发现Timer里面有schedule和scheduleAtFixedRate,两者都可以按照指定的时间间隔在约定的时间执行。但是两者有什么区别呢?官方解释:一个是固定延迟,另一个是固定速率。那么这两个字到底是什么意思呢?在demo里运行一次代码,然后把调度改成scheduleAtFixedRate,就清楚了。

示例代码简洁明了,可以看出控制执行时间的方法应该是timer.schedule跟进看源码:

publicvoidschedule(TimerTask任务,日期优先时间,长周期){

if(句号& lt= 0)

throwNewillegalargumentexception(“非正周期”));

sched(task,firstTime.getTime,-period);

}

任务表示要执行的任务逻辑

FirstTime表示首次执行的时间

周期表示每次的间隔时间

继续跟进:

privatevoidsched(TimerTask任务,longtime,longperiod) {

//省略非键码

同步(队列){

if(!thread.newTasksMayBeScheduled)

thrownewIllegalStateException(“计时器已取消”));

同步(task.lock) {

if(task.state!= TimerTask。VIRGIN)

thrownewIllegalStateException(

“任务已经计划或取消”);

task.nextExecutionTime = time

task.period = period

task.state = TimerTask。SCHEDULED

}

queue . add(task);

if(queue.getMin == task)

queue.notify

}

}

这里实际上做了两件事

给task设定了一些参数,类似于初始化task。这里还给它加了把锁,可以思考一下为甚要在此初始化?为何要加锁?(不是本文范畴,各位伙伴自行思考)把初始化后的task加入到queue中。

看完这个,我们还是不明白怎么实现计时。别担心,继续。输入queu.add(任务)

/**

*向优先级队列添加新任务。

*/

voidadd(TimerTask任务){

//如有必要,增加后备存储

if(size + 1== queue.length)

queue = Arrays.copyOf(queue,2 * queue . length);

queue[++ size]= task;

fixUp(大小);

}

注意这里提到的,给优先级队列添加一个新任务。实际上,这里的TimerTask[]是一个优先级队列,使用阵列存储模式。并且它的数据结构是堆。包括fixUp,我们可以看到它保留了堆属性,即heapify。

所以,分析了所有可以分析的东西之后,还是看不出时机是如何实现的。再静下心来想想。如果要执行定时任务,必须先启动定时器。所以我们再来关注一下施工方法。

计时器有四种构造方法,最下面一种是:

publicTimer(字符串名称){

thread.setName(名称);

thread.start

}

可以看到这里启动了一个thread,所以既然是Thread,就要注意它的run方法。输入:

publicvoidrun{

尝试{

mainLoop

}最后{

//有人杀了这个线程,表现得好像定时器取消了一样

同步(队列){

newTasksMayBeScheduled = false

queue.clear//删除过时的引用

}

}

}

继续进入主回路:

/**

*主定时器循环。(见类评论。)

*/

privateVirtumainLoop {

while( true) {

尝试{

TimerTask任务;

booleantaskFired

同步(队列){

//省略

longcurrentTime,executionTime

task = queue.getMin

同步(task.lock) {

if(task.state == TimerTask。取消){

queue.removeMin

继续;//不需要任何操作,再次轮询队列

}

current time = system . current timemillis;

execution time = task . next execution time;

if(taskFired =(execution time & lt;=currentTime)) {

如果(task.period == 0) { //非重复,则删除

queue.removeMin

task.state = TimerTask。已执行;

}其他{ //重复任务,重新计划

queue.rescheduleMin(

task.period & lt0?当前时间-任务。期间

:execution time+task . period);

}

}

}

if(!Task fried)//任务尚未激发;等待

queue . wait(execution time-CurrentTime);

}

if(TaskFried)//任务已触发;运行它,没有锁

task.run

} catch(中断异常e) {

}

}

}

从上面的源代码可以看出,有两个重要的if

if(taskFired =(execution time & lt;=currentTime)),表示执行时间已经到了,那么执行下面的任务就好了;

if(!TaskFired),表示不是执行的时候,等一下就好。那你怎么等?仔细看了一遍,原来是Object.wait(长超时)被调用了。

这里我们知道jdk中的定时器是这样实现的,等待是用最简单的Object实现的,等等!别担心,这里有一个小问题:用Therad.sleep可以实现吗?如果可以,为什么不可以?

Java . util . concurrent . Delayqueue

详细分析了Java.util.Timer,DelayQueue类似。整理一下,重新开始。

首先是示例代码:

延迟队列本质上是一个队列,只有存储延迟的子类在这个队列中才有意义,它们都定义了延迟任务:

publicClassDelayTaskImplatesdelated {

私有日期开始日期=新日期;

publicDelayTask(长延迟数百万){

this . startdate . set time(new date . gettime+delay millons);

}

@覆盖

publicintcompareTo(延迟o){

long result = this . GetDelay(time UNit。NANCES)

- o.getDelay(TimeUnit。NANCES);

if(结果& lt0) {

return-1;

} else if(result & gt;0) {

返回1;

} else{

返回0;

}

}

@覆盖

publiclonggetDelay(时间单位单位){

Date now = newDate

long diff = startdate . GetTime-now . GetTime;

returnunit.convert(diff,TimeUnit。毫秒);

}

}

public static void main(String[]args)throwsException {

阻塞队列& ltDelayTask>。queue = newDelayQueue & lt>。;

delay task delay task = new delay task(1000 * 5L);

queue . put(DelayTask);

while(queue.size >;0){

queue.take

}

}

看主要方法,我主要做了三件事:

构造DelayTask,其中的延迟时间是5秒将任务放入队列从队列中取任务

延迟队列类似于计时器。刚才的TaskQueue,都是优先级队列。当元素被放入时,它们必须被堆积起来(如果元素已满,DelayQueue.put将阻塞)。自我研究)。专注于排队。拿着。

publie TakeTowsintErruptedexception {

finallyentrantlock lock = this . lock;

lock . Lock断续地;

尝试{

for(;;) {

e first = q . peek;

if(first == null)

可用。等待;

else{

long delay = first . GetDelay(NANCES);

if(延迟& lt= 0)

returnq.poll

first = null//等待时不要保留引用

if(leader!= null)

可用。等待;

else{

thread thithread = thread . current thread;

leader = thisThread

尝试{

available.awaitNanos(延迟);

}最后{

if(leader = = thithread)

leader = null

}

}

}

}

}最后{

if(leader = = null & amp;& ampq.peek!= null)

available.signal

lock.unlock

}

}

等待在源代码中出现三次:

第一次是队列为空时,等待;

等待第二次的原因是发现一个任务,执行时间没到,有领导准备执行。还是讲道理吧。既然有人准备执行,那我们就等着吧。

第三次是真正延迟的地方,可用的. await nano(delay)。此时没有其他线程执行,也就是我来执行,就等剩下的延迟时间吧。

在这里,我们理解延迟队列是通过条件等待来等待的。请注意,这里还有一个小问题:对象等待和条件等待之间有什么异同?

Java . util . concurrent . scheduledthreadpoolexecutor

由于ScheduledThreadPoolExecutor涉及到很多ThreadPoolExecutor,就不一一详细分析了,看完这个难免会累。直接总结结论:创建ScheduledThreadPoolExecutor时,线程池的工作队列使用DelayedWorkQueue,其take方法与DelayQueue.take方法非常相似,也有三个等待。

至此,到最后。总而言之,有两种方法可以在jdk中实现计时器:

使用Object.wait

使用条件等待

记住文章中的两个小问题:

可以用Thread.sleep吗?如果可以,为什么不可以?

Object.wait和Conditon.await有什么异同?

1.《classtimer JDK 中定时器是如何实现的》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。

2.《classtimer JDK 中定时器是如何实现的》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。

3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/junshi/1191050.html

上一篇

zara声明 zara为什么要发表声明声明内容是什么

下一篇

周琦发球失误是什么情况?周琦怎么发球失误了?

北京各类学校返校时间确定 各年级返校时间具体是什么

  • 北京各类学校返校时间确定 各年级返校时间具体是什么
  • 北京各类学校返校时间确定 各年级返校时间具体是什么
  • 北京各类学校返校时间确定 各年级返校时间具体是什么
2019国庆时间放假通知 国庆放多少天假?怎么拼假?

2019国庆时间放假通知 国庆放多少天假?怎么拼假?

2019年国庆假期通知国庆放假几天?怎么拼假?最近2019年国庆假期最新通知到了!国务院办公厅规定,今年国庆放假七天,时间为:十月一日(国庆节)至七日放假一周;9月29日(周日)和10月12日(周六)。如果要拼假期,建议10月8日(星期二)到1...

暴君刷新时间间隔 王者荣耀:暴君第一条刷新是什么时候?需要间隔多久?

  • 暴君刷新时间间隔 王者荣耀:暴君第一条刷新是什么时候?需要间隔多久?
  • 暴君刷新时间间隔 王者荣耀:暴君第一条刷新是什么时候?需要间隔多久?
  • 暴君刷新时间间隔 王者荣耀:暴君第一条刷新是什么时候?需要间隔多久?

暴君的刷新时间间隔 王者荣耀:暴君第一条刷新是什么时候?需要间隔多久?

  • 暴君的刷新时间间隔 王者荣耀:暴君第一条刷新是什么时候?需要间隔多久?
  • 暴君的刷新时间间隔 王者荣耀:暴君第一条刷新是什么时候?需要间隔多久?
  • 暴君的刷新时间间隔 王者荣耀:暴君第一条刷新是什么时候?需要间隔多久?
Android 10正式版有什么新功能具体推送时间是

Android 10正式版有什么新功能具体推送时间是

两周前,谷歌发布了最新安卓版本的宣传视频,宣布最新版本命名为安卓10。加拿大两大运营商Rogers和Telus已发布相关支持文件,声明安卓10官方版将于北京时间今晚,即北美9月3日,向所有Pixel手机推送,从最早的Pixel一代到最新的Pix...

男篮备战委内瑞拉 具体开战时间是将面对什么对手

男篮备战委内瑞拉 具体开战时间是将面对什么对手

北京时间9月2日,男篮世界杯A组第二轮,中国队在加时赛后以76-79不敌波兰队。中国男篮在世界杯小组赛中有胜有负。如果他们想晋级,除了准备最后一轮别无选择。从图中可以看出,昨天的失利并没有影响到今天的准备,大家都在为第三场战役做紧张的准备。昨晚...

蓝buff持续时间 王者荣耀:红蓝buff效果的持续时间有多久?

蓝buff持续时间 王者荣耀:红蓝buff效果的持续时间有多久?

在《王者荣耀》的h5游戏中,玩家可以通过杀死蓝宝石雕像或猩红宝石雕像来获得红蓝buff增益效果。这两个缓冲效果在游戏前期和后期都很有用,但是所有的缓冲效果都是有时间限制的,那么红蓝缓冲效果会持续多久呢?下面六皮手游网边肖会给你详细解答。 最新红...

王者荣耀红蓝buff作用 王者荣耀:红蓝buff效果的持续时间有多久?

王者荣耀红蓝buff作用 王者荣耀:红蓝buff效果的持续时间有多久?

在《王者荣耀》的h5游戏中,玩家可以通过杀死蓝宝石雕像或猩红宝石雕像来获得红蓝buff增益效果。这两个缓冲效果在游戏前期和后期都很有用,但是所有的缓冲效果都是有时间限制的,那么红蓝缓冲效果会持续多久呢?下面六皮手游网边肖会给你详细解答。 最新红...