您现在的位置是:主页 > news > 佛山哪里有网站开发?/seo网站分析
佛山哪里有网站开发?/seo网站分析
admin2025/5/2 20:34:05【news】
简介佛山哪里有网站开发?,seo网站分析,牡丹江,云建站公司简单来说,定时器就相当于一个“闹钟”,给定时器设定一个任务,约定这个任务在xxx时间之后执行~ Timer类提供了一个核心接口,schedule(安排) 指定一个任务交给定时器,在一定时间之后再去执行这个任务~ 如何实现定时器的…
简单来说,定时器就相当于一个“闹钟”,给定时器设定一个任务,约定这个任务在xxx时间之后执行~
Timer类提供了一个核心接口,schedule(安排) 指定一个任务交给定时器,在一定时间之后再去执行这个任务~
如何实现定时器的效果~
- Timer中要包含一个Task类,每个Task就表示一个具体的任务实例,Task里面包含一个时间戳(啥时候执行这个任务),还包含一个Runnable实例(用来表示任务具体是啥)。
- Timer里面通过一个带优先级的阻塞队列,来组织如干个task。
- 这里的优先级是按照时间的先后来排优先级,快要到时间的任务优先级更高。
- 也就是 给 堆 加上 wait/notify ,让它能够带阻塞效果。
- 标准库里提供这样的队列PriorityBlockingQueue
- Timer 中还需要一个专门的线程,让这个线程不停的扫描队首元素,看看队首元素是不是已经可以执行了,如果可以执行了,就执行,反之继续在队列中等待。
具体如何用代码实现这样一个定时器Timer:
一般去设定时间的时候,传入的时间,都是一个时间间隔
例如:传入1000 ,就代表从当前开始过1000ms之后在执行;
而我这里为了后面代码方便判断,在这里记录一下绝对时间,这样this.time里就是一个标志的ms级时间戳了,后续只需要获取当前时间戳在和这里的time对比一下就好了。
Task 要放到一个优先级队列中,但是优先级队列里面是需要比较优先级的,所以可以让Task类实现Comparable接口,重写compareTo方法来进行比较。
这里希望时间较小的排在见面。
这里获取一下当前时间currTime,如果当前时间大于等于task里约定的时间,超过说明时间到,执行任务,反之没到,把取去的任务再放回队列,继续等待。
这里还涉及到一个问题:
举个例子:假如你早上定了一个8.30的 闹钟,8点的时候你醒了,看了下时间,还没到,你就继续睡,
但是这里是while(true),就意味着每过一秒钟就要看一次闹钟,8.01看一次,8.02看一次,这样就会白白的浪费一些资源,这就出现了“盲等”,在等待任务时间的过程中,一直持有着CPU资源~
所以这里就需要优化一下:使用wait/notify机制,就可很好的改善盲等问题~
如果取出任务发现还没到时间,就wait,等待一定时间,这里使用的wait()的重载版本,wait()里写一个参数,达到等待时间,自动醒过来~ 此时就大大降低了扫描次数和成本,
这里的notify(),就是保证当线程中如果有线程在WAITING状态的线程,就需要显示的唤醒一下线程。
举个例子;
如果队首元素8.30在执行,等待30分钟,但是此时,可能突然插入一个任务,让你8.10的时候去干一件事,如果你8.30再去唤醒的话,8.10的任务就来不及了!
所以每次插入新任务的时候,都唤醒一下woeker线程,让worker线程重新获取一下队首元素,看看接下来的任务等待多少时间合适。
//简单定时器
public class TestTimer {//每个 Task 实例 就包含一个要执行的任务//Task 要放到一个优先级队列中,但是优先级队列里面是需要比较优先级的static class Task implements Comparable<Task>{//什么时候执行private long time;//执行什么任务private Runnable command;public Task(Runnable command ,long time){this.command = command;this.time = System.currentTimeMillis()+time;}public void run(){//执行Runable 里面的run方法command.run();}@Overridepublic int compareTo(Task o) {return (int)(this.time - o.time);}}static class Timer{//先创建一个带优先级的阻塞队列private PriorityBlockingQueue<Task> queue = new PriorityBlockingQueue<>();//用这个对象来完成线程之间的协调任务private Object meilbox = new Object();//schedule 方法就是把一个Task 放在Timer中public void schedule(Runnable command,long after){Task task = new Task(command,after);//将当前任务放入对列queue.put(task);//当worker 线程中包含wait机制的时候,在安排任务的时候就需要显示的唤醒一下synchronized (meilbox){meilbox.notify();}}//写一个构造方法,创建线程public Timer(){//创建一个线程,让这个线程去扫描队列的队首元素,看看能不能执行Thread worker = new Thread(){@Overridepublic void run() {//取出队首元素,判断这个元素能不能执行while(true){try {Task task = queue.take();long currTime = System.currentTimeMillis();if(currTime >= task.time){//时间到,执行任务task.run();}else{//时间没到,继续等待queue.put(task);synchronized (meilbox){meilbox.wait(task.time-currTime);}}} catch (InterruptedException e) {e.printStackTrace();}}}};worker.start();}}
}
测试:
public static void main(String[] args) {Timer timer = new Timer();Runnable command = new Runnable() {@Overridepublic void run() {System.out.println("时间到了~");// timer.schedule(this,3000); 每隔3是就执行一次}};System.out.println("安排任务");timer.schedule(command,3000);}
}
安排任务后,等待3s就可以执行了
这里补充一下Timer原生类中的一些方法
- schedule(TimerTask task, Date time) 在指定的日期执行一次TimerTask任务;如果日期time早于当前时间,则立刻执行。
- schedule(TimerTask task, long delay, long period) 以当前时间为基准,延迟指定的毫秒后,再按指定的时间间隔地无限次数的执行TimerTask任务。
- schedule(TimerTask task, Date firstTime, long period) 在指定的日期之后,按指定的时间间隔地无限次数的执行TimerTask任务。
- scheduleAtFixedRate(TimerTask task, long delay, long period) 以当前时间为基准,延迟指定的毫秒后,再按指定的时间间隔周期性地无限次数的执行TimerTask任务。