最初にエグゼキュータを作成します。
いくつかの可能性があります。
あなたのタスクがステータスを照会するための単純なインターフェース(「NeedReschedule」または「Completed」の列挙型のようなもの)を実装するとRunnable
仮定すると、タスクとエグゼキューターをインスタンス化パラメーターとして受け取るタスクのラッパー(実装)を実装します. このラッパーは、バインドされているタスクを実行し、後でそのステータスを確認し、必要に応じて、終了する前にエグゼキューターで自身のコピーを再スケジュールします。
または、実行メカニズムを使用して、タスクを再スケジュールする必要があることをラッパーに通知することもできます。このソリューションは、タスクに特定のインターフェイスを必要としないという意味でより単純であるため、単純なRunnable
ものを問題なくシステムに投入できます。ただし、例外により計算時間が長くなります (オブジェクトの構築、スタック トレースなど)。
例外シグナル伝達メカニズムを使用したラッパーの可能な実装を次に示します。ラップされた runnable によって起動される可能性があるRescheduleException
クラス extendsを実装する必要があります (このセットアップでは、タスク用のより具体的なインターフェイスは必要ありません)。Throwable
別の回答で提案されているように単純なものを使用することもでき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());
}
}
(メッセージ キューを使用して) 他のスレッドの結果を監視し、必要に応じて再スケジュールするための専用スレッドを用意することもできますが、他のソリューションと比較して 1 つのスレッドが失われます。