scheduleAtFixedRateとscheduleWithFixedDelay


117

主な違いは何だscheduleAtFixedRatescheduleWithFixedDelayの方法ScheduledExecutorServiceは

scheduler.scheduleAtFixedRate(new Runnable() {
    @Override
    public void run() {
        System.out.println("scheduleAtFixedRate:    " + new Date());
    }
}, 1, 3L , SECONDS);

scheduler.scheduleWithFixedDelay(new Runnable() {
    @Override
    public void run() {
        System.out.println("scheduleWithFixedDelay: " + new Date());
    }
}, 1, 3L , SECONDS);

それらは正確に同じ時間に印刷され、それらは正確に同じ間隔で実行されるようです。

回答:


206

メソッドThread.sleep(1000);内に呼び出しを追加してみてくださいrun()...基本的には、前の実行いつ終了するかと(論理的に)いつ開始するかに基づいて何かをスケジュールすることの違いです。

たとえば、アラームを1時間に1回の固定レートで鳴るようにスケジュールし、鳴るたびに1杯のコーヒーを飲んでいるとします。これには10分かかります。それが真夜中に始まると仮定すると、私は次のようになります:

00:00: Start making coffee
00:10: Finish making coffee
01:00: Start making coffee
01:10: Finish making coffee
02:00: Start making coffee
02:10: Finish making coffee

1時間の固定遅延でスケジュールすると、次のようになります。

00:00: Start making coffee
00:10: Finish making coffee
01:10: Start making coffee
01:20: Finish making coffee
02:20: Start making coffee
02:30: Finish making coffee

どちらを使用するかは、タスクによって異なります。


18
コーヒーを作るのに1時間以上かかる場合、fixedRateシナリオではどうなりますか?
Brett VanderVeen 2014年

5
@BrettVanderVeen:それは問題のエグゼキューター次第だと思います。時間どおりにスケジュールされますが、実行されるかどうかは、そのエグゼキューターがスレッドを使用できるかどうかによって異なります。さまざまなシナリオでこれがどのように機能するかを確認するために実験することをお勧めします。
Jon Skeet、2014年

8
@BrettVanderVeen ドキュメントから、「このタスクの実行にその期間よりも時間がかかる場合、後続の実行が遅れて開始される可能性がありますが、同時に実行されません。」つまり、準拠する実装では、前の実装が完了するまで次の実装を実行できません。
M.ジャスティン

私のような初心者のために、表示された出力(コーヒー)の作業コードを提供できますか?
MuneshSingh

@MuneshSingh:この質問ではありません。これは、固定レートでのスケジューリングと固定遅延でのスケジューリングの違いを説明することを求めています。とにかく、これを自分で実装することはありません。組み込みのエグゼキュータを使用します。
Jon Skeet

57

呼び出しscheduleAtFixedRateメソッドの時系列を視覚化します。最後の実行が期間よりも長い場合、次の実行がすぐに開始されます。それ以外の場合は、一定期間後に開始されます。

呼び出しの時系列のscheduleAtFixedRateメソッド

呼び出しscheduleWithFixedDelayメソッドの時系列。次の実行は、実行時間に関係なく、ある実行の終了と次の実行の開始の間の遅延時間の後に開始されます

時系列の呼び出しscheduleWithFixedDelayメソッド

希望があなたを助けることができます


scheduleAtFixedRate時系列図で言及されている「余分な」単語を理解できませんでした。
MuneshSingh

1
@MuneshSinghこれは、タスクの実行時間が予定よりも長いことを示すためのものです。そのため、「余分な」時間がかかり、次の実行がすぐに開始されます。
Viorel

@Viorel明確にしていただきありがとうございます。それは、「期間」が2つの連続した実行間の正確な時間遅延ではないことを意味しますか。
MuneshSingh

1
@MuneshSingh期間は固定されていますが、一度通過すると現在のタスクを停止しません。この実行と次の実行の間に遅延はありません。「タイムアウト」を作成する場合は、フューチャーを保持し、別のエグゼキューターでキャンセルすることができます。簡単に言うと、「期間」の時間が経過した後、最初の実行を開始し、次の実行をできるだけ早く開始するということです。
Viorel

4

このscheduleAtFixedRate()メソッドは、前のタスクが終了したかどうか関係なく、新しいタスクを作成し、それをエグゼキューターに送信します

一方、このscheduleWithFixedDelay()メソッドは、前のタスクが終了した後で新しいタスクを作成します。


