Java多线程案例实战之定时器的实现
作者:兜里有颗棉花糖
一、Timer定时器
Java中,Timer类
是用于计划和执行重复任务的类(Java标准库中确实提供了java.util.Timer
类)。它可以在指定的时间间隔内重复执行一个任务,或者在指定时间点执行任务。
二、Timer定时器的设计
选择java.util
包中的Timer
类:
使用了Timer类的schedule()
方法来安排一个任务在延迟3000毫秒后执行。在TimerTask的run()方法中,我们编写需要执行的具体任务逻辑。我们现在来了解一下TimerTask()这个抽象类
(如下图):该类是一个抽象类,并且继承了Runnable方法
。创建了一个匿名内部类并实现了run()方法。这个匿名内部类可以被认为是继承了TimerTask抽象类,并提供了具体的实现代码。
调用timer.schedule()
方法注册的任务,会由Timer内部的线程池去执行,而不是由调用schedule()方法的线程直接执行run()方法。
Timer类内部创建了一个线程池,用于执行注册的定时任务。当调用schedule()方法后,Timer会将传入的TimerTask对象添加到线程池中进行调度。
下面是一个简单的定时器程序,可以运行试试看:
import java.util.Timer; import java.util.TimerTask; public class Demo22 { public static void main(String[] args) { Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("hello world!!!"); } },3000); System.out.println("程序开始执行喽!!!"); } }
运行结果如下:
可以看到程序并没有结束进程,原因如下:Timer
内部有自己的线程,为了保证随时处理新安排的任务,此线程会一直持续的执行,即此线程影响了阻止来整个进程的结束。
定时器是支持多个任务同时执行的,请看:
三、定时器的实现
代码实现如下:
import java.util.Comparator; import java.util.PriorityQueue; class MyTimerTask implements Comparable<MyTimerTask> { private long time; // 表示任务什么时候开始执行 private Runnable runnable; // 表示具体任务是啥 public MyTimerTask(Runnable runnable,long delay) { // delay是一个相对的时间差 time = System.currentTimeMillis() + delay;// 这里计算出任务执行的具体时间 this.runnable = runnable; } public long getTime() { return time; } public Runnable getRunnable() { return runnable; } @Override public int compareTo(MyTimerTask o) { // 时间最少的元素放在队首,即时间越少优先级越高 return (int)(this.time - o.time); // time是long类型 } } // 这是定时器类的本体 class MyTimer { // 使用优先级队列来保存上面的N个任务 private PriorityQueue<MyTimerTask> queue = new PriorityQueue<>(); // locker是用来加锁的对象 private Object locker = new Object(); // 定时器的核心方法,即把要执行的任务添加到队列中 public void schedule(Runnable runnable,long delay) { synchronized (locker) { MyTimerTask task = new MyTimerTask(runnable,delay); queue.offer(task); // 每次来新的任务之后都会唤醒一下扫描线程,此时扫描线程就可以根据最新的任务情况来重新规划等待时间 locker.notify(); } } // MyTimer类中还需要一个扫描线程,一方面要负责检查队首元素是否是此时应该被执行的。 // 另一方面,当任务到点开始执行之后,需要调用Runnable中的run方法来完成任务 public MyTimer() { // 扫描线程 Thread t = new Thread(() -> { while(true) { try { synchronized(locker) { while(queue.isEmpty()) { // 队列为空时,此时不应该取这里的元素 locker.wait(); } MyTimerTask task = queue.peek(); long curTime = System.currentTimeMillis(); if(curTime > task.getTime()) { // 如果当前时间晚于任务的执行时间,就意味着我们要执行这个任务了 queue.poll(); task.getRunnable().run(); // 至此就可以执行该任务了 } else { // 如果当前时间早于任务的执行时间,诶呀太早了,让这个线程(休眠)休息一会一会吧!!! // Thread.sleep(task.getTime() - curTime); locker.wait(task.getTime() - curTime); } } } catch (InterruptedException e) { e.printStackTrace(); } } }); t.start(); } } public class Demo23 { public static void main(String[] args) { MyTimer timer = new MyTimer(); timer.schedule(new Runnable() { @Override public void run() { System.out.println("hello world! 3"); } },3000); timer.schedule(new Runnable() { @Override public void run() { System.out.println("hello world! 2"); } },2000); timer.schedule(new Runnable() { @Override public void run() { System.out.println("hello world! 1"); } },1000); System.out.println("程序开始执行!!!"); } }
运行结果如下:
四、总结
Timer类是Java中的定时工具类,它可以帮助我们实现在指定时间执行指定任务的功能。Timer类提供了一个方法即schedule方法
,我们可以通过schedule方法来注册一个任务并指定执行该任务的时间,当执行时间到的时候,Timer类内部的线程就会负责调用执行注册的任务。
另外我们可以通过优先级队列的方式来实现类似于Timer类这样的定时器。
到此这篇关于Java多线程案例定时器的实现的文章就介绍到这了,更多相关Java定时器实现内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!