在java中多线程

时间:2013-01-17 22:01:48

标签: java

我有一个多线程程序,我想让一个线程在所有线程完成后打印语句。我怎么能这样做?我如何知道所有线程都已完成?

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 个答案:

答案 0 :(得分: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&#39; 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 atomic - 例如,taskCounter的值最初是2,并且两个不同的线程调用{{ 1}}同时保证一个线程将看到值1而另一个线程将看到值0,所以正好一个线程将打印&#34;即将完成&#34;信息。这与MadProgrammer's answer不同,后者涉及竞争条件:

decrementAndGet

其中可以让线程1递减值(为1),然后线程2再次递减它(为0),然后两个线程在它们调用{{1}时看到值0和两者打印消息。

答案 1 :(得分:2)

您可以使用具有屏障操作的CyclicBarrier(documentation)。

  

创建一个新的CyclicBarrier,当给定的数量时,它会跳闸   派对(线程)正在等待它,它将执行   当屏障被绊倒时,给予屏障作用   最后一个线进入障碍。

答案 2 :(得分: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...");

      }

    }
  }
}

答案 3 :(得分: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");