一、定时器的应用场景:
浏览器内部就有一个定时器,发送了请求之后,定时器就开始计时,如果在规定的时间内,响应数据没有返回,那么定时器时间到,就会终止这样的请求。
二、自己实现一个简单版本的定时器
定时器的构成:
1.使用一个 Task 类来描述 “一段逻辑”(一个要执行的任务),同时也要记录这个任务在什么时候来执行
2.使用一个 阻塞优先队列 来组织若干Task
阻塞优先队列:既支持阻塞的特性,又支持按优先级的“先进先出”,本质上是一个“堆”。
此处使用优先队列是为了保证队首元素就是那个最早要被执行的任务。判断当前队列中是否有任务时间到了,需要执行,只需要判断队首元素是否到时间即可。
3.还需要一个扫描线程,扫描线程要循环的检测队首元素是否需要执行,如果需要执行的话,就执行这个任务。
java.util.concurrent这个包
PriorityBlockingQueue其中阻塞优先队列就在这个包中
package com.itbit.BlockingQueue6;
import java.util.concurrent.PriorityBlockingQueue;
/**
* @program: Thread
* @description
* @author: wenwen
* @create: 2021-08-02 12:36
**/
public class Timer {
//优先队列中的元素必须是可比较的
//比较规则的指定主要是两种方式:
//1.让 Task 实现Comparable接口
//2.让优先队列构造的时候,传入一个比较器对象(Comparator)
static class Task implements Comparable<Task>{
//Runnable中有一个run方法,就可以借助这个run方法来描述要执行的任务是什么
private Runnable command;
//time表示什么时候执行command
private long time;
//time表示什么时候来执行command,是一个绝对时间(ms级别的时间戳)
//构造方法的参数表示:多少毫秒之后执行(相对时间),这个相对时间的参数是为了用起来方便
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 Worker extends Thread{
private PriorityBlockingQueue<Task> queue = null;
public Worker(PriorityBlockingQueue<Task> queue){
this.queue =queue;
}
public void run(){
//实现具体的线程执行的内容
while(true){
//取出队首元素,检查时间是否到了
try {
Task task = queue.take();
long curTime = System.currentTimeMillis();
//2.检查当前任务时间是否到了
if(task.time > curTime){
//时间还没到,就把任务塞回队列中
queue.put(task);
}else{
task.run();
}
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
}
static class TimerDemo{
//定时器的基本构成,有三部分
//1.用一个类来描述“任务”
//2.用一个阻塞优先队列来组织若干任务,让队首元素就是时间最早的任务
// 如果队首元素时间未到,那么其他元素也肯定不能执行
private PriorityBlockingQueue<Task> queue = new PriorityBlockingQueue<>();
//3.用一个线程来循环扫描当前的阻塞队列的队首元素,如果时间到,就执行指定的任务
public TimerDemo(){
//创建线程
Worker worker = new Worker(queue);
worker.start();
}
//4.还需要提供一个方法,让调用者能把任务“安排”进来
//schedule =》安排
public void schedule(Runnable command,long after){
Task task = new Task(command,after);
queue.put(task);
}
}
public static void main(String[] args) {
TimerDemo timerDemo = new TimerDemo();
timerDemo.schedule(new Runnable() {
@Override
public void run() {
System.out.println("hehe");
timerDemo.schedule(this,2000);
}
},2000);
}
}