一.引言
newScheduledThreadPool 周期性线程池提供了周期执行任务的方法 scheduleAtFixedRate 与 scheduleWithFixedDelay,两者比较容易混淆,下面结合代码捋一下逻辑,后续使用也更加方便。
二.功能介绍
1.scheduleAtFixedRate Api
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit)
官方解释 : 创建并执行一个周期性操作,该操作在给定的初始延迟之后首先启用,然后在给定的时间段内启用;也就是说,执行将在initialDelay之后开始,然后是initialDelay+period,然后是initialDelay+2*period,依此类推。
如果任务的任何执行遇到异常,则禁止后续执行。否则,只能通过取消或终止执行者来终止任务。如果此任务的任何执行时间长于其周期,则后续执行可能会延迟开始,但不会同时执行。
执行逻辑 : initiaDelay时间结束后,从上一个任务开始计时,period 时间后,检查上一个任务,如果上一个任务执行完成则立即执行新任务,如果未完成则等待上一个任务完成立即执行,循环往复
理想状态 : initiaDelay时间结束后,每 period 时间内,任务正常执行一次
举个栗子 : 60min时间里每个10min内都做一次执行时间小于等于10min的Runnable的任务
2.scheduleWithFixedDelay Api
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit);
官方解释 : 创建并执行一个周期性操作,该操作在给定的初始延迟之后首先启用,然后在一个执行的终止和下一个执行的开始之间具有给定的延迟。如果任务的任何执行遇到异常,则禁止后续执行。否则,只能通过取消或终止执行者来终止任务。
执行逻辑 : initiaDelay时间结束后,从上一个任务结束开始计时,delay 时间过后,立即执行下一个任务,注意这里不会检查上一个任务是否执行完毕
理想状态 : initiaDelay时间结束后,任务依次间隔执行,每个任务之间间隔 delay
举个栗子 : 每个Runnable都正常执行,Runnable A 结束后过 delay 时间 Runnable B 执行,one by one 以此类推
3.相同与不同
相同点 :
都具有延时初始化的方式,周期/间隔性的执行任务,都只实现了Runnable方法,不像 newScheduledThreadPool 的 schedule 同时支持 Runnalbe 和 Callable,都需要做好完备的Try Catch,否则中途失败只能通过取消或终止 executor 来终止任务
不同点 :
AtFixedRate 以 period 为单位,所以是周期执行,WithFixedDelay 以 delay 为单位,所以是按间隔执行
三.实战
下面通过两个简单例子讲解一下使用,两个例子我都会在线程池中额外加一个线程池负责计数,每1s钟打印一次时间
1. scheduleAtFixedRate Demo
初始化延迟为5s,每3s为一个Period,程序内执行Sleep 2s和print的操作
def testFixedRatePool(): Unit = {
// 初始化延时线程池
val executor = Executors.newScheduledThreadPool(3)
val initDelay = 5
// period执行任务
executor.scheduleAtFixedRate(new Runnable {
override def run(): Unit = {
try {
Thread.sleep(2000)
println("Runnable Execute Success!")
} catch {
case e: Exception => {}
e.printStackTrace()
}
}
}, initDelay, 3, TimeUnit.SECONDS)
executor.scheduleAtFixedRate(new Runnable {
override def run(): Unit = {
println("A second passed...")
}
}, 0, 1, TimeUnit.SECONDS)
}
执行结果:
延时初始化用掉了5s,period 3s的前2s Sleep 然后打印,随后空闲1s,接下来到达新的period,依次往复
2. scheduleWithFixedDelay Demo
延时初始化5s,执行Runnable耗时约2s,打印标记信息,随后delay延时3s,循环往复
def testFixedDelayPool(): Unit = {
val executor = Executors.newScheduledThreadPool(3)
val initDelay = 5
executor.scheduleWithFixedDelay(new Runnable {
override def run(): Unit = {
try {
Thread.sleep(2000)
println("Runnable Execute Success!")
} catch {
case e: Exception => {}
e.printStackTrace()
}
}
}, initDelay, 3, TimeUnit.SECONDS)
executor.scheduleWithFixedDelay(new Runnable {
override def run(): Unit = {
println("A second passed...")
}
}, 0, 1, TimeUnit.SECONDS)
}
执行结果:
同上,延时初始化用掉了5s,执行Runnable 消耗2s,随后delay 3s,继续执行Runnable 消耗2s,delay 3s,依次往复