文章目录
- 💐专栏导读
- 💡Java标准库中的定时器类
- 💡模拟实现定时器
💐专栏导读
本篇文章收录于多线程,也欢迎翻阅博主的其他文章,可能也会让你有不一样的收获😄
🍂JavaSE🌷多线程🍁数据结构
闹钟大家一定都使用过,当闹钟响的时候,就表示我们该起床了,或者是手机上的定时发短信,等到时间达到时,就会按照我们的要去发送短信等;定时器也就是这样一种工作组件,约定一个时间,当时间达到时,就会执行代码
定时器经常用于网络通信中,例如,当客户端向服务器发出一个请求后,就要等待服务器进行响应,但是,如果服务器一直没响应怎么办,是因为请求没发过去?响应没传过来?服务器出问题了等等,这中间你也不知道发生了什么,这时候,客户端难道就一直等着,等到天荒地老?所以,对于客户端而言,就需要一个等待时间,如果等待时间到了,是重新再发送一遍,还是放弃发送,还是其他的操作等等………
💡Java标准库中的定时器类
在Java的util包中,提供了一个Timer类,这个类就是一个定时器,下面通过代码演示:
public class MyTimer {public static void main(String[] args) {Timer timer = new Timer();timer.schedule(new TimerTask() {//给定时器安排一个任务,约定在xxx时间后开始执行@Overridepublic void run() {System.out.println("定时器中任务开始执行");}}, 3000);//指定定时时间,约定在三秒之后开始执行System.out.println("程序执行");}
}
在执行schedule方法的时候,就是把这个任务放到了timer对象中,而且,在timer对象中,也包含了一个线程,这个线程叫作”扫描线程“,等约定时间到了以后,扫描线程就开始执行这个任务;然后通过执行结果也可以看到,定时器中的任务执行完之后,进程并没有结束,而是处于等待其他任务安排进来,所以由此得出,Timer中的线程会阻止进程结束,在Timer中同样也可以安排多个任务👇
在学习完如何使用一个定时器后,我们应该还知道如何实现一个简单的定时器👇
💡模拟实现定时器
实现一个定时器主要考虑一下几个步骤:
class MyTimerTask {//顶一个一个任务private Runnable runnable;//定义一个定时时间public long time;public MyTimerTask(Runnable runnable, long delay) {this.runnable = runnable;this.time = System.currentTimeMillis()+delay;}public Runnable get_runnable() {return runnable;}
}
public class MyTimer {//定义一个队列用于组织任务private PriorityQueue<MyTimerTask> priorityQueue = new PriorityQueue<>(new Comparator<MyTimerTask>() {//自定义比较方法@Overridepublic int compare(MyTimerTask o1, MyTimerTask o2) {return (int)(o1.time - o2.time);}});//定义一个锁对象Object locker = new Object();//定义一个schedule方法public void schedule(Runnable runnable, long time) {/*因为是其他的线程调用schedule,然后对队列进行操作,而扫扫描线程也是对队列进行操作,这也就构成了两个线程对同一个数据进行操作,就可能会出现线程安全问题,因此要进行加锁*/synchronized (locker) {priorityQueue.offer(new MyTimerTask(runnable, time));locker.notify();}}//在构造方法中定义一个扫描线程public MyTimer() {Thread thread = new Thread(() -> {while(true) {//检查队列中的任务check_task();}});thread.start();}private void check_task() {try {synchronized (locker) {//当队列为空时,阻塞等待//使用while进行判断,防止唤醒wait时,队列仍然为空while (priorityQueue.isEmpty()) {locker.wait();}MyTimerTask myTimerTask = priorityQueue.peek();//判断当前时间与定时时间long curTime = System.currentTimeMillis();if(curTime >= myTimerTask.time) {//当前时间大于定时时间,开始执行任务myTimerTask.get_runnable().run();//任务执行完后删除priorityQueue.poll();}else {//为了防止忙等,在这里进行带有时间的wait等待//当时间到了以后,再进行循环,开始执行任务locker.wait(curTime - myTimerTask.time);}}}catch (InterruptedException e) {e.printStackTrace();}}
}