ScheduledThreadPoolExecutor
使用
int initialDelay = 5; System.out.println(Thread.currentThread().getName() + " " + TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())); ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); //以上一个任务开始的时间计时,period时间过去后,检测上一个任务是否执行完毕,如果上一个任务执行完毕,则当前任务立即执行,如果上一个任务没有执行完毕,则需要等上一个任务执行完毕后立即执行。 executorService.scheduleAtFixedRate(()->{ System.out.println(Thread.currentThread().getName() + " " + TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } },initialDelay,5, TimeUnit.SECONDS); //以上一个任务结束时开始计时,period时间过去后,立即执行 executorService.scheduleWithFixedDelay(()->{ System.out.println(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } },initialDelay,5, TimeUnit.SECONDS);
ScheduledThreadPoolExecutor
原理
ScheduledThreadPoolExecutor
底层实现为ThreadPoolExecutor
和自定义 DelayWorkQueue
延时队列结合使用,ThreadPoolExecutor
原理已在前面线程池原理与源码剖析中有详细说明,延时队列原理在Queue阻塞队列中详细说明。
大概原理:将任务封装到一个既实现Runnable
接口又继承Delayed
类的ScheduledFutureTask
类中,放入延时队列中,再调用我们的ThreadPoolExecutor
中的executor
方法开启线程,调用ScheduledFutureTask
中的run
方法,该方法再调用真正任务的run
方法,处理完真正任务的run
方法后,计算下次任务的执行时间,再次将ScheduledFutureTask
放入延时队列,回到调用我们的ThreadPoolExecutor
中的executor
方法的逻辑,继续往下执行。
定时任务线程池类关系.png
ScheduledFutureTask.png