@TOC 什么是定时器 定时器是多线程编程中的一个重要的组件 好比一个闹钟 定好一个时间让一个线程去执行 定时器在网络编程中特别常见 比如: 在我们打开浏览器,随便打开一个网页
@TOC
什么是定时器
- 定时器是多线程编程中的一个重要的组件
- 好比一个闹钟 定好一个时间让一个线程去执行
- 定时器在网络编程中特别常见
比如:
在我们打开浏览器,随便打开一个网页如果顺利,马上就能进入网站
但是!有时候由于网络不稳定,或者网站的服务器崩了。那么,此时这里就会一直转圈圈加载。但是浏览器不会一直都在这里等待访问的网站反馈信息。它里面其实有一个等待 的“超时时间”,过了这个时间,它就不会再等待,直接跟你说“访问失败 / 网站不见了”
此时我们很快就能想到 join,有一个用法,在括号里添加指定的 “超时时间”。sleep也可以达到这个效果,sleep(指定休眠时间) 。join 和 sleep 都是基于系统内部的定时器,来实现的
那么,我们就可以使用 代码中的定时器,来实现类似的功能。
先介绍标准库的定时器用法,然后再看看如何自己实现一个定时器
标准库的定时器用法
Timer <-----> java.util.Timer
核心方法 :schedule
schedule,它的功能就跟 它 中文意思一样。每调用一次 schedule‘,就会给定时器 安排一个任务。通过这个方法,就可以把 任务 注册到 定时器内部。而计数器内部是支持 注册 多个任务的。
schedule方法,有两个参数:
任务
多长时间之后执行
如何自己实现一个定时器
一个问题:Timer 类 的内部需要什么东西?
从Timer 的 工作内容入手
管理很多的任务
执行时间到了的任务
管理任务又可以细分为 2个:
1、描述任务(创建一个专门的类来表示一个定时器中的任务【Timer Task】)2、组织任务(使用一定的数据及结构进行组织数据,把一些任务放到一起。) 具体任务顺序为1、描述任务(创建一个专门的类来表示一个定时器中的任务【Timer Task】)2、组织任务(使用一定的数据及结构进行组织数据,把一些任务放到一起。)3、执行时间到了的任务
1. 描述任务
// 创建一个类,来描述一个具体的任务
class MyTask{
// 任务具体要做什么
private Runnable runnable;
// 任务具体的执行时间:保存任务要执行的毫秒级时间戳
private long time;
// after 是一个时间间隙,不是绝对的时间戳的值
public MyTask(Runnable runnable,long after){
this.runnable = runnable;
// 很简单,意思就是从当前时间开始, after 秒之后,这个任务被执行。
this.time = System.currentTimeMillis()+after;
}
// 通过调用这里 run方法,来执行我们任务具体要做什么
public void run(){
runnable.run();
}
}
2. 组织任务
3. 执行时间到了的任务
需要先执行时间最靠前的任务
比如:十分钟后,大家去休息一下。但是,当前的我们无法判断这个时间,所以我们需要用一个线程去不断的去检查当前优先队列的首元素,看看当前最靠前的这个任务是不是时间到了
通过 自己构造的 Mytimer 计时器类 的 构造方法。创建一个线程,帮助我们来进行一个检查
上述代码中存在两个非常严重的问题!!!
代码
import java.util.concurrent.PriorityBlockingQueue;
// 创建一个类,来描述一个具体的任务
class MyTask implements Comparable<MyTask>{
// 任务具体要做什么
private Runnable runnable;
// 任务具体的执行时间:保存任务要执行的毫秒级时间戳
private long time;
// after 是一个时间间隙,不是绝对的时间戳的值
public MyTask(Runnable runnable,long after){
this.runnable = runnable;
// 很简单,意思就是从当前时间开始, after 秒之后,这个任务被执行。
this.time = System.currentTimeMillis()+after;
}
// 通过调用这里 run方法,来执行我们任务具体要做什么
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 PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();
public void schedule(Runnable runnable,long after){
MyTask task = new MyTask(runnable,after);
queue.put(task);
synchronized(locker){
locker.notify();
}
}
private Object locker = new Object();
public MyTimer(){
Thread t = new Thread(()->{
while(true){
try {
// 取出队首元素
MyTask task =queue.take();
//再比较一下看看当前这个任务时间到了没
long curTime = System.currentTimeMillis();
// 拿当前时间 和 任务执行时间进行比较
if(curTime < task.getTime()){
//时间还没到,把任务再塞回到队列中
queue.put(task);
// 指定一个等待时间
synchronized(locker){
locker.wait(task.getTime() - curTime);
}
}else{
// 时间到了,执行这个任务
task.run();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
}
}
public class Test25 {
public static void main(String[] args) {
MyTimer myTimer = new MyTimer();
myTimer.schedule(new Runnable() {
@Override
public void run() {
System.out.println("hello timer");
}
},3000);
System.out.println("main");
}
}