目录
目录
定时器是软件开发的一个重要组件,当到达规定的时刻后,执行某个特定的任务。
一.定时器的使用
1.schedule方法
java标准库实现了定时器类 --- Timer。如下代码:
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new TimerTask(){
@Override
public void run() {
System.out.println(1);
}
},3000);
}
此代码的结果是:安排了一个任务,在程序开始执行的三秒后,打印 1。
Timer类核心的方法就是schedule(),作用是给定时器安排什么任务,以及执行的时间,此方法包含了两个参数,第一个参数TimerTask继承了Runnable接口,可以认为TimerTask就代表了一个任务清单,第二和参数则是指定的时间。
2.四个重载方法
schedule重载了四个方法:
public void schedule(TimerTask task, long delay) delay单位为毫秒,执行到此处代码的delay毫秒后,执行任务。 public void schedule(TimerTask task, Date time) 当时间达到time时,执行任务。 public void schedule(TimerTask task, long delay, long period) 执行到此处代码的delay毫秒后,第一个执行任务,此后每过period毫秒的时间间隔执行一次。 public void schedule(TimerTask task, Date firstTime, long period) 时间达到firstTime时,执行任务,此后每过period毫秒的时间间隔执行一次。
二.实现一个定时器
如果要实现一个定时器,我们必须要实现一个任务类,此类实现Runnable接口,然后还必须要有一个数据结构来存放这些任务,那么这里就可以用优先级队列来实现,并按时间来排序,这样队首元素则是时间最接近的任务。
这里还有一个非常重要的问题,我们必须额外创建一个线程,因为定时器是会自动在到达某一时间时,执行规定任务的,这就要有一个扫描线程不断的检查是否到时间,只要队首的任务到执行时间,就执行任务。
那么大致框架已明确,代码如下:
class MyTask implements Comparable<MyTask>{
private long time;
private Runnable runnable;
public MyTask(){
}
public MyTask(Runnable runnable,long time){
this.time = time;
this.runnable = runnable;
}
public void run(){
runnable.run();
}
public long getTime() {
return time;
}
@Override
public int compareTo(MyTask o) {
return (int)(this.time - o.time);
}
}
class MyTimer{
private Thread t = null;
//使用优先级的阻塞队列来存放任务。
private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();
public MyTimer() throws InterruptedException {
t = new Thread(()->{
while(true){
try {
synchronized (this){//1.由于存在notify了但是还没wait的情况,要加锁
MyTask task = queue.take();
long time = task.getTime();
if(time > System.currentTimeMillis()){
queue.put(task);
this.wait(time - System.currentTimeMillis());
}else{
task.run();
}
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.start();
}
//安排任务,
public void schedule(Runnable runnable, long time){
MyTask readingTask = new MyTask(runnable,System.currentTimeMillis()+time);
queue.put(readingTask);
synchronized (this){//当有新任务加入,就唤醒扫描线程。
this.notify();
}
}
}
以上就是本文的全部内容了。