私は春を使用してスケジュールされたタスクを実装していますが、スケジュールされた2種類の設定時間が最新から再び機能することがわかります。この構成の2つのタイプの違いは何ですか。
@Scheduled(fixedDelay = 5000)
public void doJobDelay() {
// do anything
}
@Scheduled(fixedRate = 5000)
public void doJobRate() {
// do anything
}
コード内:
@Scheduled(fixedDelay=5000)
public void updateEmployeeInventory(){
System.out.println("employee inventory will be updated once only the last updated finished ");
/**
* add your scheduled job logic here
*/
}
@Scheduled(fixedRate=5000)
public void updateEmployeeInventory(){
System.out.println("employee inventory will be updated every 5 seconds from prior updated has stared, regardless it is finished or not");
/**
* add your scheduled job logic here
*/
}
"fixedRate":次の実行を開始する前に、前の実行の開始からXミリ秒待機します。現在の実行が「fixedRate」間隔を超える場合、次の実行はキューに入れられますが、次の実行のみがキューに入れられます。一連のキュー実行は作成されません
private static int i = 0;
@Scheduled(initialDelay=1000, fixedRate=1000)
public void testScheduling() throws InterruptedException {
System.out.println("Started : "+ ++i);
Thread.sleep(4000);
System.out.println("Finished : "+ i);
}
出力:
開始済み:1
Finished:1 // 4秒後
Started:2 //固定レートで指定された1秒間待機せずにすぐに
完了:2 // 4秒後
等々
"fixedDelay":次の実行を開始する前に、前の実行の終了からXミリ秒待機します。現在の実行にどれだけ時間がかかっていても、現在の実行の終了時間に「fixedDelay」間隔を追加してから次の実行が開始されます。次の実行をキューに入れません。
private static int i = 0;
@Scheduled(initialDelay=1000, fixedDelay=1000)
public void testScheduling() throws InterruptedException {
System.out.println("Started : "+ ++i);
Thread.sleep(4000);
System.out.println("Finished : "+ i);
}
出力:
開始済み:1
[。
等々
fixedRate: nミリ秒ごとにジョブメソッドを実行するために使用されます。ジョブが前のタスクをすでに終了しているかどうかは重要ではありません。
fixedDelay:これは、タスク間の所定のnミリ秒の待機時間でジョブメソッドを連続して実行するために使用されます。
使用する場合 "fixedRate":fixedRateは、メモリとスレッドのサイズを超えないと予想される場合に適切です。プール。着信タスクがすぐに終了しない場合、「メモリ不足例外」が発生する可能性があります
使用する場合 "fixedDelay":実行中のすべてのタスクが相互に関連しており、前のタスクの前に待機する必要がある場合完了したら、fixedDelayが適しています。 fixedDelay時間を慎重に設定すると、実行中のスレッドが新しいタスクを開始する前にジョブを完了するのに十分な時間を確保できます。
明確にすべきことの1つは、fixedRate
は、実行が特定の時間間隔で開始することを意味しないということです。
1つの実行に時間がかかりすぎる(固定レートを超える)場合、次の実行は開始します[〜#〜] after [〜#〜] _@Async
_でない限り、前の実行が終了しますおよび_@EnableAsync
_が提供されます。 SpringのThreadPoolTaskScheduler
実装の一部である次のソースコードは、その理由を説明しています。
_@Override
public void run() {
Date actualExecutionTime = new Date();
super.run();
Date completionTime = new Date();
synchronized (this.triggerContextMonitor) {
this.triggerContext.update(this.scheduledExecutionTime, actualExecutionTime, completionTime);
if (!this.currentFuture.isCancelled()) {
schedule();
}
}
}
_
前のタスクが終了した後(super.run()
)、次のタスクがスケジュールされた(schedule()
)だけであることがわかります。 _@Async
_および_@EnableAsync
_の場合、super.run()
は非同期関数であり、すぐに戻ります。したがって、次のタスクは前のタスクが実際に終了するのを待つ必要はありません。
Springの@Scheduled
アノテーションを使用してスケジュールされたタスクを実行できますが、プロパティfixedDelay
およびfixedRate
に基づいて実行の性質が変わります。
fixedDelay
プロパティは、タスクの実行のfinish time
とstart time
の間にn
millisecond
の遅延があることを確認しますタスクの次の実行。
このプロパティは、タスクのインスタンスが常に1つだけ実行されるようにする必要がある場合に特に役立ちます。依存ジョブの場合、非常に役立ちます。
fixedRate
プロパティは、n
millisecond
ごとにスケジュールされたタスクを実行します。タスクの以前の実行をチェックしません。
これは、タスクのすべての実行が独立している場合に便利です。メモリとスレッドプールのサイズを超えないと予想される場合、fixedRate
は非常に便利です。
ただし、着信タスクがすぐに終了しない場合、「メモリ不足例外」が発生する可能性があります。
これらの方法が何をするかについて、矛盾したアドバイスがあるようです。おそらく、動作は、スプリングコンテキストに登録されているtaskScheduler
またはExecutor
Beanに応じて変わる可能性があります。 @Ammar Akouriの回答が最も近いことがわかりました。
ScheduledThreadPoolExecutor
(完全なテストソースを以下に提供)を使用して見つけたものです。
fixedDelay
もfixedRate
もタスクの同時実行を許可しませんfixedDelay
は、前の呼び出しのendを待ってから、将来の一定の時間に新しい呼び出しをスケジュールします。したがって、一度に複数のタスクをキューに入れることはありません。fixedRate
は、毎周期新しい呼び出しをスケジュールします。一度に複数のタスクをキューに入れます(潜在的に無制限)が、タスクを同時に実行することはありません。サンプルテスト(Kotlin/JUnit):
class LearningSchedulerTest {
private lateinit var pool: ScheduledExecutorService
@Before
fun before() {
pool = Executors.newScheduledThreadPool(2)
}
@After
fun after() {
pool.shutdown()
}
/**
* See: https://stackoverflow.com/questions/24033208/how-to-prevent-overlapping-schedules-in-spring
*
* The documentation claims: If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.
* https://docs.Oracle.com/javase/8/docs/api/Java/util/concurrent/ScheduledThreadPoolExecutor.html#scheduleAtFixedRate-Java.lang.Runnable-long-long-Java.util.concurrent.TimeUnit-
*/
@Test
fun `scheduleAtFixedRate schedules at fixed rate`() {
val task = TaskFixture( initialSleep = 0)
pool.scheduleAtFixedRate({task.run()}, 0, 10, TimeUnit.MILLISECONDS )
Thread.sleep(15)
Assert.assertEquals(2, task.invocations.get())
Thread.sleep(10)
Assert.assertEquals(3, task.invocations.get())
Thread.sleep(10)
// 1 initial and 3 periodic invocations
Assert.assertEquals(4, task.invocations.get())
}
@Test
fun `scheduleAtFixedRate catches up on late invocations`() {
val task = TaskFixture(initialSleep = 30)
pool.scheduleAtFixedRate({task.run()}, 0, 10, TimeUnit.MILLISECONDS )
Thread.sleep(15) // we see no concurrent invocations
Assert.assertEquals(1, task.invocations.get())
Thread.sleep(10) // still no concurrent invocations
Assert.assertEquals(1, task.invocations.get())
Thread.sleep(10)
// 1 initial and 3 periodic invocations
Assert.assertEquals(4, task.invocations.get())
}
@Test
fun `scheduleWithFixedDelay schedules periodically`() {
val task = TaskFixture( initialSleep = 0)
pool.scheduleWithFixedDelay({task.run()}, 0, 10, TimeUnit.MILLISECONDS )
Thread.sleep(35)
// 1 initial and 3 periodic invocations
Assert.assertEquals(4, task.invocations.get())
}
@Test
fun `scheduleWithFixedDelay does not catch up on late invocations`() {
val task = TaskFixture( initialSleep = 30)
pool.scheduleWithFixedDelay({task.run()}, 0, 10, TimeUnit.MILLISECONDS )
Thread.sleep(35)
// 1 initial invocation, no time to wait the specified 10ms for a second invocation
Assert.assertEquals(1, task.invocations.get())
}
class TaskFixture(val initialSleep: Long) {
var invocations = AtomicInteger()
fun run() {
invocations.incrementAndGet()
if (invocations.get() == 1){
Thread.sleep(initialSleep)
}
}
}
}
Fixed Delay:最後の実行が終了する次の実行時間を具体的に制御します。
固定レート:最後の呼び出しがまだ実行されている場合でも、Springが定期的な間隔でタスクを実行します。