1. 程式人生 > >java中等待所有執行緒都執行結束

java中等待所有執行緒都執行結束

  看過之後在想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();
	}
  實際上這些方法也是跟那篇文章說的類似,不過都寫出來可以稍微參考下。而且我相信還有更多其它方式。