9

スレッド プール内で実行されるスレッドのタイムアウトを設定したいと考えています。現時点では、次のコードがあります。

ExecutorService executor = Executors.newFixedThreadPool(8);
for(List<String> l: partition) {            
    Runnable worker = new WorkerThread(l);
    executor.execute(worker);
}       

executor.shutdown();
while (!executor.isTerminated()) {

}

このコードは、オブジェクトの大きなリストをサブリストに分割し、これらのサブリストをシングル スレッド内で処理するだけです。しかし、これはポイントではありません。

スレッドプール内の各スレッドにタイムアウトを与えたい。プール内のスレッドが 1 つだけの場合、次の解決策が見つかりました。

Future<?> future = null;

for (List<String> l : partition) {
    Runnable worker = new WorkerThread(l);
    future = executor.submit(worker);
}

try {
    System.out.println("Started..");
    System.out.println(future.get(3, TimeUnit.SECONDS));
    System.out.println("Finished!");
} catch (TimeoutException e) {
    System.out.println("Terminated!");
}

しかし、これは複数のスレッドでは機能しません。たぶん、各スレッドをリストに入れ、List<Future>このリストを繰り返し処理し、各futureオブジェクトのタイムアウトを設定する必要がありますか?

助言がありますか?

CountDownLatch を使用した後に編集:

CountDownLatch doneSignal = new CountDownLatch(partition.size());
List<Future<?>> tasks = new ArrayList<Future<?>>();
ExecutorService executor = Executors.newFixedThreadPool(8);
for (List<String> l : partition) {
    Runnable worker = new WorkerThread(l);
    tasks.add(executor.submit(doneSignal, worker));
}

doneSignal.await(1, TimeUnit.SECONDS);
if (doneSignal.getCount() > 0) {
    for (Future<?> fut : tasks) {
    if (!fut.isDone()) {
        System.out.println("Task " + fut + " has not finshed!");
        //fut.cancel(true) Maybe we can interrupt a thread this way?!
    }
    }
}

これまでのところうまくいきます。

次の質問は、タイムアウトになったスレッドを中断する方法です。fut.cancel(true)ワーカースレッドのいくつかの重要なループに次の構成を追加しようとしました:

if(Thread.interrupted()) {
    System.out.println("!!Thread -> " + Thread.currentThread().getName() + " INTERRUPTED!!");
        return;
}

そのため、ワーカー スレッドはタイムアウト後に「強制終了」されます。これは良い解決策ですか?

さらに: タイムアウトしたスレッドの名前をFutureインターフェイス経由で取得することは可能ですか? 現時点では、Thread.interrupted()コンストラクトの if 条件で名前を出力する必要があります。

手伝ってくれてありがとう!

よろしく

4

1 に答える 1

3

これを見たことがありますか?ExecutorService.invokeAll

それはまさにあなたが望むものでなければなりません: ワーカーのバンドルを呼び出し、時間がかかりすぎる場合はタイムアウトさせます。

コメント後の編集 - (新しいアイデア): CountDownLatchawait(long timeout, TimeUnit unit)を使用して、タスクが終了するのを待ち、 !経由でタイムアウトすることができます。その後、shutdownNow を実行して、どのタスクに時間がかかりすぎたかを確認することもできます...

編集2:

明確にするために:

  1. 終了したら、各 Worker が CountDownLatch をカウントダウンするようにします。
  2. await上記のラッチでタイムアウトのあるメイン実行スレッド。
  3. その呼び出しが戻ったら、ラッチのカウントをチェックして、タイムアウト ヒットがあったかどうかを確認できます (>0 の場合)。
  4. a) カウント = 0、すべてのタスクが時間内に終了しました。b) そうでない場合は、Future をループして、そのisDone. ExecutorService で shutdown を呼び出す必要はありません。
  5. Executor が不要になった場合は、shutdown を呼び出します。

注: ワーカーは、タイムアウトと Future の isDone() の呼び出しの間で終了できます。

于 2013-01-09T14:06:55.680 に答える