join(指定超时时间)sleep(指定休眠时间)
一.标准库的定时器
核心:schedule,参数有两个①任务②多长时间之后执行
import java.util.Timer;
import java.util.TimerTask;
public class Demo3 {
public static void main(String[] args) {
Timer timer=new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("hello");
}
},3000);
System.out.println("main");
}
}
先打印main,3秒钟之后打印hello
二.自己实现一个定时器
Timer:
①描述任务:创建一个专门的类来表示定时器的任务
class MyTask{
//创建一个具体事件
public Runnable runnable;
//创建执行任务的时间戳
public long time;
public MyTask(Runnable runnable,long after) {
this.runnable = runnable;
this.time=System.currentTimeMillis()+after;
}
public void run(){
runnable.run();
}
}
②组织任务:通过数据结构组织
在标准库中有一个专门的数据结构:PriorityBlockingQueue(有优先级,又有阻塞队列)
遇到了一个问题:优先队列里面是堆,但是每个类之间的大小关系不明确。myTask的比较规则不存在,需要手动指定,按照时间大小来比较。编译器在比较的时候尝试把这些类往comparable转换来比较,但是转换失败。
//改进:加接口
class MyTask implements Comparable<MyTask>{
//创建一个具体事件
public Runnable runnable;
//创建执行任务的时间戳
public long time;
public MyTask(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(MyTask o) {
return (int) (this.time-o.time);
}
}
③执行时间到了的任务
class MyTimer{
private PriorityBlockingQueue<MyTask> queue=new PriorityBlockingQueue<>();
public void schedule(Runnable runnable,long delay){
MyTask task =new MyTask(runnable,delay);
queue.put(task);
}
public MyTimer(){
//在线程里面不断扫描
Thread thread=new Thread(() -> {
while (true) {
try {
//取出队首元素
MyTask task = queue.take();
//取当前时间
long curTime = System.currentTimeMillis();
if (curTime < task.getTime()) {
//比较,如果时间没到,把任务塞回队列
queue.put(task);
} else {
//如果时间到了,则执行任务
task.run();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
}
}
第二个问题:如果队列中的任务为空,则线程阻塞;若队列中的任务不空且任务时间没到
wait能被中途唤醒;sleep中途不能被唤醒
package Thread;
import java.util.PriorityQueue;
import java.util.concurrent.PriorityBlockingQueue;
//创建一个类表示一个任务
class MyTask implements Comparable<MyTask>{
//创建一个具体事件
public Runnable runnable;
//创建执行任务的时间戳
public long time;
public MyTask(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(MyTask o) {
return (int) (this.time-o.time);
}
}
class MyTimer{
private PriorityBlockingQueue<MyTask> queue=new PriorityBlockingQueue<>();
public void schedule(Runnable runnable,long delay){
MyTask task =new MyTask(runnable,delay);
queue.put(task);
}
public MyTimer(){
//在线程里面不断扫描
Thread thread=new Thread(() -> {
while (true) {
try {
//取出队首元素
MyTask task = queue.take();
//取当前时间
long curTime = System.currentTimeMillis();
if (curTime < task.getTime()) {
//比较,如果时间没到,把任务塞回队列
queue.put(task);
} else {
//如果时间到了,则执行任务
task.run();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
}
}
public class Demo3 {
public static void main(String[] args) {
MyTimer myTimer=new MyTimer();
myTimer.schedule(new Runnable() {
@Override
public void run() {
System.out.println("hello");
}
},3000);
System.out.println("main");
}
}