很多时候,客户端请求服务器,在发送完请求之后, 一直都等不来服务器响应, 此时客户端不能一直等下去, 此因此客户端就要设置一个"超时时间",也就是说,一旦等待时长超过这个时间, 客户端就会自动执行某一段代码
这里就会用到计时器的实现
标准库中的计时器
计时器主要就是schedule方法
schedule(超时后要执行的方法, 超时时间ms);
这里的TimeTask是一个runnable接口, 所以要new TimeTask(),然后重写run方法, 从而执行操作
import java.util.Timer;
import java.util.TimerTask;
public class Demo25 {
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("好好学习!");
}
},100);
System.out.println("开始计时!");
}
}
Timer也能执行多个任务
import java.util.Timer;
import java.util.TimerTask;
public class Demo25 {
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("好好学习!");
}
},100);
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("赶紧学习!");
}
},200);
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("快快快!");
}
},300);
System.out.println("开始计时!");
}
}
值得注意的是: 执行完任务之后, 进程并没有结束
原因就是Timer内部需要一组线程来执行注册的任务, 这里的线程是前台线程, 会影响进程退出
后台线程 vs 前台线程
isDaemon 要是true就是后台线程(守护线程),不会影响进程退出,直接就把进程销毁了
要是isDaemon是false,就是前台线程,就会影响进程退出
自己实现定时器
import java.util.PriorityQueue;
//实现自己的定时器
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
class MyTask implements Comparable<MyTask>{
private Runnable runnable;
private long time;
public MyTask(Runnable runnable, long delay) {
this.runnable = runnable;
this.time = System.currentTimeMillis() + delay;
}
public Runnable getRunnable() {
return runnable;
}
public long getTime() {
return time;
}
@Override
public int compareTo(MyTask o) {
return (int)(this.time - o.time);//time是long类型,compareTo接口要是int的,所以要强转
}
}
class MyTimer{
//使用优先级阻塞队列 既保证了按照时间优先级来调用,又保证了线程安全
private BlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();
Object locker = new Object();
public MyTimer(){
//创建一个线程,不停的扫描队列中的队首元素,时间一到就执行任务
Thread t = new Thread(()->{
//但是,这个循环会一直执行,一直都在看时间,就会浪费效率,也就是"忙等"
//使用wait来解决
while(true) {
synchronized (locker) {
try {
//取出队首元素
MyTask myTask = queue.take();
long curTime = System.currentTimeMillis();
if (myTask.getTime() <= curTime) {
//到点了,该执行任务了
myTask.getRunnable().run();
} else {
//还没到点就再塞会阻塞优先级队列里面
//还没到点就等待
locker.wait(myTask.getTime()-curTime );
queue.put(myTask);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t.start();
}
public void schedule(Runnable runnable, long after) throws InterruptedException {
MyTask myTask = new MyTask(runnable, after);
queue.put(myTask);
//要是有新的时间添加进来,就唤醒,并且调整wait的时间
synchronized (locker) {
locker.notify();
}
}
}
public class Demo26 {
public static void main(String[] args) throws InterruptedException {
MyTimer myTimer = new MyTimer();
myTimer.schedule(new Runnable() {
@Override
public void run() {
System.out.println("快点行动1");
}
},1000);
myTimer.schedule(new Runnable() {
@Override
public void run() {
System.out.println("快点行动2");
}
},2000);
System.out.println("计时开始");
}
}