実行プログラムを最初に作成します。
あなたはいくつかの可能性があります。
ステータスが「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());
}
}
他のソリューションに比べて、あなたはまた、他のスレッドの結果(メッセージ・キューを使用)を監視し、必要に応じてスケジュールを変更するには専用のスレッドを持つことができますが、あなたは一つのスレッドを失います。
現在のタスクと同じ新しいタスクを作成してキューに入れるだけです。現在のタスクを終了する – hoaz
@hoaz:あなたはタスク内からエグゼキュータを参照することを意味しますか? – Cratylus
@Cratylus - はい、タスクにエグゼキュータの参照が戻ってきた場合は、自身に再キューイングできます。エグゼキュータの保留中のタスク・キューが無制限であることを確認するか、自分自身をデッドロックする可能性があります。 – jtahlborn