神奇好望角 The Magical Cape of Good Hope

          庸人不必自擾,智者何需千慮?
          posts - 26, comments - 50, trackbacks - 0, articles - 11
            BlogJava :: 首頁(yè) ::  :: 聯(lián)系 :: 聚合  :: 管理

          非主流并發(fā)工具之 CountDownLatch

          Posted on 2011-10-14 14:22 蜀山兆孨龘 閱讀(1715) 評(píng)論(1)  編輯  收藏 所屬分類: Java SE

          顧名思義,CountDownLatch 是一個(gè)用來倒計(jì)數(shù)的咚咚。如果某項(xiàng)任務(wù)可以拆分成若干個(gè)子任務(wù)同時(shí)進(jìn)行,然后等待所有的子任務(wù)完成,可以考慮使用它。

          該類的用法非常簡(jiǎn)單。首先構(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)員到場(chǎ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)員到場(chǎng)并開始準(zhǔn)備...
          2 號(hào)運(yùn)動(dòng)員到場(chǎng)并開始準(zhǔn)備...
          4 號(hào)運(yùn)動(dòng)員到場(chǎng)并開始準(zhǔn)備...
          等待所有運(yùn)動(dòng)員就位...
          8 號(hào)運(yùn)動(dòng)員到場(chǎng)并開始準(zhǔn)備...
          6 號(hào)運(yùn)動(dòng)員到場(chǎng)并開始準(zhǔn)備...
          3 號(hào)運(yùn)動(dòng)員到場(chǎng)并開始準(zhǔn)備...
          7 號(hào)運(yùn)動(dòng)員到場(chǎng)并開始準(zhǔn)備...
          5 號(hào)運(yùn)動(dòng)員到場(chǎ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í)間。


          評(píng)論

          # re: 非主流并發(fā)工具之 CountDownLatch  回復(fù)  更多評(píng)論   

          2011-10-14 20:56 by 與你同飛
          謝謝,長(zhǎng)見識(shí)了。
          主站蜘蛛池模板: 新昌县| 双鸭山市| 格尔木市| 凤翔县| 永安市| 临湘市| 冷水江市| 井冈山市| 东明县| 遂宁市| 双峰县| 敦化市| 利辛县| SHOW| 绥德县| 龙州县| 多伦县| 时尚| 河源市| 宁蒗| 九龙县| 宜黄县| 富民县| 吴江市| 仪陇县| 格尔木市| 平阳县| 犍为县| 岗巴县| 白河县| 交口县| 凤城市| 岱山县| 北安市| 阿拉善右旗| 麻栗坡县| 临潭县| 武鸣县| 东台市| 五台县| 合水县|