0

すべてのスレッドが終了した後にスレッドの 1 つがステートメントを出力するマルチスレッド プログラムがあります。すべてのスレッドが終了したことをどのように知ることができますか?

ExecutorService pool = Executors.newCachedThreadPool();
    for(int i = 0; i < myList.size(); ++i) {
            pool.execute (new ThreadProcessRunnable (args));
    }


    public class ThreadProcessRunnable implements Runnable {
           public void run() {


           System.out.println("last thread should execute this");
    }
    }
4

4 に答える 4

3

これは、次の場合の理想的な使用例のように思えますExecutorService.invokeAll

ExecutorService pool = Executors.newCachedThreadPool();
List<Callable<Object>> tasks = new ArrayList<Callable<Object>>();
for(int i = 0; i < myList.size(); ++i) {
    tasks.add (Executors.callable(new ThreadProcessRunnable (args)));
}
List<Future<Object>> futures = pool.invokeAll(tasks);
System.out.println("All tasks finished");


public class ThreadProcessRunnable implements Runnable {
    public void run() {
        // do some stuff
    }
}

invokeAll提供されたすべてのタスクが完了するまでブロックListします。

printlnスレッドのメソッドの内部にどうしても必要な場合は、run私が考えることができる最も簡単な方法は、ある種のカウンターをAtomicInteger

public class ThreadProcessRunnable implements Runnable {
  private AtomicInteger taskCounter;

  public ThreadProcessRunnable(AtomicInteger counter) {
    this.taskCounter = counter;
  }

  public void run() {
    // do stuff
    if(taskCounter.decrementAndGet() == 0) {
      System.out.println("I am the last thread and I am about to finish");
    }
  }
}

// Main class
ExecutorService pool = Executors.newCachedThreadPool();
AtomicInteger taskCounter = new AtomicInteger(myList.size());
for(int i = 0; i < myList.size(); ++i) {
    pool.execute(new ThreadProcessRunnable(taskCounter));
}

この作業を行う重要な点は、アトミックであることtaskCounter.decrementAndGetですtaskCounterたとえば、の値が最初は 2 で、2 つの異なるスレッドdecrementAndGetが同時に呼び出すと、一方のスレッドが値 1 を認識し、もう一方のスレッドが値を認識することが保証されます。値が 0 であるため、正確に 1 つのスレッドが「終了しようとしています」というメッセージを出力します。これは、競合状態を伴うMadProgrammer の answerとは異なります。

latch.countDown();
if(latch.getCount() == 0) { ... }

スレッド 1 が値を (1 に) デクリメントし、スレッド 2 が再び (0 に) デクリメントすると、両方スレッドが呼び出し時に値 0 を認識しメッセージが出力されます。getCount

于 2013-01-17T22:08:42.777 に答える
2

バリア アクションで CyclicBarrier を使用できます (ドキュメント)。

指定された数のパーティ (スレッド) が待機しているときにトリップし、バリアがトリップされたときに指定されたバリア アクションを実行する新しい CyclicBarrier を作成します。これは、バリアに入る最後のスレッドによって実行されます。

于 2013-01-17T22:08:14.873 に答える
2

これは、CountDownLatch

public class TestCountDownLatch {

  private static CountDownLatch latch;

  public static void main(String[] args) {

    latch = new CountDownLatch(10);
    ExecutorService pool = Executors.newCachedThreadPool();
    for (int i = 0; i < 10; ++i) {
      pool.execute(new Worker(i));
    }
  }

  public static class Worker implements Runnable {

    private int number;

    public Worker(int number) {
      this.number = number;
    }

    @Override
    public void run() {

      try {
        System.out.println(number + " is sleeping...");
        Thread.sleep((long) (Math.round(Math.random() * 1000)));
      } catch (InterruptedException ex) {
      }

      System.out.println(number + " is Completed...");
      latch.countDown();

      if (latch.getCount() == 0) {

        System.out.println(number + " was last...");

      }

    }
  }
}

シンプルなシングル スレッドのテスト ケース

public class TestCountDownLatch {

  private static CountDownLatch latch;

  public static void main(String[] args) {

    latch = new CountDownLatch(1);
    ExecutorService pool = Executors.newCachedThreadPool();
    for (int i = 0; i < 1; ++i) {
      pool.execute(new Worker(i));
    }
  }

  public static class Worker implements Runnable {

    private int number;

    public Worker(int number) {
      this.number = number;
    }

    @Override
    public void run() {

      try {
        System.out.println(number + " is sleeping...");
        Thread.sleep((long) (Math.round(Math.random() * 1000)));
      } catch (InterruptedException ex) {
      }

      System.out.println(number + " is Completed...");
      latch.countDown();

      if (latch.getCount() == 0) {

        System.out.println(number + " was last...");

      }

    }
  }
}
于 2013-01-17T23:56:13.567 に答える
1

メインスレッドに配置できます。pool.await()プール内のすべてのスレッドが終了するまでメイン スレッドをブロックするために呼び出してから、余分な作業を行います。コードは次のようになります。

ExecutorService pool = Executors.newCachedThreadPool();
for(int i = 0; i < myList.size(); ++i) {
        pool.execute (new ThreadProcessRunnable (args));
}
pool.shutdown();
pool.awaitTermination();//blocks the main thread
System.out.println("last thread should execute this");
于 2013-01-17T22:09:06.427 に答える