本文主要详细介绍Java定时器Timer的用法。本文中的示例代码非常详细,具有一定的参考价值。感兴趣的朋友可以参考一下。
目录
摘要简单来说,定时器就相当于一个“闹钟”,给定时器设定一个任务,约定这个任务在xxx时间之后执行~
Timer类提供了一个核心接口。schedule指定一个任务给定时器,一定时间后再执行任务~
如何实现定时器的效果~
Timer应该包含一个任务类,每个任务代表一个特定的任务实例。任务包含一个时间戳(当任务被执行时)和一个可运行的实例(用于指示任务是什么)。
定时器通过优先级阻塞队列被组织成一个任务。
在这里,优先级是按照时间的顺序排列的,即将到达时间的任务优先级更高。
也就是在堆中加入wait/notify,这样可以起到阻塞的作用。
标准库提供了这样一个队列,PriorityBlockingQueue。
Timer还需要一个特殊的线程,不断扫描队列头元素,看是否可以执行。如果可以执行,就执行,否则继续在队列中等待。
具体如何用代码实现这样一个定时器Timer:
一般在设置时间的时候,入局时间是一个时间间隔。
例如:传入1000 ,就代表从当前开始过1000ms之后在执行;
而这里,为了下面代码的方便,我在这里记录了绝对时间,这样this.time就是一个标志的ms级时间戳。在后续中,我只需要获取当前时间戳,并与这里的时间进行比较。
任务应该放在优先级队列中,但是优先级需要在优先级队列中进行比较,因此任务类可以实现compare接口并重写compareTo方法进行比较。
在这里,我希望较短的时间线会满足。
这里,获取当前时间currTime。如果当前时间大于或等于任务中的约定时间,则在规定时间后完成,否则,将其移除。
将任务放回队列,继续等待。
这里还涉及到一个问题:
例如,如果你把闹钟设在早上8:30,你在8:00醒来,检查时间,在它到来之前你又回去睡觉。
但这里是while(真),意思是你要每秒钟看一次闹钟,8.01,8.02,这样会白白浪费一些资源,导致“瞎等”。在等待任务时间的过程中,你一直掌握着CPU资源~
所以这里需要优化一下:使用等待/通知机制可以改善盲目性等问题~
如果发现还没到出任务的时候,就等一等,等一定时间。这里使用的重载版wait()在wait()中写一个参数,达到等待时间自动唤醒~此时扫描次数和成本大大降低。
这里的notify()是为了确保如果有一个线程处于等待状态,它需要唤醒这个线程。
举个例子;
如果正在执行组长元素8.30,等待30分钟,但是这个时候可能会突然插入一个任务让你做8.10的事情。如果8.30再醒来,8.10的任务就来不及了!
所以每次插入新任务的时候,唤醒woeker线程,让worker线程重新获得queue leader元素,看看等待下一个任务多长时间合适。
//简单计时器
公共类TestTimer {
//每个任务实例包含一个要执行的任务
//任务应该放在优先级队列中,但是优先级需要在优先级队列中进行比较。
静态类任务实现ComparableTask{
//什么时候执行?
私人时间长;
//执行什么任务?
私有Runnable命令;
公共任务(Runnable命令,长时间){
this.command=命令;
this . time=system . current time millis()time;
}
公共无效运行(){
//执行Runable中的run方法。
命令. run();
}
@覆盖
公共int compareTo(任务o) {
return(int)(this . time-o . time);
}
}
静态类别计时器{
//首先创建一个优先级阻塞队列
private PriorityBlockingQueueTask queue=new PriorityBlockingQueue();
//使用此对象完成线程间的协调任务
私有对象mei lbox=new Object();
//调度方法是将一个任务放入定时器中。
公共无效计划(Runnable命令,长时间后){
Task task=新任务(命令,之后);
//将当前任务放在相对的列中
queue.put(任务);
//当工作线程包含等待机制时,调度任务时需要唤醒。
同步(meibox){
meibox . notify();
}
}
//编写一个构造函数来创建线程
公共计时器(){
//创建一个线程,让这个线程扫描队列的第一个元素,看是否可以执行。
线程工作线程=新线程(){
@覆盖
公共无效运行(){
//取出队列头的元素,判断这个元素是否可以执行。
while(true){
尝试{
task task=queue . take();
long curr time=system . current time millis();
if(currTime=task.time){
//时间到了,执行任务
task.run()。
}否则{
//时间还没到,继续等
queue.put(任务);
同步(meibox){
mei lbox . wait(task . time-curr time);
}
}
} catch (InterruptedException e) {
e . printstacktrace();
}
}
}
};
worker . start();
}
}
}
测试:
公共静态void main(String[] args) {
Timer Timer=new Timer();
Runnable command=new Runnable() {
@覆盖
公共无效运行(){
System.out.println('时间到了~ ');
//timer.schedule(这个,3000);每3小时执行一次。
}
};
System.out.println('调度任务');
timer.schedule(命令,3000);
}
}
任务安排好之后,等待3s才可以执行。
下面是定时器原生类型中的一些方法。
Schedule (TimerTask task,date time)在指定日期执行一次TimerTask任务。如果日期时间早于当前时间,将立即执行。
Schedule (TimerTask Task,Long Delay,Long Period)以当前时间为基准,延迟指定的毫秒数,然后以指定的时间间隔无限期执行TimerTask任务。
Schedule (TimerTask任务,日期第一次,长周期)在指定日期后的指定时间间隔内无限期执行TimerTask任务。
ScheduleatFixedRate(TimerTask task,long delay,long period)以当前时间为基准,延迟指定的毫秒数,然后以指定的时间间隔周期性地无限执行TimerTask任务。
总结
本文到此为止。希望能帮到你,也希望你能多关注我们的更多内容!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。