10

タスクをスケジュールし、特定のイベントが発生したときにそれらを削除する必要があるタスクがあります。私は ScheduledThreadPoolExecutor を使用してタスクをスケジュールしています。これは非常に簡単です。しかし、保留中のアイテムをキャンセルする 2 つの方法を見つけました。どちらも少し奇妙に見えます。

それらのいずれかが製品品質であるかどうかに興味があります。どちらでもない場合、あなたは何を提案しますか?

これが私がしていることのスケルトンです:

private final ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(1);

public void doStuff() {
    //...
    scheduler.schedule(new Runnable() {/*...*/}, 10, TimeUnit.MILISECONDS)
}

public void actOnEvent() {
    cancelPendingItems();
    doMoreStuff();
}

public void cancelPendnigItems() {
    // TODO implement me
}

これは候補 1 です。

public void cancelPendingItems() {
    scheduler.getQueue().clear();
}

これは候補 2 です。

public void cancelPendingItems() {
    for (Runnable task : scheduler.getQueue()) {
        scheduler.remove(task);
    }
}

どちらも、ScheduledExecutor インターフェイスで指定されていない ScheduledThreadPoolExecutor.queue プロパティに依存しているため、私にはハックのように見えます。ScheduledThreadPoolExecutor の不変式に違反する可能性があり、それを検出するのが遅すぎるのではないかと少し心配しています。

では、これらのスニペットは、私が望んでいることを実行するでしょうか? それを行うためのより良い/よりクリーンな方法はありますか?

4

3 に答える 3

11

ScheduledExecutorService.scheduleを返すことに注意してくださいScheduledFuture。これらを保存するだけで、cancel メソッドが呼び出されたときcancelに、保存された先物でメソッドを使用して、将来の反復をキャンセルします。

于 2012-09-24T16:42:05.660 に答える
5

私はを使用しますList<Future>

private final List<Future> futures = ...

public void doStuff() {
    futures.add(scheduler.schedule(new Runnable() {/*...*/}, 10,
        TimeUnit.MILISECONDS));
}

public void cancelPendingItems() {
    for(Future future: futures)
        future.cancel(true);
    futures.clear();
}
于 2012-09-24T16:42:41.977 に答える
2

Future.cancel(boolean mayInterruptIfRunning)

このタスクの実行をキャンセルしようとします。タスクが既に完了している、キャンセルされている、またはその他の理由でキャンセルできなかった場合、この試行は失敗します。成功し、キャンセルが呼び出されたときにこのタスクが開始されていない場合、このタスクは決して実行されません。タスクがすでに開始されている場合、mayInterruptIfRunning パラメータは、タスクを停止するために、このタスクを実行しているスレッドを中断する必要があるかどうかを決定します。

または、ScheduledThreadPoolExecutor#shutdownNowを使用することもできます

アクティブに実行中のすべてのタスクの停止を試み、待機中のタスクの処理を停止し、実行を待機していたタスクのリストを返します。

アクティブに実行中のタスクの処理を停止するための最善の努力以外の保証はありません。この実装は Thread.interrupt() を介してタスクをキャンセルするため、割り込みに応答しないタスクは決して終了しない可能性があります。

したがってInterruptedException、キャンセルされているスレッドを安全に終了できるように処理する必要があります。

于 2012-09-24T16:48:09.723 に答える