Java中等待所有线程都执行结束

来源:互联网 发布:手机微信java通用版 编辑:程序博客网 时间:2024/05/17 08:55
原文地址: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,貌似有点浪费,而且两个循环也不太好看。

[java] view plain copy
  1.        @Test  
  2. public void testThreadSync1() {  
  3.   
  4.     final Vector<Integer> list = new Vector<Integer>();  
  5.     Thread[] threads = new Thread[TEST_THREAD_COUNT];  
  6.     try {  
  7.         for (int i = 0; i < TEST_THREAD_COUNT; i++) {  
  8.             final int num = i;  
  9.             threads[i] = new Thread(new Runnable() {  
  10.                 public void run() {  
  11.                     try {  
  12.                         Thread.sleep(random.nextInt(100));  
  13.                     } catch (InterruptedException e) {  
  14.                         e.printStackTrace();  
  15.                     }  
  16.                     list.add(num);  
  17.                     System.out.print(num + " add.\t");  
  18.                 }  
  19.             });  
  20.             threads[i].start();  
  21.         }  
  22.         for (int i = 0; i < threads.length; i++) {  
  23.             threads[i].join();  
  24.             System.out.print(i + " end.\t");  
  25.         }  
  26.     } catch (InterruptedException ie) {  
  27.         ie.printStackTrace();  
  28.     }  
  29.     printSortedResult(list);  
  30. }  

[java] view plain copy
  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.    
  2. before sort  
  3. 9   7   3   5   4   1   0   8   2   6     
  4. after sort  
  5. 0   1   2   3   4   5   6   7   8   9  

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

[java] view plain copy
  1. @Test  
  2. public void testThreadSync2() throws IOException, InterruptedException {  
  3.     final Object waitObject = new Object();  
  4.     final AtomicInteger count = new AtomicInteger(TEST_THREAD_COUNT);  
  5.     final Vector<Integer> list = new Vector<Integer>();  
  6.     Thread[] threads = new Thread[TEST_THREAD_COUNT];  
  7.     for (int i = 0; i < TEST_THREAD_COUNT; i++) {  
  8.         final int num = i;  
  9.         threads[i] = new Thread(new Runnable() {  
  10.             public void run() {  
  11.                 try {  
  12.                     Thread.sleep(random.nextInt(100));  
  13.                 } catch (InterruptedException e) {  
  14.                     e.printStackTrace();  
  15.                 }  
  16.                 list.add(num);  
  17.                 System.out.print(num + " add.\t");  
  18.                 synchronized (waitObject) {  
  19.                     int cnt = count.decrementAndGet();  
  20.                     if (cnt == 0) {  
  21.                         waitObject.notifyAll();  
  22.                     }  
  23.                 }  
  24.             }  
  25.         });  
  26.         threads[i].start();  
  27.     }  
  28.     synchronized (waitObject) {  
  29.         while (count.get() != 0) {  
  30.             waitObject.wait();  
  31.         }  
  32.     }  
  33.     printSortedResult(list);  
  34. }  
  3. 使用CountDownLatch,这其实是最优雅的写法了,每个线程完成后都去将计数器减一,最后完成时再来唤醒。

[java] view plain copy
  1. @Test  
  2. public void testThreadSync3() {  
  3.     final Vector<Integer> list = new Vector<Integer>();  
  4.     Thread[] threads = new Thread[TEST_THREAD_COUNT];  
  5.     final CountDownLatch latch = new CountDownLatch(TEST_THREAD_COUNT);  
  6.     for (int i = 0; i < TEST_THREAD_COUNT; i++) {  
  7.         final int num = i;  
  8.         threads[i] = new Thread(new Runnable() {  
  9.             public void run() {  
  10.                 try {  
  11.                     Thread.sleep(random.nextInt(100));  
  12.                 } catch (InterruptedException e) {  
  13.                     e.printStackTrace();  
  14.                 }  
  15.                 list.add(num);  
  16.                 System.out.print(num + " add.\t");  
  17.                 latch.countDown();  
  18.             }  
  19.         });  
  20.         threads[i].start();  
  21.     }  
  22.     try {  
  23.         latch.await();  
  24.     } catch (InterruptedException e) {  
  25.         e.printStackTrace();  
  26.     }  
  27.     printSortedResult(list);  
  28. }  

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

[java] view plain copy
  1. @Test  
  2. public void testThreadSync4() throws IOException {  
  3.     final Vector<Integer> list = new Vector<Integer>();  
  4.     Thread[] threads = new Thread[TEST_THREAD_COUNT];  
  5.     final CyclicBarrier barrier = new CyclicBarrier(TEST_THREAD_COUNT,  
  6.             new Runnable() {  
  7.                 public void run() {  
  8.                     printSortedResult(list);  
  9.                 }  
  10.             });  
  11.     for (int i = 0; i < TEST_THREAD_COUNT; i++) {  
  12.         final int num = i;  
  13.         threads[i] = new Thread(new Runnable() {  
  14.             public void run() {  
  15.                 try {  
  16.                     Thread.sleep(random.nextInt(100));  
  17.                 } catch (InterruptedException e) {  
  18.                     e.printStackTrace();  
  19.                 }  
  20.                 list.add(num);  
  21.                 System.out.print(num + " add.\t");  
  22.                 try {  
  23.                     barrier.await();  
  24.                 } catch (InterruptedException e) {  
  25.                     e.printStackTrace();  
  26.                 } catch (BrokenBarrierException e) {  
  27.                     e.printStackTrace();  
  28.                 }  
  29.             }  
  30.         });  
  31.         threads[i].start();  
  32.     }  
  33.     System.in.read();  
  34. }  
  实际上这些方法也是跟那篇文章说的类似,不过都写出来可以稍微参考下。而且我相信还有更多其它方式。
0 0