- 需要一个Task类来描述一段逻辑或者说是一个要执行的任务 同时要记录这个任务在啥时候执行
// 优先队列中的元素必须是可比较的~
// 比较规则的指定主要是两种方式:
// 1. 让 Task 实现 Comparable 接口
// 2. 让优先队列构造的时候, 传入一个比较器对象 (Comparator).
static class Task implements Comparable {
// Runnable 中有一个 run 方法, 就可以借助这个 run 方法来描述要执行的具体的任务是啥.
private Runnable command;
// time 表示啥时候来执行 command, 是一个绝对时间(ms级别的时间戳)
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 {
// 为了避免忙等, 需要使用 wait 方法.
// 使用一个单独的对象来辅助进行 wait
// 使用 this 也行.
private final Object mailBox = new Object();
// 定时器的基本构成, 有三个部分.
// 1. 用一个类来描述 “任务”
// 2. 用一个阻塞优先队列来组织若干个任务. 让队首元素就是时间最早的任务.
// 如果队首元素时间未到, 那么其他元素也肯定不能执行.
private PriorityBlockingQueue queue = new PriorityBlockingQueue<>();
// 3. 用一个线程来循环扫描当前的阻塞队列的队首元素, 如果时间到, 就执行指定的任务.
public Timer() {
// 创建线程
Worker worker = new Worker(queue, mailBox);
worker.start();
}
// 4. 还需要提供一个方法, 让调用者能把任务给 “安排” 进来.
// schedule => 安排
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 queue;
private final Object mailBox;
public Worker(PriorityBlockingQueue queue, Object mailBox) {
this.queue = queue;
this.mailBox = mailBox;
}
@Override
public void run() {
// 实现具体的线程执行的内容
while (true) {
try {
// 1. 取出队首元素, 检查时间是否到了
Task task = queue.take();
// 2. 检查当前任务时间是否到了
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 {
//添加一个公共用对象去实现wait和唤醒
private final Object loker = new Object();
//首先需要一个类Task去描述一个任务
//使用阻塞优先级队列来组织若干个线程判断谁先执行
private PriorityBlockingQueue blockingQueue = new PriorityBlockingQueue<>();
//用一个线程去循环扫描当前队列的队首元素 如果时间到了就执行该任务
public Timer() {
Worker worker = new Worker(blockingQueue, loker);
//启动worker里的线程
worker.start();
}
//计时器还需要一个方法让用户往里放任务
public void schedule(Runnable runnable, long time) {
Task task = new Task(runnable, time);
blockingQueue.put(task);
//新进来任务要唤醒wait的线程让优先级队列重新组织去判断哪个先执行
synchronized (loker) {
loker.notify();
}
}
}
//因为要放到优先级阻塞队列所有要实现Compararble接口
class Task implements Comparable {
//在这类去描述一个线程任务 所以他需要你个Runnable和time去确定什么时候执行
private Runnable runnable;
private long time;
public Task(Runnable runnable, long after) {
this.runnable = runnable;
this.time = System.currentTimeMillis() + after;
}
//提供一个run方法执行Runnable
public void run() {
runnable.run();
}
public long getTime() {
return time;
}
@Override
public int compareTo(Task o) {
//要让时间小的先去执行
return (int) (this.time - o.time);
}
}
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
…(img-Sn3EsMdt-1715713839976)]
[外链图片转存中…(img-21rnSLPU-1715713839977)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!