Java如何实现定时任务

更新时间:2023-07-08 08:52:28 阅读: 评论:0

能成教育Java如何实现定时任务
在我们编程过程中如果需要执⾏⼀些简单的定时任务,⽆须做复杂的控制,我们可以考虑使⽤JDK中的Timer定时任务来实现。下⾯LZ就其原理、实例以及Timer缺陷三个⽅⾯来解析java Timer定时器。
⼀、简介
在java中⼀个完整定时任务需要由Timer、TimerTask两个类来配合完成。 API中是这样定义他们的,Timer:⼀种⼯具,线程⽤其安排以后在后台线程中执⾏的任务。可安排任务执⾏⼀次,或者定期重复执⾏。由TimerTask:Timer 安排为⼀次执⾏或重复执⾏的任务。我们可以这样理解Timer是⼀种定时器⼯具,⽤来在⼀个后台线程计划执⾏指定任务,⽽TimerTask⼀个抽象类,它的⼦类代表⼀个可以被Timer计划的任务。
Timer类
在⼯具类Timer中,提供了四个构造⽅法,每个构造⽅法都启动了计时器线程,同时Timer类可以保证多个线程可以共享单个Timer对象⽽⽆需进⾏外部同步,所以Timer类是线程安全的。但是由于每⼀个Timer对象对应的是单个后台线程,⽤于顺序执⾏所有的计时器任务,⼀般情况下我们的线程任务执⾏所消耗的时间应该⾮常短,但是由于特殊情况导致某个定时器任务执⾏的时间太长,那么他就会“独占”计时器
的任务执⾏线程,其后的所有线程都必须等待它执⾏完,这就会延迟后续任务的执⾏,使这些任务堆积在⼀起,具体情况我们后⾯分析。
当程序初始化完成Timer后,定时任务就会按照我们设定的时间去执⾏,Timer提供了schedule⽅法,该⽅法有多中重载⽅式来适应不同的情况,如下:
schedule(TimerTask task, Date time):安排在指定的时间执⾏指定的任务。
schedule(TimerTask task, Date firstTime, long period) :安排指定的任务在指定的时间开始进⾏重复的固定延迟执⾏。
schedule(TimerTask task, long delay) :安排在指定延迟后执⾏指定的任务。
schedule(TimerTask task, long delay, long period) :安排指定的任务从指定的延迟后开始进⾏重复的固定延迟执⾏。
同时也重载了scheduleAtFixedRate⽅法,scheduleAtFixedRate⽅法与schedule相同,只不过他们的侧重点不同,区别后⾯分析。
scheduleAtFixedRate(TimerTask task, Date firstTime, long period):安排指定的任务在指定的时间开始进⾏重复的固定速率执⾏。
scheduleAtFixedRate(TimerTask task, long delay, long period):安排指定的任务在指定的延迟后开始进⾏重复的固定速率执⾏。
TimerTask
TimerTask类是⼀个抽象类,由Timer 安排为⼀次执⾏或重复执⾏的任务。它有⼀个抽象⽅法run()⽅法,该⽅法⽤于执⾏相应计时器任务要执⾏的操作。因此每⼀个具体的任务类都必须继承TimerTask,然后重写run()⽅法。
另外它还有两个⾮抽象的⽅法:
boolean cancel():取消此计时器任务。
long scheduledExecutionTime():返回此任务最近实际执⾏的安排执⾏时间。
⼆、实例
2.1、指定延迟时间执⾏定时任务
public class TimerTest01 {
Timer timer;
public TimerTest01(int time){
timer = new Timer();
timer.schedule(new TimerTaskTest01(), time * 1000);
}
</span><span >public</span> <span >static</span> <span >void</span><span > main(String[] args) {
System.out.println(</span>""<span >);
</span><span >new</span> TimerTest01(3<span >);
}
}
public class TimerTaskTest01 extends TimerTask{
黄宝石
</span><span >public</span> <span >void</span><span > run() {
System.out.println(</span>"Time's up"<span >);
}
}
运⾏结果:
⾸先打印:
3秒后打印:Time's up
2.2、在指定时间执⾏定时任务 [code]public class TimerTest02 { Timer timer;
public class TimerTest02 {
Timer timer;
</span><span >public</span><span > TimerTest02(){
Date time </span>=<span > getTime();
System.out.println(</span>"指定时间time=" +<span > time);
timer </span>= <span >new</span><span > Timer();
timer.schedule(</span><span >new</span><span > TimerTaskTest02(), time);
}
</span><span >public</span><span > Date getTime(){
Calendar calendar </span>=<span > Instance();
calendar.t(Calendar.HOUR_OF_DAY, </span>11<span >);
calendar.t(Calendar.MINUTE, </span>39<span >);
calendar.t(Calendar.SECOND, </span>00<span >);
Date time </span>=<span > Time();
</span><span >return</span><span > time;
}
</span><span >public</span> <span >static</span> <span >void</span><span > main(String[] args) {
</span><span >new</span><span > TimerTest02();
}
}
public class TimerTaskTest02 extends TimerTask{
@Override
</span><span >public</span> <span >void</span><span > run() {
System.out.println(</span>"指定时间执⾏线程任务..."<span >);
}
}
当时间到达11:39:00时就会执⾏该线程任务,当然⼤于该时间也会执⾏!!执⾏结果为:
指定时间time=Tue Jun 10 11:39:00 CST 2014
指定时间执⾏线程任务...
2.3、在延迟指定时间后以指定的间隔时间循环执⾏定时任务
public class TimerTest03 {
Timer timer;
</span><span >public</span><span > TimerTest03(){
timer </span>= <span >new</span><span > Timer();
timer.schedule(</span><span >new</span> TimerTaskTest03(), 1000, 2000<span >);
}
</span><span >public</span> <span >static</span> <span >void</span><span > main(String[] args) {
</span><span >new</span><span > TimerTest03();
}
}
public class TimerTaskTest03 extends TimerTask{
@Override
</span><span >public</span> <span >void</span><span > run() {
Date date </span>= <span >new</span> Date(<span >this</span><span >.scheduledExecutionTime());
System.out.println(</span>"本次执⾏该线程的时间为:" +<span > date);
}
}
运⾏结果:
本次执⾏该线程的时间为:Tue Jun 10 21:19:47 CST 2014
本次执⾏该线程的时间为:Tue Jun 10 21:19:49 CST 2014
本次执⾏该线程的时间为:Tue Jun 10 21:19:51 CST 2014
本次执⾏该线程的时间为:Tue Jun 10 21:19:53 CST 2014
本次执⾏该线程的时间为:Tue Jun 10 21:19:55 CST 2014
本次执⾏该线程的时间为:Tue Jun 10 21:19:57 CST 2014
.................
对于这个线程任务,如果我们不将该任务停⽌,他会⼀直运⾏下去。
对于上⾯三个实例,LZ只是简单的演⽰了⼀下,同时也没有讲解scheduleAtFixedRate⽅法的例⼦,其实该⽅法与schedule⽅法⼀样!
2.4、分析schedule和scheduleAtFixedRate
1、schedule(TimerTask task, Date time)、schedule(TimerTask task, long delay)
对于这两个⽅法⽽⾔,如果指定的计划执⾏时间scheduledExecutionTime<= systemCurrentTime,则task会被⽴即执⾏。scheduledExecutionTime不会因为某⼀个task的过度执⾏⽽改变。
2、schedule(TimerTask task, Date firstTime, long period)、schedule(TimerTask task, long delay, long period)
这两个⽅法与上⾯两个就有点⼉不同的,前⾯提过Timer的计时器任务会因为前⼀个任务执⾏时间较长⽽延时。在这两个⽅法中,每⼀次执⾏的task的计划时间会随着前⼀个task的实际时间⽽发⽣改变,
也就是scheduledExecutionTime(n+1)=realExecutionTime(n)+periodTime。也就是说如果第n个task由于某种情况导致这次的执⾏时间过程,最后导致systemCurrentTime>= scheduledExecutionTime(n+1)
,这是第n+1个task并不会因为到时了⽽执⾏,他会等待第n个task执⾏完之后再执⾏,那么这样势必会导致n+2个的执⾏实现scheduledExecutionTime放⽣改变即scheduledExecutionTime(n+2) = realExecutionTime(n+1)+periodTime。所以这两个⽅法更加注重保存间隔时间的稳定。
3、scheduleAtFixedRate(TimerTask task, Date firstTime, long period)、scheduleAtFixedRate(TimerTask task, long delay, long period)
中国过年习俗在前⾯也提过scheduleAtFixedRate与schedule⽅法的侧重点不同,schedule⽅法侧重保存间隔时间的稳定,⽽scheduleAtFixedRate⽅法更加侧重于保持执⾏频率的稳定。为什么这么说,原因如下。在schedule⽅法中会因为前⼀个任务的延迟⽽导致其后⾯的定时任务延时,⽽scheduleAtFixedRate⽅法则不会,如果第n个task执⾏时间过长导致systemCurrentTime>= scheduledExecutionTime(n+1),
则不会做任何等待他会⽴即执⾏第n+1个task,所以scheduleAtFixedRate⽅法执⾏时间的计算⽅法不同于schedule,⽽是scheduledExecutionTime(n)=firstExecuteTime +n*periodTime,该计算⽅法永远保持不变。所以scheduleAtFixedRate更加侧重于保持执⾏频率的稳定。
三、Timer的缺陷
3.1、Timer的缺陷
Timer计时器可以定时(指定时间执⾏任务)、延迟(延迟5秒执⾏任务)、周期性地执⾏任务(每隔个1秒执⾏任务),但是,Timer存在⼀些缺陷。⾸先Timer对调度的⽀持是基于绝对时间的,⽽不是
相对时间,所以它对系统时间的改变⾮常敏感。其次Timer线程是不会捕获异常的,如果TimerTask抛出的了未检查异常则会导致Timer线程终⽌,同时Timer也不会重新恢复线程的执⾏,他会错误的认为整个Timer线程都会取消。同时,已经被安排单尚未执⾏的TimerTask也不会再执⾏了,新的任务也不能被调度。故如果TimerTask抛出未检查的异常,Timer将会产⽣⽆法预料的⾏为。
1、Timer管理时间延迟缺陷
前⾯Timer在执⾏定时任务时只会创建⼀个线程任务,如果存在多个线程,若其中某个线程因为某种原因⽽导致线程任务执⾏时间过长,超过了两个任务的间隔时间,会发⽣⼀些缺陷:
public class TimerTest04 {
private Timer timer;
public long start;
</span><span >public</span><span > TimerTest04(){
</span><span >this</span>.timer = <span >new</span><span > Timer();
start </span>=<span > System.currentTimeMillis();
}
</span><span >public</span> <span >void</span><span > timerOne(){
timer.schedule(</span><span >new</span><span > TimerTask() {
</span><span >public</span> <span >void</span><span > run() {
System.out.println(</span>"timerOne invoked ,the time:" + (System.currentTimeMillis() -<span > start));
</span><span >try</span><span > {
Thread.sleep(</span>4000);  <span >//</span><span >线程休眠3000</span>
} <span >catch</span><span > (InterruptedException e) {
e.printStackTrace();
}
}
}, </span>1000<span >);
}
</span><span >public</span> <span >void</span><span > timerTwo(){
timer.schedule(</span><span >new</span><span > TimerTask() {
</span><span >public</span> <span >void</span><span > run() {
System.out.println(</span>"timerOne invoked ,the time:" + (System.currentTimeMillis() -<span > start));
}
}, </span>3000<span >);
}
</span><span >public</span> <span >static</span> <span >void</span> main(String[] args) <span >throws</span><span > Exception {  TimerTest04 test </span>= <span >new</span><span > TimerTest04();
test.timerOne();
test.timerTwo();
}
}
按照我们正常思路,timerTwo应该是在3s后执⾏,其结果应该是:
timerOne invoked ,the time:1001撩人小情话
白花蛇舌timerOne invoked ,the time:3001
但是事与愿违,timerOne由于sleep(4000),休眠了4S,同时Timer内部是⼀个线程,导致timeOne所需的时间超过了间隔时间,结果:
timerOne invoked ,the time:1000
timerOne invoked ,the time:5000
2、Timer抛出异常缺陷
如果TimerTask抛出RuntimeException,Timer会终⽌所有任务的运⾏。如下:
public class TimerTest04 {
private Timer timer;
</span><span >public</span><span > TimerTest04(){
</span><span >this</span>.timer = <span >new</span><span > Timer();
}
</span><span >public</span> <span >void</span><span > timerOne(){
timer.schedule(</span><span >new</span><span > TimerTask() {
</span><span >public</span> <span >void</span><span > run() {
</span><span >throw</span> <span >new</span><span > RuntimeException();
}
}, </span>1000<span >);
}
</span><span >public</span> <span >void</span><span > timerTwo(){
timer.schedule(</span><span >new</span><span > TimerTask() {
</span><span >public</span> <span >void</span><span > run() {
System.out.println(</span>"我会不会执⾏呢??"<span >);
}
}, </span>1000<span >);
}
</span><span >public</span> <span >static</span> <span >void</span><span > main(String[] args) {
TimerTest04 test </span>= <span >new</span><span > TimerTest04();
test.timerOne();
test.timerTwo();
}
}
运⾏结果:timerOne抛出异常,导致timerTwo任务终⽌。
Exception in thread "Timer-0" java.lang.RuntimeException
at com.chenssy.timer.TimerTest04$1.run(TimerTest04.java:25)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
对于Timer的缺陷,我们可以考虑 ScheduledThreadPoolExecutor 来替代。Timer是基于绝对时间的,对系统时间⽐较敏感,⽽ScheduledThreadPoolExecutor 则是基于相对时间;Timer是内部是单⼀线程,⽽ScheduledThreadPoolExecutor内部是个线程池,所以可以⽀持多个任务并发执⾏。
3.2、⽤ScheduledExecutorService替代Timer
1、解决问题⼀:
public class ScheduledExecutorTest {
private ScheduledExecutorService scheduExec;
</span><span >public</span> <span >long</span><span > start;
ScheduledExecutorTest(){
</span><span >this</span>.scheduExec = wScheduledThreadPool(2<span >);
</span><span >this</span>.start =<span > System.currentTimeMillis();
}
</span><span >public</span> <span >void</span><span > timerOne(){
scheduExec.schedule(</span><span >new</span><span > Runnable() {
</span><span >public</span> <span >void</span><span > run() {
System.out.println(</span>"timerOne,the time:" + (System.currentTimeMillis() -<span > start));
</span><span >try</span><span > {
Thread.sleep(</span>4000<span >);
} </span><span >catch</span><span > (InterruptedException e) {
e.printStackTrace();
}
}
},</span>1000<span >,TimeUnit.MILLISECONDS);
}
</span><span >public</span> <span >void</span><span > timerTwo(){
scheduExec.schedule(</span><span >new</span><span > Runnable() {
</span><span >public</span> <span >void</span><span > run() {
System.out.println(</span>"timerTwo,the time:" + (System.currentTimeMillis() -<span > start));
}
},</span>2000<span >,TimeUnit.MILLISECONDS);
}
</span><span >public</span> <span >static</span> <span >void</span><span > main(String[] args) {
ScheduledExecutorTest test </span>= <span >new</span><span > ScheduledExecutorTest();
test.timerOne();
test.timerTwo();
}
}
运⾏结果:
timerOne,the time:1003
timerTwo,the time:2005
2、解决问题⼆
public class ScheduledExecutorTest {
private ScheduledExecutorService scheduExec;
</span><span >public</span> <span >long</span><span > start;
ScheduledExecutorTest(){白菜煎豆腐
</span><span >this</span>.scheduExec = wScheduledThreadPool(2<span >);
</span><span >this</span>.start =<span > System.currentTimeMillis();
}
</span><span >public</span> <span >void</span><span > timerOne(){
scheduExec.schedule(</span><span >new</span><span > Runnable() {
</span><span >public</span> <span >void</span><span > run() {
</span><span >throw</span> <span >new</span><span > RuntimeException();
}
},</span>1000<span >,TimeUnit.MILLISECONDS);
上帝是个女孩
}
</span><span >public</span> <span >void</span><span > timerTwo(){
scheduExec.scheduleAtFixedRate(</span><span >new</span><span > Runnable() {
</span><span >public</span> <span >void</span><span > run() {
System.out.println(</span>"timerTwo invoked ....."<span >);
}
},</span>2000,500<span >,TimeUnit.MILLISECONDS);
}
</span><span >public</span> <span >static</span> <span >void</span><span > main(String[] args) {
ScheduledExecutorTest test </span>= <span >new</span><span > ScheduledExecutorTest();
test.timerOne();
test.timerTwo();
}
}
运⾏结果:
timerTwo invoked .....
timerTwo invoked .....
timerTwo invoked .....
timerTwo invoked .....
timerTwo invoked .....
timerTwo invoked .....
沉香是啥
timerTwo invoked .....
timerTwo invoked .....
timerTwo invoked .....
........................
到此这篇关于Java如何实现定时任务的⽂章就介绍到这了,更多相关Java定时任务内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!

本文发布于:2023-07-08 08:52:28,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/1085169.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:任务   线程   时间   指定   导致   安排
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图