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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://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,貌似有点浪费,而且两个循环也不太好看。

        @Test
	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);
	}

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)。

	@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,这其实是最优雅的写法了,每个线程完成后都去将计数器减一,最后完成时再来唤醒。

	@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);
	}

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

	@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();
	}
  实际上这些方法也是跟那篇文章说的类似,不过都写出来可以稍微参考下。而且我相信还有更多其它方式。


没有更多推荐了,返回首页

私密
私密原因:
请选择设置私密原因
  • 广告
  • 抄袭
  • 版权
  • 政治
  • 色情
  • 无意义
  • 其他
其他原因:
120
出错啦
系统繁忙,请稍后再试