Timer
类是 Java 提供的用于执行定时任务的工具类。它允许你安排任务在未来的某个时间点执行,也可以定期执行。下面是关于Timer
类的详细介绍:
一、主要特点
-
任务调度:
Timer
类允许你调度指定的任务在将来的某个时间执行,或者按照一定的时间间隔循环执行。 -
单线程执行任务:
Timer
内部维护一个后台线程,用于执行任务。这意味着所有任务都是由同一个线程来串行执行的,因此如果一个任务执行时间过长,会影响其他任务的执行。 -
多任务支持:
Timer
允许你安排多个任务执行。 -
异常处理:
Timer
会捕获任务抛出的未捕获异常,防止这些异常中断任务队列的执行流程。
二、应用场景
-
定时任务调度:适用于需要在特定时间执行任务的场景,比如定时数据备份、定时数据清理等。
-
定期任务执行:适用于需要按照一定的时间间隔重复执行任务的场景,如定时发送心跳、定期执行某些操作等。
三、基本用法
要使用Timer
类执行定时任务,通常需要创建一个继承自TimerTask
类的任务,并在Timer
对象中安排任务的执行时间。例如:
import java.util.Timer;
import java.util.TimerTask;
public class ScheduledTask extends TimerTask {
@Override
public void run() {
System.out.println("Task executed at: " + System.currentTimeMillis());
}
public static void main(String[] args) {
Timer timer = new Timer();
long delay = 1000; // 任务延迟1秒执行
long interval = 2000; // 任务每隔2秒执行一次
timer.scheduleAtFixedRate(new ScheduledTask(), delay, interval);
}
}
注意事项
-
线程安全性:由于
Timer
是基于单个后台线程执行任务的,需要注意任务执行时间过长可能会影响其他任务的执行。 -
异常处理:需要留意捕获任务抛出的异常,以免异常中断任务队列的执行流程。
-
Java 5 之后的替代方案:虽然
Timer
类已经存在很长时间,但在 Java 5 中ScheduledThreadPoolExecutor
被引入,通常被认为是Timer
的更灵活、更可控制的替代方案。
四、自己实现
import java.util.PriorityQueue;
public class MyTimer {
//内部类表示创建的任务
class Mytask implements Comparable<Mytask> {
private Runnable runnable;
// 为了⽅便后续判定, 使⽤绝对的时间戳.
private long time;
public Mytask(Runnable runnable, long delay) {
this.runnable = runnable;
// 取当前时刻的时间戳 + delay, 作为该任务实际执⾏的时间戳
this.time = System.currentTimeMillis() + delay;
}
//表示每个任务以到达时间以小到大排序
// 这样的写法意味着每次取出的是时间最⼩的元素.
@Override
public int compareTo(Mytask o) {
return (int)(this.time - o.time);
}
}
// 核⼼结构
private PriorityQueue<Mytask> queue = new PriorityQueue<>();
// 创建⼀个锁对象
private Object locker = new Object();
//构造方法,创建线程
Thread t;
public MyTimer() {
// 在这⾥构造线程, 负责执⾏具体任务了.
t = new Thread( () -> {
try {
while (!Thread.currentThread().isInterrupted()) {
synchronized (locker) {
// 阻塞队列, 只有阻塞的⼊队列和阻塞的出队列, 没有阻塞的查看队⾸元素
while (queue.isEmpty()) {
locker.wait();
}
Mytask task = queue.peek();
long waitTime = task.time - System.currentTimeMillis();
if (waitTime <= 0) {
// 时间到了, 可以执⾏任务了
queue.poll();
task.runnable.run();
} else {
// 时间还没到
locker.wait(waitTime);
}
}
}
}catch (InterruptedException e) {
e.printStackTrace();
}
});
t.start();
}
public void schedule(Runnable command, long after) {
synchronized (locker) {
Mytask mytack = new Mytask(command, after);
//根据参数,插入队列
queue.offer(mytack);
locker.notify();
}
}
//中断线程
public void cancel() {
t.interrupt();
for (Mytask task : queue) {
queue.remove(task);
}
}
// 测试代码
public static void main(String[] args) {
MyTimer timer = new MyTimer();
timer.schedule( ()->{
System.out.println(2000);
}, 2000);
timer.schedule( () -> {
System.out.println(1000);
}, 1000);
timer.schedule( ()->{
System.out.println(3000);
}, 3000);
System.out.println(100);
}
}