非主流并發(fā)工具之 CountDownLatch
Posted on 2011-10-14 14:22 蜀山兆孨龘 閱讀(1713) 評(píng)論(1) 編輯 收藏 所屬分類: Java SE顧名思義,CountDownLatch
是一個(gè)用來倒計(jì)數(shù)的咚咚。如果某項(xiàng)任務(wù)可以拆分成若干個(gè)子任務(wù)同時(shí)進(jìn)行,然后等待所有的子任務(wù)完成,可以考慮使用它。
該類的用法非常簡單。首先構(gòu)造一個(gè) CountDownLatch
,唯一的參數(shù)是任務(wù)數(shù)量,一旦構(gòu)造完畢就不能修改。接著啟動(dòng)所有的子任務(wù)(線程),且每個(gè)子任務(wù)在完成自己的計(jì)算后,調(diào)用 CountDownLatch#countDown
方法將倒計(jì)數(shù)減一。最后在主線程中調(diào)用 CountDownLatch#await
方法等待計(jì)數(shù)器歸零。
例如賽跑的準(zhǔn)備階段,八名運(yùn)動(dòng)員先后到達(dá)起點(diǎn)做好準(zhǔn)備,然后裁判打響發(fā)令槍,準(zhǔn)備工作就結(jié)束了,比賽開始。如果把從運(yùn)動(dòng)員就位到發(fā)令槍響看做賽跑準(zhǔn)備任務(wù),那么每個(gè)運(yùn)動(dòng)員的準(zhǔn)備過程就是其子任務(wù),可以用 CountDownLatch
模擬如下:
final int count = 8; System.out.println("運(yùn)動(dòng)員開始就位。"); // 構(gòu)造 CountDownLatch。 final CountDownLatch cdl = new CountDownLatch(count); for (int i = 1; i <= count; i++) { final int number = i; new Thread() { @Override public void run() { System.out.println(number + " 號(hào)運(yùn)動(dòng)員到場并開始準(zhǔn)備..."); try { // 讓運(yùn)動(dòng)員隨機(jī)準(zhǔn)備 2~5 秒鐘。 TimeUnit.SECONDS.sleep(new Random().nextInt(4) + 2); } catch (InterruptedException ex) { } System.out.println(number + " 號(hào)運(yùn)動(dòng)員就位。"); // 倒計(jì)數(shù)減一。 cdl.countDown(); } }.start(); } System.out.println("等待所有運(yùn)動(dòng)員就位..."); try { // 等待倒計(jì)數(shù)變?yōu)?0。 cdl.await(); System.out.println("比賽開始。"); } catch (InterruptedException ex) { }
運(yùn)行輸出(可能)為:
運(yùn)動(dòng)員開始就位。 1 號(hào)運(yùn)動(dòng)員到場并開始準(zhǔn)備... 2 號(hào)運(yùn)動(dòng)員到場并開始準(zhǔn)備... 4 號(hào)運(yùn)動(dòng)員到場并開始準(zhǔn)備... 等待所有運(yùn)動(dòng)員就位... 8 號(hào)運(yùn)動(dòng)員到場并開始準(zhǔn)備... 6 號(hào)運(yùn)動(dòng)員到場并開始準(zhǔn)備... 3 號(hào)運(yùn)動(dòng)員到場并開始準(zhǔn)備... 7 號(hào)運(yùn)動(dòng)員到場并開始準(zhǔn)備... 5 號(hào)運(yùn)動(dòng)員到場并開始準(zhǔn)備... 6 號(hào)運(yùn)動(dòng)員就位。 1 號(hào)運(yùn)動(dòng)員就位。 5 號(hào)運(yùn)動(dòng)員就位。 4 號(hào)運(yùn)動(dòng)員就位。 7 號(hào)運(yùn)動(dòng)員就位。 8 號(hào)運(yùn)動(dòng)員就位。 2 號(hào)運(yùn)動(dòng)員就位。 3 號(hào)運(yùn)動(dòng)員就位。 比賽開始。
從上面的例子還可以看出 CountDownLatch
的局限性和 CompletionService
類似,在于無法處理子任務(wù)數(shù)量不確定的情況,例如統(tǒng)計(jì)某個(gè)文件夾中的文件數(shù)量。另外,如果某個(gè)子任務(wù)在調(diào)用 countDown
之前就掛掉了,倒計(jì)數(shù)就永遠(yuǎn)不會(huì)歸零。對(duì)于這種情況,要么用 finally
之類的手段保證 countDown
一定會(huì)被調(diào)用,要么用帶參數(shù)的 await
方法指定超時(shí)時(shí)間。