2013-09-28 26 views
5

ためのパターンをキャンセル長いruningてメソッドをキャンセルする軽量なパターンがあり、ウィッヒは、このようなコードを置き換える:軽量長時間実行メソッドは、Java

public void longComputations() { 
    ... first step... 
    if (cancelled) { 
     rollbackWork(); 
     return; 
    } 
    ... second step... 
    if (cancelled) { 
     rollbackWork(); 
     return; 
    } 
    ... third step... 
    if (cancelled) { 
     rollbackWork(); 
     return; 
    } 
} 

私はTaskクラスを作ることができることを知って、タスクへのステップを細分化オブジェクトを作成し、キューを作成し、キャンセルチェックをループでステップごとにタスクを実行しますが、私はちょうどそこにシンプルなコード構造パターンがあるのだろうかと思っています。

答えて

4

私はそのような仕組みに気づいていません。 rollbackWork()を実行できるように作業を追跡する必要があるため、このロジックをさらに進化させたい場合は、うまく設計されたオブジェクト指向ソリューションをお勧めします。通常、このようなシナリオでは、私はまだかなり軽量見つけるcommand patternを使用して実装することができます

// Task or Command 
public interface Command { 
    void redo(); 
    void undo(); 
} 

スケジューラまたはキューは、その後、このようなタスク/コマンドの実装を実行すると、順番にそれらをロールバックの世話をすることができます。

+2

1 GoFのコマンドパターン –

+0

私は十分な時間の期間のために受け付けます。しかし、実際の答えは「いいえ、単純なコード構造ではありません」ということです。あなたのソリューションは非常に小さなプロセスでは少し重いです(私は 'タスク・オブジェクトにステップを細分する 'と言っていました)が、スレッド・エクゼチション/スレッドの中断を伴うより良い方法だと思います。 –

+0

@killer_PL:はい、スレッドを使用すると、タスクが複雑すぎるかもしれません... –

1

ステップがInterruptedExceptionをスローするメソッドを呼び出す場合は、Thread.interrupt()を使用できます。ロールバックを適切に行うには、まだ十分な状態情報を維持する必要があります。手順はこの方法を中断することができない場合

することは、あなたはは、それが本質的に安全であることから非推奨Thread.stop()メカニズムに頼って検討するべきではありません。

説明した内容を正確に行うことは理にかなっているようです。このワークフローロジックを計算ステップとは独立したクラスにカプセル化します。キャンセルや中断をサポートし、実行するタスクを受け入れる必要があります。ワークフローに入力するタスクには、計算を実行する方法と計算を実行する方法の少なくとも2つの方法が用意されている必要があります。

0

java.util.concurrentパッケージの使用を検討してください。 Callables(またはRunnables)として作業手順をラップする必要があります。

public class InterruptibleTest { 
    public static void main(String[] args) { try { 
     final ExecutorService queue = Executors.newFixedThreadPool(1); 
     queue.submit(new Callable<Void>() { @Override public Void call() { busyWait(1000); return null; } }); 
     queue.submit(new Callable<Void>() { @Override public Void call() { busyWait(1000); return null; } }); 
     queue.submit(new Callable<Void>() { @Override public Void call() { busyWait(1000); return null; } }); 
     final AtomicBoolean cancelled = new AtomicBoolean(); 
     new Thread() { @Override public void run() { 
       try { Thread.sleep(1500); } catch (InterruptedException ex) { } 
       queue.shutdownNow(); 
       cancelled.set(true); 
      } 
     }.run(); 
     if (cancelled.get()) { rollback(); } 
     queue.shutdown(); 
     System.out.println("Finished"); 
    } catch (Exception ex) { ex.printStackTrace(System.err); } } 

    public synchronized static void busyWait(int millis) { 
     System.out.println("Start"); 
     long until = System.currentTimeMillis() + millis; 
     while (System.currentTimeMillis() < until) { } 
     System.out.println("Stopped"); 
    } 
    public synchronized static void rollback() { 
     System.out.println("Rollback!"); 
    } 
} 

shutdownNow()は現在実行中の作業スレッドでinterrupt()を呼び出すかもしれないことに注意してください。停止可能でないコードの実行が終了する前にshutdownNow()が戻るため、ロールバック()を同期させる必要もあります。

+0

'new Thread(...)。run()'? – assylias

2

この編集はどうですか、パターンではありませんか?例外は非常に安いので、速くなければなりません。

public void caller(){ 
    try{ 
     longComputations(); 
    } catch (MeaningfulRuntimeException e){ 
     rollbackWork(e.getStep()); 
    } 
} 

public void longComputations() { 
    ... first step... 
    checkStatus(1); 

    ... second step... 
    checkStatus(2); 

    ... third step... 
    checkStatus(3); 
} 

public void checkStatus(int step){ 
    if (cancelled) { 
     ... we may rollback here or throw an exception ... 
     throw MeaningfulRuntimeException(step); 
    } 
} 
関連する問題