java中等待所有執行緒都執行結束
阿新 • • 發佈:2019-01-31
看過之後在想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)。
3. 使用CountDownLatch,這其實是最優雅的寫法了,每個執行緒完成後都去將計數器減一,最後完成時再來喚醒。@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); }
@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();
}
實際上這些方法也是跟那篇文章說的類似,不過都寫出來可以稍微參考下。而且我相信還有更多其它方式。