企业网站设计与优化,公司注册名字怎么取,卓越职业院校建设专题网站,网站建设与管理淘宝IDE#xff1a;IntelliJ IDEA 2022.2.3 x64 操作系统#xff1a;win10 x64 位 家庭版 JDK: 1.8 文章目录 一、Timer类是什么#xff1f;二、Timer类主要由哪些部分组成#xff1f;1.TaskQueue2. TimerThread 三、示例代码分析四、自定义TimerTask为什么会发生任务相互阻塞的… IDEIntelliJ IDEA 2022.2.3 x64 操作系统win10 x64 位 家庭版 JDK: 1.8 文章目录 一、Timer类是什么二、Timer类主要由哪些部分组成1.TaskQueue2. TimerThread 三、示例代码分析四、自定义TimerTask为什么会发生任务相互阻塞的问题4.1 使用schedule添加任务如任务执行超时会导致任务丢失少执行4.2 使用scheduleAtFixedRate添加任务如任务执行超时会导致任务执行时间乱掉下一个任务会马上执行 五、Timer类的应用特性六、如何解决任务阻塞问题 提示以下是本篇文章正文内容下面案例可供参考
一、Timer类是什么
Java Timer类是一个用于调度任务的类它可以在指定的时间间隔内执行一次或多次任务。它提供了一种简单的方式来安排和执行定时任务可以用于各种应用程序中如计划任务、定时器等。
Java Timer类位于java.util包中它有两个主要的子类Timer和TimerTask。其中Timer类用于调度任务而TimerTask类则表示一个具体的任务需要实现run()方法来定义任务的具体行为。
使用Java Timer类可以方便地创建和管理定时任务但需要注意的是它的精度有限如果需要更高精度的任务调度可以考虑使用ScheduledThreadPoolExecutor等其他工具。 二、Timer类主要由哪些部分组成 1.TaskQueue
官方解释 The timer task queueThis 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. 一句话就是一个用于存储和处理任务的队列里面存放TimeTask 2. TimerThread
官方解释 The timer thread. 显而易见就是处理线任务的线程 三、示例代码分析
示例代码如下所示
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;public class myTimerTest {public static void main(String[] args){Timer timer new Timer(); //任务执行for (int i 0; i 2 ; i) {TimerTask timerTask new FooTimerTask(FooTimerTaski);//将timerTask以当前时间执行以2秒时间为间隔再次触发即120000执行那么120002 会再次触发执行timer.schedule(timerTask,new Date(),2000);//任务添加}}
}class FooTimerTask extends TimerTask {private String name;public FooTimerTask(String name) {this.name name;}Overridepublic void run() {try {System.out.println(name - startTime new Date());//延迟3秒执行Thread.sleep(3000);System.out.println(name - endTime new Date());} catch (InterruptedException e) {e.printStackTrace();}}
}
注意 其中任务会在 Timer timer new Timer();时执行而并非大家认为的在timer.schedule(timerTask,new Date(),2000);时执行该代码是将该timerTask添加到TaskQueue中任务队列中 不信请看如下的源代码
①在new Timer()时执行任务 ②在timer.schedule(timerTask,new Date(),2000)时添加任务至任务队列中 通过上述源代码演示Timer类是在new Timer()中以多线程的方式运行TimerThread的start()方法进而调用其中的run()方法。而我们自子自定义的FooTimerTask 的run()方法却是以单线程的方式被调用。 在TimerThread中的run方法中mainLoop方法里以死循环不断检查是否有任务需要开始执行了有就执行它执行任务也是用这个线程执行。 何以见得
在mainLoop方法中 我们自定义的FooTimerTask会以单线程的方式执行这样任务可能会相互阻塞 四、自定义TimerTask为什么会发生任务相互阻塞的问题
4.1 使用schedule添加任务如任务执行超时会导致任务丢失少执行
示例代码如下所示
public class myTimerTest {public static void main(String[] args){Timer timer new Timer(); //任务执行for (int i 0; i 2 ; i) {TimerTask timerTask new FooTimerTask(FooTimerTaski);//将timerTas以当前时间执行间隔2s后触发执行比如在120000执行timerTas下一次触发就是120002时执行余者类推timer.schedule(timerTask,new Date(),2000);//任务添加}}
}class FooTimerTask extends TimerTask {private String name;public FooTimerTask(String name) {this.name name;}Overridepublic void run() {try {System.out.println(name - startTime new Date());//延迟3秒执行Thread.sleep(3000);System.out.println(name - endTime new Date());} catch (InterruptedException e) {e.printStackTrace();}}
}示例运行如下 这里有个问题根据上述代码定义自定义timerTask会在间隔2s后执行而timerTask自己的执行会延迟3s才会真正结束那么我们所推测它的执行场景应该是这样的 假如任务A在120000开始执行120003执行结束那么下一个任务B将会在120005开始执行 但上述代码的运行结果却与我们的推测 大相径庭
思考① 那如果timerTask去掉延迟3s的代码运行结果应该是如“任务A在120000开始执行12000执行结束那么下一个任务B将会在120003开始执行”这样执行吧 代码示例如下
class FooTimerTask extends TimerTask {private String name;public FooTimerTask(String name) {this.name name;}Overridepublic void run() {System.out.println(name - startTime new Date());System.out.println(name - endTime new Date());
// try {
// System.out.println(name - startTime new Date());
// //延迟3秒执行
// Thread.sleep(3000);
// System.out.println(name - endTime new Date());
// } catch (InterruptedException e) {
// e.printStackTrace();
// }}
}运行如下 看来任务阻塞的问题就出现在延迟3s的代码上
思考② 如果一个任务本身执行时间过长超过预设的时间间隔即任务执行超时为什么会发生任务阻塞的问题 任务阻塞问题会导致后面的任务往后推移预想在这个间隔内存在的任务执行就没了任务少执行了【假如在10s的时间段内任务正常执行5次假如发生任务超时可能会执行3-4次】
通过如下追踪源代码可知
①追踪进入schedule()方法中 注意schedule方法将period值加了负号即-period ②追踪进入sched()方法中 任务task的nextExecutionTime被赋值为time传入的时间 ③追踪进入run()方法中的mainLoop()方法中
④追踪进入queue.rescheduleMin()方法中 ⑤追踪进入fixDown()方法中
结论 由此可知schedule里Timertask真正的执行时间取决上一个任务的结束时间并非以预设的时间为准故如某一个任务执行超时则有可能出现任务丢失的问题 4.2 使用scheduleAtFixedRate添加任务如任务执行超时会导致任务执行时间乱掉下一个任务会马上执行
示例代码如下所示
public class myTimerTest {public static void main(String[] args){Timer timer new Timer(); //任务执行for (int i 0; i 2 ; i) {TimerTask timerTask new FooTimerTask(FooTimerTaski);timer.scheduleAtFixedRate(timerTask,new Date(),2000);}}
}class FooTimerTask extends TimerTask {private String name;public FooTimerTask(String name) {this.name name;}Overridepublic void run() {try {System.out.println(name - startTime new Date());//延迟3秒执行Thread.sleep(3000);System.out.println(name - endTime new Date());} catch (InterruptedException e) {e.printStackTrace();}}
}
运行如下 思考 为什么一旦任务发生超时下一个任务会马上触发执行 通过如下追踪源代码可知
①追踪进入schedule()方法中
②追踪进入sched()方法中 任务task的nextExecutionTime被赋值为time传入的时间 ③追踪进入run()方法中的mainLoop()方法中 注剩余追踪步骤和4.1小节一致故不予展示 结论 scheduLeAtFixedRate()方法会严格按照预设时间作为TimerTask的执行时间如果发生任务超时下一个任务会直接触发 五、Timer类的应用特性
运行时异常会导致timer线程终止任务调度是基于绝对时间的对系统时间敏感 六、如何解决任务阻塞问题
解决方案 在自定义TimerTask里的run()方法里使用线程池去执行即可解决上述问题