0

作成したすべてのスレッドを待機するワークフローを作成しました。この例は 99% のケースで機能しますが、すべてのスレッドが完了するよりも早く waitForAllDone メソッドが終了することがあります。waitForAllDone の後、作成されたスレッドを使用しているストリームを閉じているため、例外が発生するため、私はそれを知っています

Caused by: java.io.IOException: Stream closed

私のスレッドは次で始まります:

  @Override
  public void run() {
    try {
      process();
    } finally {
      Factory.close(this);
    }
  }

閉鎖:

  protected static void close(final Client client) {
    clientCount--;
  }

スレッドを作成するとき、これを呼び出します:

  public RobWSClient getClient() {
    clientCount++;
    return new Client();
  }

ファクトリ内の clientCount 変数:

  private static volatile int clientCount = 0;

待つ:

  public void waitForAllDone() {
    try {
      while (clientCount > 0) {
        Thread.sleep(10);
      }

    } catch (InterruptedException e) {
      LOG.error("Error", e);
    }
  }
4

3 に答える 3

5

clientCountviaの変更と読み取りを保護する必要がありますsynchronized。主な問題は、clientCount--andclientCount++がアトミック操作ではないため、2 つのスレッドがclientCount--/clientCount++を実行して間違った結果になる可能性があることです。

上記のように使用するだけvolatileでは、フィールドに対するすべての操作がアトミックである場合にのみ機能します。それらはそうではないので、ロック機構を使用する必要があります。アントンが述べているように、ここでAtomicIntegerは優れた選択です。スレッドローカルでないことを確認するには、finalまたはのいずれかにする必要があることに注意してください。volatile

そうは言っても、Java 1.5 以降の一般的なルールは、 のExecutorService代わりに a を使用することですThreads。これを Guava のFuturesクラスと組み合わせて使用​​すると、すべてが完了するのを次のように簡単に待つことができます。

Future<List<?>> future = Futures.successfulAsList(myFutureList);
future.get();
// all processes are complete

Futures.successfulAsList

于 2012-11-20T12:21:19.863 に答える
3

あなたのコードの残りの部分に問題がないかどうかはわかりませんが、このように volatile 変数をインクリメントすることはできません - clientCount++; AtomicInteger代わりに使用

于 2012-11-20T12:22:12.013 に答える
1

スレッドが終了するのを待つ最善の方法は、高度な同時実行機能の 1 つを使用することです。この場合、最も簡単な方法は ExecutorService を使用することです。

次のようにして、エグゼキューターに新しいタスクを「提供」します。

...
ExecutorService executor = Executors.newFixedThreadPool(POOL_SIZE);
...

Client client = getClient(); //assuming Client implements runnable
executor.submit(client);
...

public void waitForAllDone() {
    executor.awaitTermination(30, TimeUnit.SECOND) ; wait termination of all threads for 30 secs
... 
}

このようにして、ビジーな待機やスリープ/起動サイクルで貴重な CPU サイクルを無駄にすることはありません。詳細については、 ExecutorServiceのドキュメントを参照してください。

于 2012-11-20T12:52:22.397 に答える