什么是定时器
- 定时器是多线程编程中的一个重要的组件
- 好比一个闹钟 定好一个时间让一个线程去执行
- 定时器在网络编程中特别常见
实现定时器需要什么
- 需要一个Task类来描述一段逻辑或者说是一个要执行的任务 同时要记录这个任务在啥时候执行
static class Task implements Comparable<Task> {
private Runnable command;
private long time;
public Task(Runnable command, long after) {
this.command = command;
this.time = System.currentTimeMillis() + after;
}
public void run() {
command.run();
}
@Override
public int compareTo(Task o) {
return (int) (this.time - o.time);
}
}
- 需要使用一个阻塞优先级队列组织所有的任务 判断谁先执行 谁后执行
static class Timer {
private final Object mailBox = new Object();
private PriorityBlockingQueue<Task> queue = new PriorityBlockingQueue<>();
public Timer() {
Worker worker = new Worker(queue, mailBox);
worker.start();
}
public void schedule(Runnable command, long after) {
Task task = new Task(command, after);
queue.put(task);
synchronized (mailBox) {
mailBox.notify();
}
}
}
- 还需要一个扫描线程 循环扫描判断队列的队首元素是不是到时间了需要执行了 如果需要执行了就执行该任务
static class Worker extends Thread {
private PriorityBlockingQueue<Task> queue;
private final Object mailBox;
public Worker(PriorityBlockingQueue<Task> queue, Object mailBox) {
this.queue = queue;
this.mailBox = mailBox;
}
@Override
public void run() {
while (true) {
try {
Task task = queue.take();
long curTime = System.currentTimeMillis();
if (task.time > curTime) {
queue.put(task);
synchronized (mailBox) {
mailBox.wait(task.time - curTime);
}
} else {
task.run();
}
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
}
完整代码+测试
import java.util.concurrent.PriorityBlockingQueue;
public class Timer {
private final Object loker = new Object();
private PriorityBlockingQueue<Task> blockingQueue = new PriorityBlockingQueue<>();
public Timer() {
Worker worker = new Worker(blockingQueue, loker);
worker.start();
}
public void schedule(Runnable runnable, long time) {
Task task = new Task(runnable, time);
blockingQueue.put(task);
synchronized (loker) {
loker.notify();
}
}
}
class Task implements Comparable<Task> {
private Runnable runnable;
private long time;
public Task(Runnable runnable, long after) {
this.runnable = runnable;
this.time = System.currentTimeMillis() + after;
}
public void run() {
runnable.run();
}
public long getTime() {
return time;
}
@Override
public int compareTo(Task o) {
return (int) (this.time - o.time);
}
}
class Worker extends Thread {
private PriorityBlockingQueue<Task> blockingQueue;
private final Object loker;
public Worker(PriorityBlockingQueue<Task> blockingQueue, Object loker) {
this.blockingQueue = blockingQueue;
this.loker = loker;
}
@Override
public void run() {
while (true) {
try {
Task task = blockingQueue.take();
long curTime = System.currentTimeMillis();
if (task.getTime() > curTime) {
blockingQueue.put(task);
synchronized (loker) {
loker.wait(task.getTime() - curTime);
}
} else {
task.run();
}
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
}
public class TestTimer {
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new Runnable() {
@Override
public void run() {
System.out.println("haha");
timer.schedule(this, 2000);
}
}, 2000);
}
}
- 结果便是每俩秒输出一个haha