转自:http://blog.csdn.net/liweisnake/article/details/12966761

今天看到一篇文章,是关于java中如何等待所有线程都执行结束,文章总结得很好,原文如下http://software.intel.com/zh-cn/blogs/2013/10/15/java-countdownlatchcyclicbarrier/?utm_campaign=CSDN&utm_source=intel.csdn.net&utm_medium=Link&utm_content=others-%20Java

看过之后在想java中有很大的灵活性,应该有更多的方式可以做这件事。

这个事情的场景是这样的:许多线程并行的计算一堆问题,然后每个计算存在一个队列,在主线程要等待所有计算结果完成后排序并展示出来。这样的问题其实很常见。

1. 使用join。这种方式其实并不是那么的优雅,将所有线程启动完之后还需要将所有线程都join,但是每次join都会阻塞,直到被join线程完成,很可能所有被阻塞线程已经完事了,主线程还在不断地join,貌似有点浪费,而且两个循环也不太好看。

  1.  public void testThreadSync1() {  
    
         final Vector<Integer> list = new Vector<Integer>();
    Thread[] threads = new Thread[TEST_THREAD_COUNT];
    try {
    for (int i = 0; i < TEST_THREAD_COUNT; i++) {
    final int num = i;
    threads[i] = new Thread(new Runnable() {
    public void run() {
    try {
    Thread.sleep(random.nextInt(100));
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    list.add(num);
    System.out.print(num + " add.\t");
    }
    });
    threads[i].start();
    }
    for (int i = 0; i < threads.length; i++) {
    threads[i].join();
    System.out.print(i + " end.\t");
    }
    } catch (InterruptedException ie) {
    ie.printStackTrace();
    }
    printSortedResult(list);
    }
  1.  9 add.  7 add.  3 add.  5 add.  4 add.  1 add.  0 add.  0 end.  1 end.  8 add.  2 add.  2 end.  3 end.  4 end.  5 end.  6 add.  6 end.  7 end.  8 end.  9 end.
    before sort
    9 7 3 5 4 1 0 8 2 6
    after sort
    0 1 2 3 4 5 6 7 8 9

2. 使用wait/notifyAll,这个方式其实跟上面是类似的,只是比较底层些吧(join实际上也是wait)。

  1.  @Test
    public void testThreadSync2() throws IOException, InterruptedException {
    final Object waitObject = new Object();
    final AtomicInteger count = new AtomicInteger(TEST_THREAD_COUNT);
    final Vector<Integer> list = new Vector<Integer>();
    Thread[] threads = new Thread[TEST_THREAD_COUNT];
    for (int i = 0; i < TEST_THREAD_COUNT; i++) {
    final int num = i;
    threads[i] = new Thread(new Runnable() {
    public void run() {
    try {
    Thread.sleep(random.nextInt(100));
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    list.add(num);
    System.out.print(num + " add.\t");
    synchronized (waitObject) {
    int cnt = count.decrementAndGet();
    if (cnt == 0) {
    waitObject.notifyAll();
    }
    }
    }
    });
    threads[i].start();
    }
    synchronized (waitObject) {
    while (count.get() != 0) {
    waitObject.wait();
    }
    }
    printSortedResult(list);
    }

3. 使用CountDownLatch,这其实是最优雅的写法了,每个线程完成后都去将计数器减一,最后完成时再来唤醒。

例1

  1.  @Test
    public void testThreadSync3() {
    final Vector<Integer> list = new Vector<Integer>();
    Thread[] threads = new Thread[TEST_THREAD_COUNT];
    final CountDownLatch latch = new CountDownLatch(TEST_THREAD_COUNT);
    for (int i = 0; i < TEST_THREAD_COUNT; i++) {
    final int num = i;
    threads[i] = new Thread(new Runnable() {
    public void run() {
    try {
    Thread.sleep(random.nextInt(100));
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    list.add(num);
    System.out.print(num + " add.\t");
    latch.countDown();
    }
    });
    threads[i].start();
    }
    try {
    latch.await();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    printSortedResult(list);
    }

例2

CountDownLatch 初始化设置count,即等待(await)count个线程或一个线程count次计数,通过工作线程来countDown计数减一,直到计数为0,await阻塞结束。

设置的count不可更改,如需要动态设置计数的线程数,可以使用CyclicBarrier.

下面的例子,所有的工作线程中准备就绪以后,并不是直接运行,而是等待主线程的信号后再执行具体的操作。

  1.  package com.example.multithread;  
    
     import java.util.concurrent.CountDownLatch;  
    
     class Driver
    {
    private static final int TOTAL_THREADS = 10;
    private final CountDownLatch mStartSignal = new CountDownLatch(1);
    private final CountDownLatch mDoneSignal = new CountDownLatch(TOTAL_THREADS); void main()
    {
    for (int i = 0; i < TOTAL_THREADS; i++)
    {
    new Thread(new Worker(mStartSignal, mDoneSignal, i)).start();
    }
    System.out.println("Main Thread Now:" + System.currentTimeMillis());
    doPrepareWork();// 准备工作
    mStartSignal.countDown();// 计数减一为0,工作线程真正启动具体操作
    doSomethingElse();//做点自己的事情
    try
    {
    mDoneSignal.await();// 等待所有工作线程结束
    }
    catch (InterruptedException e)
    {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    System.out.println("All workers have finished now.");
    System.out.println("Main Thread Now:" + System.currentTimeMillis());
    } void doPrepareWork()
    {
    System.out.println("Ready,GO!");
    } void doSomethingElse()
    {
    for (int i = 0; i < 100000; i++)
    {
    ;// delay
    }
    System.out.println("Main Thread Do something else.");
    }
    } class Worker implements Runnable
    {
    private final CountDownLatch mStartSignal;
    private final CountDownLatch mDoneSignal;
    private final int mThreadIndex; Worker(final CountDownLatch startSignal, final CountDownLatch doneSignal,
    final int threadIndex)
    {
    this.mDoneSignal = doneSignal;
    this.mStartSignal = startSignal;
    this.mThreadIndex = threadIndex;
    } @Override
    public void run()
    {
    // TODO Auto-generated method stub
    try
    {
    mStartSignal.await();// 阻塞,等待mStartSignal计数为0运行后面的代码
    // 所有的工作线程都在等待同一个启动的命令
    doWork();// 具体操作
    System.out.println("Thread " + mThreadIndex + " Done Now:"
    + System.currentTimeMillis());
    mDoneSignal.countDown();// 完成以后计数减一
    }
    catch (InterruptedException e)
    {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    } public void doWork()
    {
    for (int i = 0; i < 1000000; i++)
    {
    ;// 耗时操作
    }
    System.out.println("Thread " + mThreadIndex + ":do work");
    }
    } public class CountDownLatchTest
    {
    public static void main(String[] args)
    {
    // TODO Auto-generated method stub
    new Driver().main();
    } }

    通过Executor启动线程:

    1.  class CountDownLatchDriver2
      {
      private static final int TOTAL_THREADS = 10;
      private final CountDownLatch mDoneSignal = new CountDownLatch(TOTAL_THREADS); void main()
      {
      System.out.println("Main Thread Now:" + System.currentTimeMillis());
      doPrepareWork();// 准备工作 Executor executor = Executors.newFixedThreadPool(TOTAL_THREADS);
      for (int i = 0; i < TOTAL_THREADS; i++)
      {
      // 通过内建的线程池维护创建的线程
      executor.execute(new RunnableWorker(mDoneSignal, i));
      }
      doSomethingElse();// 做点自己的事情
      try
      {
      mDoneSignal.await();// 等待所有工作线程结束
      }
      catch (InterruptedException e)
      {
      // TODO Auto-generated catch block
      e.printStackTrace();
      }
      System.out.println("All workers have finished now.");
      System.out.println("Main Thread Now:" + System.currentTimeMillis());
      } void doPrepareWork()
      {
      System.out.println("Ready,GO!");
      } void doSomethingElse()
      {
      for (int i = 0; i < 100000; i++)
      {
      ;// delay
      }
      System.out.println("Main Thread Do something else.");
      }
      } class RunnableWorker implements Runnable
      { private final CountDownLatch mDoneSignal;
      private final int mThreadIndex; RunnableWorker(final CountDownLatch doneSignal, final int threadIndex)
      {
      this.mDoneSignal = doneSignal;
      this.mThreadIndex = threadIndex;
      } @Override
      public void run()
      {
      // TODO Auto-generated method stub doWork();// 具体操作
      System.out.println("Thread " + mThreadIndex + " Done Now:"
      + System.currentTimeMillis());
      mDoneSignal.countDown();// 完成以后计数减一
      // 计数为0时,主线程接触阻塞,继续执行其他任务
      try
      {
      // 可以继续做点其他的事情,与主线程无关了
      Thread.sleep(5000);
      System.out.println("Thread " + mThreadIndex
      + " Do something else after notifing main thread"); }
      catch (InterruptedException e)
      {
      // TODO Auto-generated catch block
      e.printStackTrace();
      } } public void doWork()
      {
      for (int i = 0; i < 1000000; i++)
      {
      ;// 耗时操作
      }
      System.out.println("Thread " + mThreadIndex + ":do work");
      }
      }

      输出:

       Main Thread Now:1359959480786
      Ready,GO!
      Thread 0:do work
      Thread 0 Done Now:1359959480808
      Thread 1:do work
      Thread 1 Done Now:1359959480811
      Thread 2:do work
      Thread 2 Done Now:1359959480813
      Main Thread Do something else.
      Thread 3:do work
      Thread 3 Done Now:1359959480825
      Thread 5:do work
      Thread 5 Done Now:1359959480827
      Thread 7:do work
      Thread 7 Done Now:1359959480829
      Thread 9:do work
      Thread 9 Done Now:1359959480831
      Thread 4:do work
      Thread 4 Done Now:1359959480833
      Thread 6:do work
      Thread 6 Done Now:1359959480835
      Thread 8:do work
      Thread 8 Done Now:1359959480837
      All workers have finished now.
      Main Thread Now:1359959480838
      Thread 0 Do something else after notifing main thread
      Thread 1 Do something else after notifing main thread
      Thread 2 Do something else after notifing main thread
      Thread 3 Do something else after notifing main thread
      Thread 9 Do something else after notifing main thread
      Thread 7 Do something else after notifing main thread
      Thread 5 Do something else after notifing main thread
      Thread 4 Do something else after notifing main thread
      Thread 6 Do something else after notifing main thread
      Thread 8 Do something else after notifing main thread

4. 使用CyclicBarrier。这里其实类似上面,这个berrier只是在等待完成后自动调用传入CyclicBarrier的Runnable。

例1

  1.  @Test
    public void testThreadSync4() throws IOException {
    final Vector<Integer> list = new Vector<Integer>();
    Thread[] threads = new Thread[TEST_THREAD_COUNT];
    final CyclicBarrier barrier = new CyclicBarrier(TEST_THREAD_COUNT,
    new Runnable() {
    public void run() {
    printSortedResult(list);
    }
    });
    for (int i = 0; i < TEST_THREAD_COUNT; i++) {
    final int num = i;
    threads[i] = new Thread(new Runnable() {
    public void run() {
    try {
    Thread.sleep(random.nextInt(100));
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    list.add(num);
    System.out.print(num + " add.\t");
    try {
    barrier.await();
    } catch (InterruptedException e) {
    e.printStackTrace();
    } catch (BrokenBarrierException e) {
    e.printStackTrace();
    }
    }
    });
    threads[i].start();
    }
    System.in.read();
    }

    例2

    1.  class WalkTarget
      {
      private final int mCount = 5;
      private final CyclicBarrier mBarrier;
      ExecutorService mExecutor; class BarrierAction implements Runnable
      {
      @Override
      public void run()
      {
      // TODO Auto-generated method stub
      System.out.println("所有线程都已经完成任务,计数达到预设值");
      //mBarrier.reset();//恢复到初始化状态 }
      } WalkTarget()
      {
      //初始化CyclicBarrier
      mBarrier = new CyclicBarrier(mCount, new BarrierAction());
      mExecutor = Executors.newFixedThreadPool(mCount); for (int i = 0; i < mCount; i++)
      {
      //启动工作线程
      mExecutor.execute(new Walker(mBarrier, i));
      }
      }
      } //工作线程
      class Walker implements Runnable
      {
      private final CyclicBarrier mBarrier;
      private final int mThreadIndex; Walker(final CyclicBarrier barrier, final int threadIndex) {
      mBarrier = barrier;
      mThreadIndex = threadIndex;
      } @Override
      public void run()
      {
      // TODO Auto-generated method stub
      System.out.println("Thread " + mThreadIndex + " is running...");
      // 执行任务
      try
      {
      TimeUnit.MILLISECONDS.sleep(5000);
      // do task
      }
      catch (InterruptedException e)
      {
      // TODO Auto-generated catch block
      e.printStackTrace();
      } // 完成任务以后,等待其他线程完成任务
      try
      {
      mBarrier.await();
      }
      catch (InterruptedException e)
      {
      // TODO Auto-generated catch block
      e.printStackTrace();
      }
      catch (BrokenBarrierException e)
      {
      // TODO Auto-generated catch block
      e.printStackTrace();
      }
      // 其他线程任务都完成以后,阻塞解除,可以继续接下来的任务
      System.out.println("Thread " + mThreadIndex + " do something else");
      } } public class CountDownLatchTest
      {
      public static void main(String[] args)
      {
      // TODO Auto-generated method stub
      //new CountDownLatchDriver2().main();
      new WalkTarget();
      } }

      输出(注意,只有所有的线程barrier.await之后才能继续执行其他的操作):

      Thread 0 is running... Thread 2 is running... Thread 3 is running... Thread 1 is running... Thread 4 is running... 所有线程都已经完成任务,计数达到预设值 Thread 4 do something else Thread 0 do something else Thread 2 do something else Thread 3 do something else Thread 1 do something else

5、

CountDownLatch和CyclicBarrier简单比较:

CountDownLatch

CyclicBarrier

软件包

java.util.concurrent

java.util.concurrent

适用情景

主线程等待多个工作线程结束

多个线程之间互相等待,直到所有线程达到一个障碍点(Barrier point)

主要方法

CountDownLatch(int count) (主线程调用)

初始化计数

CountDownLatch.await (主线程调用)

阻塞,直到等待计数为0解除阻塞

CountDownLatch.countDown

计数减一(工作线程调用)

CyclicBarrier(int parties, Runnable barrierAction) //初始化参与者数量和障碍点执行Action,Action可选。由主线程初始化

CyclicBarrier.await() //由参与者调用

阻塞,直到所有线程达到屏障点

等待结束

各线程之间不再互相影响,可以继续做自己的事情。不再执行下一个目标工作。

在屏障点达到后,允许所有线程继续执行,达到下一个目标。可以重复使用CyclicBarrier

异常

如果其中一个线程由于中断,错误,或超时导致永久离开屏障点,其他线程也将抛出异常。

其他

如果BarrierAction不依赖于任何Party中的所有线程,那么在任何party中的一个线程被释放的时候,可以直接运行这个Action。

If(barrier.await()==2)

{

//do action

}

java中等待所有线程都执行结束(转)的更多相关文章

  1. java中等待所有线程都执行结束

    转自:http://blog.csdn.net/liweisnake/article/details/12966761 今天看到一篇文章,是关于java中如何等待所有线程都执行结束,文章总结得很好,原 ...

  2. JAVA中等待所有线程都执行结束(转2)

    场景: package com.java4all.mypoint; import java.util.concurrent.CountDownLatch; public class ThreadTes ...

  3. Java中如何保证线程顺序执行

    只要了解过多线程,我们就知道线程开始的顺序跟执行的顺序是不一样的.如果只是创建三个线程然后执行,最后的执行顺序是不可预期的.这是因为在创建完线程之后,线程执行的开始时间取决于CPU何时分配时间片,线程 ...

  4. 【java】【多线程】等待开启的多个线程都执行完成,再做事情,怎么实现

    今天在controller中写一个接口用来测试模拟多个请求同时到达 下订单的情况, 怎么能有效保证高并发下的库存和销量的一致性呢?[具体实现方法:https://www.cnblogs.com/sxd ...

  5. Java中的守护线程 & 非守护线程(简介)

    Java中的守护线程 & 非守护线程 守护线程 (Daemon Thread) 非守护线程,又称用户线程(User Thread) 用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守 ...

  6. Java 中如何实现线程间通信

    世界以痛吻我,要我报之以歌 -- 泰戈尔<飞鸟集> 虽然通常每个子线程只需要完成自己的任务,但是有时我们希望多个线程一起工作来完成一个任务,这就涉及到线程间通信. 关于线程间通信本文涉及到 ...

  7. Java中的守护线程和非守护线程(转载)

    <什么是守护线程,什么是非守护线程> Java有两种Thread:"守护线程Daemon"(守护线程)与"用户线程User"(非守护线程). 用户线 ...

  8. 详解线程池的作用及Java中如何使用线程池

    服务端应用程序(如数据库和 Web 服务器)需要处理来自客户端的高并发.耗时较短的请求任务,所以频繁的创建处理这些请求的所需要的线程就是一个非常消耗资源的操作.常规的方法是针对一个新的请求创建一个新线 ...

  9. 重新想象 Windows 8 Store Apps (42) - 多线程之线程池: 延迟执行, 周期执行, 在线程池中找一个线程去执行指定的方法

    [源码下载] 重新想象 Windows 8 Store Apps (42) - 多线程之线程池: 延迟执行, 周期执行, 在线程池中找一个线程去执行指定的方法 作者:webabcd 介绍重新想象 Wi ...

随机推荐

  1. C语言文件操作 FILE结构体

    内存中的数据都是暂时的,当程序结束时,它们都将丢失.为了永久性的保存大量的数据,C语言提供了对文件的操作. 1.文件和流 C将每个文件简单地作为顺序字节流(如下图).每个文件用文件结束符结束,或者在特 ...

  2. Java-获取堆的大小

    package com.tj; public class getHeapInfo { public static void main(String[] args) { //获取当前堆的大小 byte ...

  3. mac finder中添加自定义边栏

    想在finder中添加自定义边栏,操作如图所示: 选中边栏中任意边栏项,右键-在上层文件夹中显示,然后创建新的文件夹,将该文件夹拖到边栏中即可.

  4. 【LeetCode】Same Tree(相同的树)

    这道题是LeetCode里的第100道题. 这是题目: 给定两个二叉树,编写一个函数来检验它们是否相同. 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的. 示例 1: 输入: 1 1 ...

  5. HLG 2025

    确定大小 Time Limit: 1000 MS Memory Limit: 32768 K Total Submit: 50(15 users) Total Accepted: 12(11 user ...

  6. UITableView滑动动画+FPSLabel

    主要使用了tableView的代理方法 行将要显示的时候 - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableView ...

  7. ios弹性头部

    很久没写博客了,金天有点时间来写下,一直觉得弹性头部很炫,看起来高大上,写起来蛮简单的 层次分析 一共有3层,最底部是图像层,中间是scrollView或者它的子类,最上层是scrollView上面添 ...

  8. NOJ——1642简单的图论问题?(BFS+优先队列)

    [1642] 简单的图论问题? 时间限制: 5000 ms 内存限制: 65535 K 问题描述 给一个 n 行 m 列的迷宫,每个格子要么是障碍物要么是空地.每个空地里都有一个权值.你的 任务是从找 ...

  9. 算法复习——单调队列(sliding windows,ssoi)

    题目: 题目描述 给你一个长度为 N 的数组,一个长为 K 的滑动的窗体从最左移至最右端,你只能见到窗口的 K 个整数,每次窗体向右移动一位,如下表:

  10. 巧克力王国 BZOJ 2850

    巧克力王国 [问题描述] 巧克力王国里的巧克力都是由牛奶和可可做成的.但是并不是每一块巧克力都受王国人民的欢迎,因为大家都不喜欢过于甜的巧克力.对于每一块巧克力,我们设x和y为其牛奶和可可的含量.由于 ...