2012-11-20 14 views
5

Executorによって実行される一連のタスク(つまり、Runnable)があります。
各タスクには、続行するために有効な一定の条件が必要です。私は何らかの方法でExecutorをキューの最後に移動し、条件が有効でタスクを実行して終了できるときに実行しようとする方法があるかどうかを知ることに興味があります。executorキューにタスクを戻す方法はありますか

  1. Thread-1テイクキューからタスクとrunキューの最後に条件がまだ有効
  2. 作業ではありませんrunインサイド
  3. 呼ば停止し、Thread-1場所タスクさ:
    だから行動のようなものがあること は次のタスクを実行します
  4. (スレッドプールから)後でタスクをキュー状態から再度選択すると有効なのは で、タスクが実行されています実行済み
+0

現在のタスクと同じ新しいタスクを作成してキューに入れるだけです。現在のタスクを終了する – hoaz

+0

@hoaz:あなたはタスク内からエグゼキュータを参照することを意味しますか? – Cratylus

+1

@Cratylus - はい、タスクにエグゼキュータの参照が戻ってきた場合は、自身に再キューイングできます。エグゼキュータの保留中のタスク・キューが無制限であることを確認するか、自分自身をデッドロックする可能性があります。 – jtahlborn

答えて

2

実行プログラムを最初に作成します。

あなたはいくつかの可能性があります。

ステータスが「NeedReschedule」または「Completed」の列挙型のような単純なインターフェイスを実装していると仮定した場合、タスクを実行するラッパー(実装Runnable)を実装し、インスタンス化パラメータとして実行者。このラッパーは、バインドされているタスクを実行し、その後の状況を確認し、必要に応じて、終了する前にエグゼキュータ内の自身のコピーを再スケジュールします。

また、実行メカニズムを使用して、タスクを再スケジュールする必要があることをラッパーに通知することもできます。 この解決法は、タスクのための特定のインターフェイスを必要としないという意味で、シンプルであり、シンプルなRunnableが問題なくシステムにスローされる可能性があります。しかし、例外はより多くの計算時間(オブジェクト構築、スタックトレースなど)を必要とします。

例外シグナリングメカニズムを使用したラッパーの実装例です。 Throwableに拡張されたRescheduleExceptionクラスを実装する必要があります。これは、ラップされた実行可能ファイルによって起動される可能性があります(この設定では、タスクに対してより特定のインターフェイスは必要ありません)。別の回答で提案されているように単純なRuntimeExceptionを使用することもできますが、これがあなたが待っている例外であるかどうかを知るためにメッセージ文字列をテストする必要があります。

public class TaskWrapper implements Runnable { 

    private final ExecutorService executor; 
    private final Runnable task;  

    public TaskWrapper(ExecutorService e, Runnable t){ 
     executor = e; 
     task = t; 
    } 

@Override 
public void run() { 

    try { 
       task.run(); 
    } 
    catch (RescheduleException e) { 
     executor.execute(this); 
    } 
} 

ここでは、非常に単純なアプリケーションで、200回のラップされたタスクをランダムに実行して再スケジュールを求めています。

class Task implements Runnable { 

    @Override 
    public void run(){ 
    if (Maths.random() > 0.5) 
     throw new RescheduleException(); 
    }  
} 


public class Main { 

public static void main(String[] args){ 

    ExecutorService executor = Executors.newFixedThreadPool(10); 

    int i = 200; 
      while(i--) 
     executor.execute(new TaskWrapper(executor, new Task()); 
} 
} 

他のソリューションに比べて、あなたはまた、他のスレッドの結果(メッセージ・キューを使用)を監視し、必要に応じてスケジュールを変更するには専用のスレッドを持つことができますが、あなたは一つのスレッドを失います。

+0

あなたの提案についてもう少し詳しくお聞かせください。 – Cratylus

+0

'このラッパーは、バインドされたタスクを実行し、後でその状態を確認します.'どのように' Callable'sを使用していますか? – Cratylus

+0

簡単な実装(テストされていないコード)を提供しました。 – didierc

3

Java 6では、ThreadPoolExecutorコンストラクタにはBlockingQueue<Runnable>が使用され、キューに入れられたタスクの格納に使用されます。 poll()を無効にするようなブロッキングキューを実装して、「準備完了」ジョブを削除して実行しようとすると、pollが正常に処理されるようにすることができます。それ以外の場合、実行可能ファイルはキューの後ろに配置され、短時間のタイムアウト後にポーリングを再試行します。

+0

これは実装の詳細に依存しませんか?実装で* poll *を使用するかどうかを知るにはどうすればいいですか?たとえば、Oracleのソースコードに基づいていないようにしてください – Cratylus

+0

確実に 'poll'を使います。私は 'remove()'、 'poll()'、take()や 'poll(time、unit)'のどれかを使うことを知っています。 – mbatchkarov

+0

あなたの提案は魅力的ですが(+1)、ここでどのように役立つのか分かりませんが、チェックされる条件はグローバルな条件ではなく、実行中のRunnableの状態の一部です。 – Cratylus

3

ビジー待機が必要な場合を除き、 "有効"なのでキャンセルまたは強制終了する適切なポーリング間隔で繰り返しタスクをScheduledExecutorServiceに追加できます。

ScheduleExecutorService ses = ... 

ses.scheduleAtFixedRate(new Runnable() { 
    public void run() { 
     if (!isValid()) return; 
     preformTask(); 
     throw new RuntimeException("Last run"); 
    } 
}, PERIOD, PERIOD, TimeUnit.MILLI_SECONDS); 
+0

' RuntimeException'とは何ですか? – Cratylus

+0

タスクを繰り返すのを止める最も簡単な方法です。選択肢はありますが、少なくとも醜く複雑なものです。 –

+0

例外はキューの次のタスクには影響しません。 – Cratylus

関連する問題