文章目录
- 一、定时器
- Timer类和TimerTask类
- 如何使用?
- 二、自己实现一个定时器
- 定时器原理
- 代码实现
提示:以下是本篇文章正文内容,Java系列学习将会持续更新
一、定时器
Timer类和TimerTask类
Timer定时器主要用于做定时任务或者按照一定的时间间隔做循环任务。
java.util.Timer 作为定时器,用于启动定时任务。
java.util.TimerTask 实现了Runnable接口,需要重写**run()**方法,用于盛放我们要做的任务。
注意:
①一个Timer定时器只会开启一个新线程。
②一个Timer定时器可以开启多个TimerTask定时任务,但这些任务只是在同一个线程下轮流执行的。
如何使用?
// 创建一个定时器
Timer timer = new Timer();
// 创建一个定时任务
TimerTask timerTask = new TimeTask() {
@Override
public void run() {
System.out.println("闹钟响了");
}
};
// 延时1000ms后开始,每隔3000ms执行一次
timer.schedule(task, 1000, 3000);
// 启动定时任务的方法
timer.schedule(TimerTask task, long delay);
timer.schedule(TimerTask task, long delay, long period);
回到目录…
二、自己实现一个定时器
定时器原理
①其中 TaskQueue 是一个平衡二叉树堆实现的优先级队列,每个 Timer 对象内部有唯一一个 TaskQueue 队列。用户线程调用 timer 的 schedule 方法就是把 TimerTask 任务添加到 TaskQueue 队列,在调用 schedule 的方法时候 long delay 参数用来说明该任务延迟多少时间执行。
②TimerThread 是具体执行任务的线程,它从 TaskQueue 队列里面获取优先级最小的任务进行执行,需要注意的是只有执行完了当前的任务才会从队列里面获取下一个任务而不管队列里面是否有已经到了设置的 delay 时间,一个 Timer 只有一个 TimerThread 线程,所以可知 Timer 的内部实现是一个
多生产者单消费者模型。
代码实现
我的定时器
import java.util.concurrent.PriorityBlockingQueue;
public class MyTimer {
// 存放延时任务的优先级队列
private final PriorityBlockingQueue<MyTimerTask> queue = new PriorityBlockingQueue<>();
// 定义一个锁
private final Object newTaskComing = new Object();
public MyTimer() {
// 开始实施任务
Worker worker = new Worker();
worker.start();
}
// 定时器的启动方法
public void schedule(MyTimerTask task, long delay) {
// 该方法非工作线程调用
task.runAt = System.currentTimeMillis() + delay;
queue.put(task);
synchronized (newTaskComing) {
// 唤醒优先级最高的任务
newTaskComing.notify();
}
}
// 实际上实施任务的线程类
class Worker extends Thread {
@Override
public void run() {
while (true) {
// 先从队列中获取任务
MyTimerTask task = null;
try {
task = queue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
// task 应该有个应该执行的时刻(不能记录 delay)
long now = System.currentTimeMillis();
long delay = task.runAt - now;
if (delay <= 0) {
task.run();
} else {
try {
// 应该在两种条件下醒来:
// 1. 有新的任务过来了(任务可能比当前最小的任务更靠前)
// 2. 没有新任务来,但到了该执行该任务的时候了
synchronized (newTaskComing) {
newTaskComing.wait(delay);
}
// 如果当前时间已经在要执行任务的时间之后了
// 说明任务的执行时间已过,所以应该去执行任务了
// 否则,先把这个任务放回去(因为时间还没到),再去取最小的任务
if (System.currentTimeMillis() >= task.runAt) {
task.run();
} else {
queue.put(task);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
任务类
public abstract class MyTimerTask implements Comparable<MyTimerTask> {
long runAt; // 这个任务应该在何时运行(记录为 ms 为单位的时间戳)
abstract public void run();
@Override
public int compareTo(MyTimerTask o) {
if (runAt < o.runAt) {
return -1;
} else if (runAt > o.runAt) {
return 1;
} else {
return 0;
}
}
}
回到目录…
总结:
提示:这里对文章进行总结:
以上就是今天的学习内容,本文是Java多线程的学习,认识了定时器Timer,定时器的用法;以及深入了解了定时器的实现原理。之后的学习内容将持续更新!!!