2013-04-03 8 views
5

2つのタスクがあります。最初のタスク(work)が再発し、2番目のタスク(cleanup)がいくつかのリソースを解放します。 cleanupタスクは、再発したworkタスクが完了した後で1回だけ実行され、再度実行されません。ここでの問題はcancel()はすぐに返すことである定期タスクがキャンセルされたときのコールバック

ScheduledExecutorService service = ...; 
ScheduledFuture<?> future = service.scheduleAtFixedRate(work, ...); 

// other stuff happens 

future.cancel(false); 
cleanup.run(); 

私の最初の本能は、このようなものでした。したがって、workが実行されている場合は、cleanupが重複します。

理想的には、GuavaのFutures.addCallback(ListenableFuture future, FutureCallback callback)のようなものを使用します。 (グアバ15はsomething like thatを有するかもしれない)。一方

futureはもはや実行しているworkをキャンセルしていない場合にどのようにコールバックを発射することができますか?

答えて

1

これは私が思いついた解決策です。それはかなりシンプルなようですが、私はまだそこにもっと一般的な、そして/またはエレガントな解決策があると仮定します。そして、私は私のコールバックを発射するラッパーを作成

private static final class SynchronizedRunnable implements Runnable { 
    private final Object monitor; 
    private final Runnable delegate; 

    private SynchronizedRunnable(Object monitor, Runnable delegate) { 
     this.monitor = monitor; 
     this.delegate = delegate; 
    } 

    @Override 
    public void run() { 
     synchronized (monitor) { 
      delegate.run(); 
     } 
    } 
} 

:私は本当に私は私のランナブルで相互排他を課すためのラッパーを作成まず

...グアバなどのライブラリに1を見てみたいと思います cancelの成功invokations:

private static final class FutureWithCancelCallback<V> extends ForwardingFuture.SimpleForwardingFuture<V> { 

    private final Runnable callback; 

    private FutureWithCancelCallback(Future<V> delegate, Runnable callback) { 
     super(delegate); 
     this.callback = callback; 
    } 

    @Override 
    public boolean cancel(boolean mayInterruptIfRunning) { 
      boolean cancelled = super.cancel(mayInterruptIfRunning); 
      if (cancelled) { 
       callback.run(); 
      } 
      return cancelled; 
    } 
} 

その後、私は私自身の方法で一緒にそれをすべてロール:

private Future<?> scheduleWithFixedDelayAndCallback(ScheduledExecutorService service, Runnable work, long initialDelay, long delay, TimeUnit unit, Runnable cleanup) { 

    Object monitor = new Object(); 

    Runnable monitoredWork = new SynchronizedRunnable(monitor, work); 

    Runnable monitoredCleanup = new SynchronizedRunnable(monitor, cleanup); 

    Future<?> rawFuture = service.scheduleAtFixedRate(monitoredWork, initialDelay, delay, unit); 

    Future<?> wrappedFuture = new FutureWithCancelCallback(rawFuture, monitoredCleanup); 

    return wrappedFuture; 
} 
0

は、なぜあなたは、このように、あなたはおそらく終了したとworkを実行するのを待つことができ、シャットダウンへのあなたのエグゼキュータのサービスを教えてくれます

// other stuff happens 

future.cancel(false); 
service.shutdown(); 
service.awaitTermination(1, TimeUnit.DAYS); 
cleanup.run(); 

この

をしません。

+0

私はexecutorサービスのすべてのタスクをキャンセルするつもりはありません...私はスケジュールされたタスクだけをキャンセルします。実際、ScheduledExecutorServiceは私に提供されており、他の誰がタスクをサブミットしているのかわかりません。 – Drew

+0

ああ、残念です...それは、 'ScheduledExecutorService'を拡張してしまい、より多くの選択肢があります。あなたの '仕事'インスタンスはどうですか?それはあなたの手にありますか? – skirsch

+0

はい、作業とクリーンアップのタスク/ Runnablesは私のものです。私は作業/クリーンアップのビジネスロジックからスレッド/エグゼキュータの懸念を分離したいと思います...これらのクラスをいくつかのTaskから継承させてもらえれば幸いです。あるいは、他の実行可能/呼び出し可能なクラスでそれらをラップすることもできます。 – Drew

1

もう一度打ってみましょう。コマンドを拡張するか、または実行したものをラップすることができます。Runnable/Callableこれを見て:

public static class RunnableWrapper implements Runnable { 

    private final Runnable original; 
    private final Lock lock = new ReentrantLock(); 

    public RunnableWrapper(Runnable original) { 
     this.original = original; 
    } 

    public void run() { 
     lock.lock(); 
     try { 
      this.original.run(); 
     } finally { 
      lock.unlock(); 
     } 
    } 

    public void awaitTermination() { 
     lock.lock(); 
     try { 
     } finally { 
      lock.unlock(); 
     } 
    } 

} 

は、だから、cancelを呼び出した後

ScheduledExecutorService service = ...; 
RunnableWrapper wrapper = new RunnableWrapper(work); 
ScheduledFuture<?> future = service.scheduleAtFixedRate(wrapper, ...); 

// other stuff happens 

future.cancel(false); 
wrapper.awaitTermination(); 
cleanup.run(); 

にコードを変更することはできませんいずれかworkはもはや実行されているとawaitTermination()戻ってすぐ、またはそれが実行されているとawaitTermination()ブロックそれが行われるまで。

+0

あなたのソリューションは私とほとんど同じです。私は自分の解決策を受け入れました。なぜなら、それはクライアントの立場から見れば「火と忘れ」が多いからです。それは私の特定のシナリオでは素晴らしいプロパティです。 – Drew

関連する問題