当前位置:网站首页>多线程案例——定时器
多线程案例——定时器
2022-08-09 09:34:00 【Living_Amethyst】
定时器是什么
定时器
也是软件开发中的一个重要组件. 类似于一个 “闹钟”. 达到一个设定的时间之后, 就执行某个指定好的代码.
定时器是一种实际开发中非常常用的组件.
比如网络通信中, 如果对方 500ms 内没有返回数据, 则断开连接尝试重连.
比如一个 Map, 希望里面的某个 key 在 3s 之后过期(自动删除).
类似于这样的场景就需要用到定时器
标准库中的定时器
- 标准库中提供了一个 Timer 类. Timer 类的核心方法为 schedule .
- schedule 包含两个参数. 第一个参数指定即将要执行的任务代码, 第二个参数指定多长时间之后
执行 (单位为毫秒).
示例:
public static void main(String[] args) {
// java.util 里的一个组件
Timer timer = new Timer();
//schedule这个方法的效果 是 “安排一个任务”
//不是立刻执行 而是3000毫秒之后执行
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("这是一个要执行的任务");
}
},3000);
}
模拟实现定时器
很多细节的解析再注释中注明
//模拟实现 定时器
import java.util.PriorityQueue;
import java.util.concurrent.PriorityBlockingQueue;
class MyTask implements Comparable<MyTask>{
//任务要干啥
private Runnable command;
//任务啥时候干
private long time; //绝对时间
public MyTask (Runnable command,long after){
this.command = command;
//此处记录的时间是一个绝对的时间戳,不是多长时间后执行
this.time = System.currentTimeMillis()+after;
}
//执行任务的方法 直接在内部调用 Runnable 的 run 即可
public void run(){
command.run();
}
public long getTime() {
return time;
}
@Override
public int compareTo(MyTask o) {
//希望时间小的在前 大的在后
return (int) (this.time - o.time);
}
}
class MyTimer {
//用来阻塞等待的锁对象
private Object locker = new Object();
//使用优先级队列来保存若干个任务
private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();
// command:要执行的任务是啥
// after:多长时间之后执行这个任务
public void schedule(Runnable command,long after) {
MyTask myTask = new MyTask(command,after);
// 防止 新插入的任务 比之前队首的任务的时间还早,需要唤醒
synchronized (locker){
queue.put(myTask); //把加入操作也加锁
locker.notify();
}
}
public MyTimer(){
// 启动一个线程
Thread t = new Thread(()->{
while (true){
//循环过程中 不断尝试从队列中获取到队首元素
//判定队首元素当时的时间是否就绪,就绪了就执行 不就绪就不执行
try {
synchronized (locker) {
MyTask myTask = queue.take();//取的是队首元素,时间最早的任务
long curTime = System.currentTimeMillis();
if (myTask.getTime() > curTime) {
//时间还没到
queue.put(myTask); //把任务再放回队列
//队首的(最早执行的)元素时间还没到,需要等待,不然一直循环 CPU空转 内耗
locker.wait(myTask.getTime() - curTime);
} else {
//时间到了 执行任务
myTask.run();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
}
}
public class Demo18 {
public static void main(String[] args) {
MyTimer myTimer = new MyTimer();
myTimer.schedule(new Runnable() {
@Override
public void run() {
System.out.println("111");
}
},2000);
myTimer.schedule(new Runnable() {
@Override
public void run() {
System.out.println("222");
}
},4000);
myTimer.schedule(new Runnable() {
@Override
public void run() {
System.out.println("333");
}
},6000);
}
}
边栏推荐
- latex中复杂公式换行等号对齐
- class object property method class member
- makefile学习-解决目标文件输出路径问题
- "The camera can't be used" + win8.1 + DELL + external camera + USB drive-free solution
- What is the reason for the suspended animation of the migration tool in the GBase database?
- Ontology development diary 02 - simple sparql query
- 软件测试面试题目:请你列举几个物品的测试方法怎么说?
- Golang Protobuf 处理
- 命令行查询数据库
- Cisco common basic configuration of common commands
猜你喜欢
随机推荐
Sweet alert
用户设备IP三者绑定自动上号
How much do you know about the mobile APP testing process specifications and methods?
3.编码方式
Another implementation of lateral view explode
7.Collections tool class
unix环境编程学习-多线程
【面试体系知识点总结】---JVM
6. The File types
列表
米斗APP逆向分析
mysql 修改密码和忘记密码操作
批量修改Shapefile属性表的一种方法(使用gdal.jar)
MySQL关于表的知识点,进来学习!
Ontology Development Diary 01-Jena Configuration Environment Variables
软件测试面试题目:请你列举几个物品的测试方法怎么说?
static_assert报错为什么?
BlockingQueue理论普
2. Thread creation
实用小技能:一键获取Harbor中镜像信息,快捷查询镜像