案例三:定时器
Java标准库中,还提供了定时器的实现。
定义一个timer添加多个任务,每个任务同时会带一个时间,执行完后,进程没有结束,Timer里内置了线程(前台线程)
timer.cancle();需要主动结束,否则Timer不知道是否其他地方还要继续添加任务
Timer中需要一个线程,负责掐时间,等任务到达合适的时间,这个线程就执行,还需要一个队列/数组,能够保存所有schedule进来的任务,
这个线程就可以不停的去扫描上述队列中的每个元素,看每个任务是否到时间了,到时间就执行
如果队列很长,这个遍历过程开销就会很大O(N)
每个任务都是带有delay时间的,肯定要先执行时间小的,后执行时间大的。 => 扫描线程就不必执行了,只需要关注队首元素是否到时间了,如果队首元素没到时间,后续其他线程也一定没到时间=> 使用标准库提供的PriorityQueue(线程不安全)手动加锁
1)线程
2)优先级队列,保存所有任务
注:ms级别的时间戳:以1970年1月1日0时0分0秒为基准,计算当前时刻和基准时间的秒数/毫秒数/微秒数...之差。
代码
1. MyTimerTask
类
MyTimerTask
类表示一个定时任务,它包含以下内容:
-
time
:任务执行的绝对时间(以毫秒为单位的时间戳)。 -
runnable
:实际要执行的任务,是一个Runnable
对象。 -
getTime()
:获取任务的执行时间。 -
MyTimerTask(Runnable runnable, long delay)
:构造函数,接受一个Runnable
任务和一个延迟时间delay
。它会根据当前时间和延迟时间计算出任务的绝对执行时间。 -
run()
:执行任务,即调用runnable.run()
。 -
compareTo(MyTimerTask o)
:实现Comparable
接口,用于比较两个任务的执行时间。PriorityQueue
会根据这个方法来排序任务,确保最早执行的任务在队首。
2. MyTimer
类
MyTimer
类是一个定时器,它负责管理任务的调度和执行。它包含以下内容:
-
t
:一个线程,负责扫描任务队列并执行任务。 -
queue
:一个优先队列(PriorityQueue
),用于存储MyTimerTask
任务。队列会根据任务的执行时间进行排序,最早执行的任务在队首。 -
locker
:一个锁对象,用于同步对任务队列的访问。
2.1 schedule(Runnable runnable, long delay)
方法
-
这个方法用于调度一个任务,任务将在指定的延迟时间
delay
后执行。 -
它首先创建一个
MyTimerTask
对象,并将其添加到优先队列queue
中。 -
然后,它调用
locker.notify()
来唤醒可能正在等待的扫描线程(t
),以便它能够检查新添加的任务。
2.2 构造方法
-
在
MyTimer
的构造方法中,创建并启动了一个扫描线程t
。 -
这个线程会不断地检查任务队列,判断队首任务的执行时间是否已经到达。
-
如果队列为空,线程会调用
locker.wait()
进入等待状态,直到有新任务被添加并调用locker.notify()
。 -
如果队列不为空,线程会检查队首任务的执行时间:
-
如果当前时间已经到达或超过了任务的执行时间,线程会从队列中取出任务并执行它。
-
如果当前时间还未到达任务的执行时间,线程会调用
locker.wait(task.getTime() - curTime)
进入等待状态,直到任务的执行时间到达或新任务被添加。
-
-