あなたは2度書いたscheduleAtFixedRate:)
Vlad

3

Java Docを読んだ方がわかりやすいでしょう

ScheduledFuture scheduleAtFixedRate(Runnable command、long initialDelay、long period、TimeUnit unit) 定期的なアクションを作成して実行し、指定された初期遅延の後で最初に有効になり、その後、指定された期間で有効になります。つまり、実行は、initialDelay、initialDelay + period、initialDelay + 2 * periodなどの後に開始されます。

ScheduledFuture scheduleWithFixedDelay(Runnable command、long initialDelay、long delay、TimeUnit unit) 所定の初期遅延の後で最初に有効になり、その後、ある実行の終了と次の実行の開始との間に指定の遅延が続く定期的なアクションを作成して実行します。


1

最初のスレッドが時間がかかりすぎて所定の期間で終了しない場合、scheduleAtFixedRateには1つの問題があります。最初のタスクが終了すると、2番目の連続したスレッドは開始されず、最初のスレッドがタスクとgievn期間を完了している間はすぐには開始されません。経過しました。JVMは、次のタスクがいつ実行されるかを決定します。

私はそれがあなたが方法を選ぶのを助けると思います


1
何?JVMが決定しますか?それはどういう意味ですか?runnableはドキュメントに従ってそれ自体と同時に実行されないことは事実ですが、カスタムまたは標準である可能性のあるエグゼキューScheduledThreadPoolExecutor
ター

いいえ、アプリケーションで同様の問題が見つかりました。15分間隔を指定し、最初のタスクが15分で完了せず、15.30秒かかるため、2番目のタスクはすぐに開始されませんでした。これは標準的な動作ではないので、8分で私はこの動作を制御できるかどうかはわかりません。
user1047873 2014

教科書のタスクキューイングのように聞こえます。
Ordous、2014

はい、それはあなたのエグゼキュータのすべてのスレッドがすでに何かをするのにビジーであり、あなたのタスクがやるべきことのキューに入れられることを単に意味します。(注:このキューを確認するか、エグゼキュータースレッドが何を行っているかを確認する必要があります)。これをどのように制御するかは、使用しているエグゼキュータのタイプによって異なります。この特定のタスク専用に別の1スレッドエグゼキュータを作成すると、何も待機しません。または、現在のエグゼキューターにスレッドを増やします。または、戦略を変更します。
Ordous、2014

0

簡単なプログラムを書いてみましょう:

import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit

var time = 0L
var start = System.currentTimeMillis()
val executor = Executors.newScheduledThreadPool(1)
executor.scheduleWithFixedDelay({
    if (time >= 12_000L) {
        executor.shutdown()
    } else {
        Thread.sleep(2000L)
        val now = System.currentTimeMillis()
        time += now - start
        System.out.println("Total $time delay ${now - start}\n")
        start = now
    }
}, 0L, 1000L, TimeUnit.MILLISECONDS)

そして結果を見てください:

| scheduleWithFixedDelay |   scheduleAtFixedRate  |
|:----------------------:|:----------------------:|
| Total 2001 delay 2001  | Total 2003 delay 2003  |
| Total 5002 delay 3001  | Total 4004 delay 2001  |
| Total 8003 delay 3001  | Total 6004 delay 2000  |
| Total 11003 delay 3000 | Total 8004 delay 2000  |
| Total 14003 delay 3000 | Total 10005 delay 2001 |
|          ---           | Total 12005 delay 2000 |

実行時間は待機よりも長いことに注意してください

scheduleWithFixedDelayは遅延を維持します
scheduleAtFixedRateは遅延を削除します


-1
scheduledExecutorService.scheduleAtFixedRate(() -> {
        System.out.println("runnable start"); try { Thread.sleep(5000);  System.out.println("runnable end");} catch
     (InterruptedException e) { // TODO Auto-generated catch block
      e.printStackTrace(); }}, 2, 7, TimeUnit.SECONDS);



     scheduledExecutorService.scheduleWithFixedDelay(() -> {
     System.out.println("runnable start"); try { Thread.sleep(5000); System.out.println("runnable end");} catch
     (InterruptedException e) { // TODO Auto-generated catch block
     e.printStackTrace(); } }, 2, 7, TimeUnit.SECONDS);

実行するだけで違いがわかります。ありがとうございました


1
コードがOPの問題をどのように解決するかも説明してください。:)
Yash
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.