我看到了一些比较好的文章:
1、JAVA 定时器的三种方法:https://blog.csdn.net/mazegong/article/details/77743805
里面讲解的是(1、自己创建一个线程实现定时效果,
2、Timer类可以调度任务,TimerTask则是通过在run()方法里实现具体任务。
3、通过ScheduledExecutorService#scheduleAtFixedRate展示这个例子,通过代码里参数的控制,首次执行加了delay时间。 )
2、深入理解Java线程池:ScheduledThreadPoolExecutor:https://blog.csdn.net/chang_ge/article/details/80080382
里面讲解的有(1、Timer类与ScheduledThreadPoolExecutor创建定时器的区别以及两者的优点,其中ScheduledThreadPoolExecutor 更好 ,用于多线程,有许多的优化。
2、深入了解ScheduledThreadPoolExecutor的原理,里面写的特别详细,看这一篇就可以啦,不过内容特别多,需要多次进行消化。
2.1:ScheduledThreadPoolExecutor的使用
2.2:ScheduledThreadPoolExecutor的实现
2.2.1:ScheduledThreadPoolExecutor的类结构
2.2.2:ScheduledThreadPoolExecutor的3种的构造方法
2.2.3 :schedule方法来进行任务调度
2.2.4:scheduleAtFixedRate方法(一般是延迟时间与任务时间进行比较)
2.2.5:scheduleWithFixedDelay方法(任务的执行时间加上延迟时间)
2.2.6:triggerTime方法(获取下一次执行的具体时间)
2.2.7 :overflowFree方法(限制队列中所有节点的延迟时间在Long.MAX_VALUE之内,防止在compareTo方法中溢出。
2.2.8:ScheduledFutureTask的run方法:当线程池中的工作线程启动时,不断地从阻塞队列中取出任务并执行,当然,取出的任务实现了Runnable接口,所以是通过调用任务的run方法来执行任务的。
3、DelayedWorkQueue :阻塞工作队列
ScheduledThreadPoolExecutor之所以要自己实现阻塞的工作队列,是因为ScheduledThreadPoolExecutor要求的工作队列有些特殊。
DelayedWorkQueue是一个基于堆的数据结构,类似于DelayQueue和PriorityQueue。在执行定时任务的时候,每个任务的执行时间都不同,所以DelayedWorkQueue的工作就是按照执行时间的升序来排列,执行时间距离当前时间越近的任务在队列的前面(注意:这里的顺序并不是绝对的,堆中的排序只保证了子节点的下次执行时间要比父节点的下次执行时间要大,而叶子节点之间并不一定是顺序的)
为什么要使用DelayedWorkQueue呢?
定时任务执行时需要取出最近要执行的任务,所以任务在队列中每次出队时一定要是当前队列中执行时间最靠前的,所以自然要使用优先级队列。
DelayedWorkQueue是一个优先级队列,它可以保证每次出队的任务都是当前队列中执行时间最靠前的,由于它是基于堆结构的队列,堆结构在执行插入和删除操作时的最坏时间复杂度是 O(logN)。
创建ScheduledExecutorService来定时执行一些任务
package com.bjsxt.height.concurrent017;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
class Temp extends Thread {
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("run");
}
}
public class ScheduledJob {
public static void main(String args[]) throws Exception {
Temp command = new Temp();
Temp command2 = new Temp();
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
//scheduleWithFixedDelay 其中0代表执行前不延迟,时隔2秒后在循环执行一次任务,其中执行command任务需要5秒,所以时隔7秒执行一次任务
ScheduledFuture<?> scheduleTask1 = scheduler.scheduleWithFixedDelay(command, 0, 2, TimeUnit.SECONDS);
//scheduleAtFixedRate 0代表执行前不延迟,时隔2秒执行一次任务,其中执行command需要5秒,所以时隔5秒执行一次任务。
ScheduledFuture<?> scheduleTask2 = scheduler.scheduleAtFixedRate(command, 0, 2, TimeUnit.SECONDS);
}
}