11

繰り返されるタスクの期間がその期間よりも長い場合があります (私の場合、これは一度に何時間も発生する可能性があります)。実行に 7 分かかり、10 分ごとに実行されるようにスケジュールされている繰り返しタスクを考えてみてください。

Timer クラスと ScheduledThreadPoolExecutor クラスの両方に、通常このタイプの機能に使用される scheduleAtFixedRate メソッドがあります。しかし、どちらも「遅れると追いつこうとする」という特徴があります。言い換えると、Timer が数回の実行で遅れた場合、Timer は作業のキューを作成します。これは、どのタスクもより長くかからなかった場合に発生したであろう実行回数に追いつくまで、継続的に処理されます。指定された期間。前の実行が完了していない場合、現在の実行をスキップすることで、この動作を回避したいと考えています。

プールされたエグゼキューターの afterExecution メソッドをいじり、遅延を再計算し、新しい遅延でランナブルを再スケジュールすることを含む 1 つの解決策がありますが、より簡単な方法があるかどうか、またはこの機能がどこかの共通ライブラリに既に存在するかどうか疑問に思っていました. 固定期間ではなく固定遅延を使用したスケジューリングについては知っていますが、固定時間にタスクを実行することが重要であるため、これはうまくいきません。私の afterExecution ソリューションよりも簡単なオプションはありますか?

4

3 に答える 3

20

長時間実行されるタスク自体をScheduledExecutorService自体ではなく、バックグラウンドスレッドで実行することが必要だと思います。その後、固定レートのタスクは常に迅速に完了します。これは、実際のタスクをバックグラウンドで開始するかどうか(または、前回から実行されている場合は開始しないかどうか)を確認するためにのみ使用されるためです。

ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
final Runnable actualTask = null;

executorService.scheduleAtFixedRate(new Runnable() {
    private final ExecutorService executor = Executors.newSingleThreadExecutor();
    private Future<?> lastExecution;
    @Override
    public void run() {
        if (lastExecution != null && !lastExecution.isDone()) {
            return;
        }
        lastExecution = executor.submit(actualTask);
    }
}, 10, 10, TimeUnit.MINUTES);
于 2012-08-14T02:26:08.057 に答える
1

コーディネーターと呼ばれる 3 番目のクラスを作成します。コーディネーターには、isRunning を true に設定し、別のスレッドがまだ実行されていない場合に true を返す、同期された startRunning() メソッドがあります。isRunning を false に設定する、同期された stopRunning メソッドも必要です。ランナブルがすでに実行されている場合は true を返します。このクラスのインスタンスを 1 つ作成し、構築するすべてのランナブルへの参照を渡します。ランナブルの run メソッドでは、最初に startRunning を呼び出し、戻り値をチェックして、別の実行がまだ実行されていないことを確認します。コードを必ず try-finally の run() に配置し、finally ブロック内から stopRunning を呼び出してください。

于 2012-08-14T03:41:29.527 に答える