17

エグゼキュータを使用してタスクを送信しましたが、しばらくすると(たとえば、5分)停止する必要があります。私はこのようにしてみました:

   for (Future<?> fut : e.invokeAll(tasks, 300, TimeUnit.SECONDS)) {
         try {
             fut.get(); 
         } catch (CancellationException ex) {
             fut.cancel(true);   
             tasks.clear();
         } catch(ExecutionException ex){
             ex.printStackTrace(); //FIXME: gestita con printstack       
         }
   }

しかし、常にエラーが発生します。タスクによって変更してからスレッドで読み取る必要がある共有ベクターがあり、すべてのタスクを停止しても、タイムアウトが発生すると、次のようになります。

Exception in thread "Thread-1" java.util.ConcurrentModificationException

何か問題がありますか?5分経ってもまだ機能している送信済みのタスクを停止するにはどうすればよいですか?

4

5 に答える 5

29

呼び出しcancel()たからFutureといって、タスクが自動的に停止するわけではありません。タスクが停止することを確認するには、タスク内でいくつかの作業を行う必要があります。

  • cancel(true)タスクに割り込みが送信されるように使用します。
  • ハンドルInterruptedException。タスク内の関数がをスローする場合はInterruptedException、例外をキャッチしたらできるだけ早く正常に終了するようにしてください。
  • Thread.currentThread().isInterrupted()タスクが継続的な計算を行うかどうかを定期的に確認してください。

例えば:

class LongTask implements Callable<Double> {
    public Double call() {
        
         // Sleep for a while; handle InterruptedException appropriately
         try {
             Thread.sleep(10000);
         } catch (InterruptedException ex) {
             System.out.println("Exiting gracefully!");
             return null;
         }


         // Compute for a while; check Thread.isInterrupted() periodically
         double sum = 0.0;
         for (long i = 0; i < 10000000; i++) {
             sum += 10.0
             if (Thread.currentThread().isInterrupted()) {
                 System.out.println("Exiting gracefully");
                 return null;
             }
         }

         return sum;
    } 
}

また、他の投稿で言及されているようConcurrentModificationExceptionに、スレッドセーフクラスを使用している場合でもスローされる可能性があります。これはVector、から取得するイテレータがVectorスレッドセーフではないため、同期する必要があるためです。拡張されたforループはイテレータを使用するため、次の点に注意してください。

final Vector<Double> vector = new Vector<Double>();
vector.add(1.0);
vector.add(2.0);

// Not thread safe!  If another thread modifies "vector" during the loop, then
// a ConcurrentModificationException will be thrown.
for (Double num : vector) {
    System.out.println(num);
}

// You can try this as a quick fix, but it might not be what you want:
synchronized (vector) {    // "vector" must be final
    for (Double num : vector) {
        System.out.println(num);
    }
}
于 2009-09-13T16:57:13.753 に答える
1

これは、Exceutorsがあなたのを繰り返している間にConcurrentModificationExceptionあなたの呼び出しから来ています。あなたがしようとすることができるのはあなたのExecutorServiceを呼び出すことですtasks.clear()tasks VectorshutdownNow()

于 2009-09-13T16:15:56.477 に答える
0

の最も一般的なケースConcurrentModificationExceptionは、vectorが繰り返されると同時に変更される場合です。多くの場合、これは単一のスレッドで実行されます。反復全体でをロックする必要がありVectorます(デッドロックしないように注意してください)。

于 2009-09-13T15:57:27.530 に答える
0

fut.get()はブロッキング呼び出しです。タイムアウトした後でも、タスクが完了するまでブロックします。可能な限り5分マークの近くで停止したい場合は、割り込みフラグを確認する必要があります。割り込み状態を保持するThread.isInterrupted()メソッドを使用して確認することをお勧めします。すぐに停止し、状態をクリーンアップする必要がない場合は、Futureによってキャッチされ、ExecutionExceptionとして示される例外をスローします。

fut.cancel(true)は、invokeAll()メソッドがすでにこれを行っているため、何もしません。

「tasks」コレクションを別の場所で使用しない限り、おそらくclear()を呼び出す必要はありません。clear()を呼び出すまでにinvokeAll()メソッドがListで実行されるため、これが問題の原因になることはありません。ただし、実行する新しいタスクのリストの作成を開始する必要がある場合は、古い新しいタスクのリストを使用するのではなく、新しいタスクのリストを作成することをお勧めします。

残念ながら、私はあなたの問題に対する答えを持っていません。ここには、診断するのに十分な情報がありません。提供したコードスニペットには、ライブラリクラス/メソッドの不適切な(不要な)使用を示すものはありません。おそらく、1行のエラーではなく、完全なスタックトレースを含めた場合です。

于 2009-09-14T18:42:49.873 に答える
-1

fut.cancel(true); をfinallyブロックに 入れます

于 2012-10-17T03:55:47.770 に答える