ScheduledExecutorService的主要作用就是可以将定时任务与线程池功能结合使用。
由于是基于线程池设计的定时任务类,每个调度任务都会分配到线程池中的一个线程去执行,也就是说,任务是并发执行,互不影响。
需要注意,只有当调度任务来的时候,ScheduledExecutorService才会真正启动一个线程,其余时间ScheduledExecutorService都是出于轮询任务的状态。
Executors利用工厂模式向我们提供了4种线程池实现方式,但是并不推荐使用,原因是使用Executors创建线程池不会传入这个参数而使用默认值所以我们常常忽略这一参数,而且默认使用的参数会导致资源浪费,不可取。
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
ScheduledExecutorService mScheduledExecutorService = Executors.newScheduledThreadPool(num);
num 在的意思是线程池中保持num个线程可以同时执行,但是注意,并不是说线程池中永远都是这三个线程,只是说可以同时存在的线程数,当某个线程执行结束后,会有新的线程进来。
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1,
1,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue());
ScheduledExecutorService newScheduledThreadPool =
Executors.newScheduledThreadPool(4,threadPoolExecutor.getThreadFactory());
//org.apache.commons.lang3.concurrent.BasicThreadFactory
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());
ScheduledExecutorService falseexecutorService = new ScheduledThreadPoolExecutor(num);
daemon(true) 是守护线程的意思
在Java中有两类线程:用户线程 (User Thread)、守护线程 (Daemon Thread)。
所谓守护线程,是指在程序运行的时候在后台提供一种通用服务的线程,比如垃圾回收线程就是一个很称职的守护者,并且这种线 程并不属于程序中不可或缺的部分。因此,当所有的非守护线程结束时,程序也就终止了,同时会杀死进程中的所有守护线程。反过来说,只要任何非守护线程还在运行,程序就不会终止。
用户线程和守护线程两者几乎没有区别,唯一的不同之处就在于虚拟机的离开:如果用户线程已经全部退出运行了,只剩下守护线程存在了,虚拟机也就退出了。 因为没有了被守护者,守护线程也就没有工作可做了,也就没有继续运行程序的必要了。
将线程转换为守护线程可以通过调用Thread对象的setDaemon(true)方法来实现。在使用守护线程时需要注意一下几点:
(1) thread.setDaemon(true)必须在thread.start()之前设置,否则会跑出一个IllegalThreadStateException异常。你不能把正在 运行的常规线程设置为守护线程。
(2) 在Daemon线程中产生的新线程也是Daemon的。
(3) 守护线程应该永远不去访问固有资源,如文件、数据库,因为它会在任何时候甚至在一个操作的中间发生中断。
falseexecutorService.scheduleWithFixedDelay(command, initialDelay, delay, unit)
falseexecutorService.scheduleAtFixedRate(command, initialDelay, period, unit)
falseexecutorService.schedule(command, delay, unit)
参数 command 方法 执行体
参数 initialDelay 首次执行的延时时间
参数 delay 定时执行的间隔时间
参数 unit 单位
// TimeUnit.NANOSECONDS 千分之一微秒的时间单位
// TimeUnit.MICROSECONDS 千分之一毫秒的时间单位
// TimeUnit.MILLISECONDS 表示千分之一秒的时间单位
// TimeUnit.SECONDS 表示一秒的时间单位
// TimeUnit.MINUTES 表示六十秒的时间单位
// TimeUnit.HOURS 表示六十分钟的时间单位
// TimeUnit.DAYS 表示二十四小时的时间单位
scheduleAtFixedRate 循环任务严格按照每5秒发起一次 Thread.sleep(3000); 只是对上一个线程的影响 如果有多个线程不影响下个线程的执行 -------> 以上一个任务的开始时间 + 延迟时间 = 下一个任务的开始时间。
executorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("run {{"+Thread.currentThread().getName()+"}}> "
+ System.currentTimeMillis()/1000);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, 1, 5, //TimeUnit.MILLISECONDS 表示千分之一秒的时间单位
TimeUnit.SECONDS);
输出结果 :
run {{pool-1-thread-1}}> 1551258899
run {{pool-1-thread-1}}> 1551258904
run {{pool-1-thread-2}}> 1551258909
scheduleWithFixedDelay循环任务严格按照每一秒发起一次,sleep(3000)对于任务的开启是有影响的
以上一个任务的结束时间 + 延迟时间 = 下一个任务的开始时间。
executorService.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
System.out.println("run {{"+Thread.currentThread().getName()+"}}> "
System.currentTimeMillis()/1000);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, 0, 5, //TimeUnit.MILLISECONDS 表示千分之一秒的时间单位
TimeUnit.SECONDS);
输出结果 :
run {{pool-1-thread-1}}> 1551259165
run {{pool-1-thread-1}}> 1551259173
run {{pool-1-thread-2}}> 1551259181
run {{pool-1-thread-1}}> 1551259189
run {{pool-1-thread-1}}> 1551259197
schedule 是延时任务 只执行有一次
executorService.schedule((new Runnable() {
@Override
public void run() {
System.out.println("run 延时任务>>>> "+ System.currentTimeMillis());
}
}), 3, TimeUnit.MILLISECONDS);
运行结果 :
run 延时任务>>>> 1551259382734