<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    神奇好望角 The Magical Cape of Good Hope

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

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

    Posted on 2012-02-09 10:40 蜀山兆孨龘 閱讀(2681) 評(píng)論(2)  編輯  收藏 所屬分類: Java SE

    ForkJoinPool 是 Java SE 7 新功能“分叉/結(jié)合框架”的核心類,現(xiàn)在可能乏人問津,但我覺得它遲早會(huì)成為主流。分叉/結(jié)合框架是一個(gè)比較特殊的線程池框架,專用于需要將一個(gè)任務(wù)不斷分解成子任務(wù)(分叉),再不斷進(jìn)行匯總得到最終結(jié)果(結(jié)合)的計(jì)算過程。比起傳統(tǒng)的線程池類 ThreadPoolExecutorForkJoinPool 實(shí)現(xiàn)了工作竊取算法,使得空閑線程能夠主動(dòng)分擔(dān)從別的線程分解出來的子任務(wù),從而讓所有的線程都盡可能處于飽滿的工作狀態(tài),提高執(zhí)行效率。

    ForkJoinPool 提供了三類方法來調(diào)度子任務(wù):

    execute 系列
    異步執(zhí)行指定的任務(wù)。
    invokeinvokeAll
    執(zhí)行指定的任務(wù),等待完成,返回結(jié)果。
    submit 系列
    異步執(zhí)行指定的任務(wù)并立即返回一個(gè) Future 對(duì)象。

    子任務(wù)由 ForkJoinTask 的實(shí)例來代表。它是一個(gè)抽象類,JDK 為我們提供了兩個(gè)實(shí)現(xiàn):RecursiveTaskRecursiveAction,分別用于需要和不需要返回計(jì)算結(jié)果的子任務(wù)。ForkJoinTask 提供了三個(gè)靜態(tài)的 invokeAll 方法來調(diào)度子任務(wù),注意只能在 ForkJoinPool 執(zhí)行計(jì)算的過程中調(diào)用它們。

    ForkJoinPoolForkJoinTask 還提供了很多讓人眼花繚亂的公共方法,其實(shí)它們大多數(shù)都是其內(nèi)部實(shí)現(xiàn)去調(diào)用的,對(duì)于應(yīng)用開發(fā)人員來說意義不大。

    下面以統(tǒng)計(jì) D 盤文件個(gè)數(shù)為例。這實(shí)際上是對(duì)一個(gè)文件樹的遍歷,我們需要遞歸地統(tǒng)計(jì)每個(gè)目錄下的文件數(shù)量,最后匯總,非常適合用分叉/結(jié)合框架來處理:

    // 處理單個(gè)目錄的任務(wù)
    public class CountingTask extends RecursiveTask<Integer> {
        private Path dir;
    
        public CountingTask(Path dir) {
            this.dir = dir;
        }
    
        @Override
        protected Integer compute() {
            int count = 0;
            List<CountingTask> subTasks = new ArrayList<>();
    
            // 讀取目錄 dir 的子路徑。
            try (DirectoryStream<Path> ds = Files.newDirectoryStream(dir)) {
                for (Path subPath : ds) {
                    if (Files.isDirectory(subPath, LinkOption.NOFOLLOW_LINKS)) {
                        // 對(duì)每個(gè)子目錄都新建一個(gè)子任務(wù)。
                        subTasks.add(new CountingTask(subPath));
                    } else {
                        // 遇到文件,則計(jì)數(shù)器增加 1。
                        count++;
                    }
                }
    
                if (!subTasks.isEmpty()) {
                    // 在當(dāng)前的 ForkJoinPool 上調(diào)度所有的子任務(wù)。
                    for (CountingTask subTask : invokeAll(subTasks)) {
                        count += subTask.join();
                    }
                }
            } catch (IOException ex) {
                return 0;
            }
            return count;
        }
    }
    
    // 用一個(gè) ForkJoinPool 實(shí)例調(diào)度“總?cè)蝿?wù)”,然后敬請(qǐng)期待結(jié)果……
    Integer count = new ForkJoinPool().invoke(new CountingTask(Paths.get("D:/")));
        

    在我的筆記本上,經(jīng)多次運(yùn)行這段代碼,耗費(fèi)的時(shí)間穩(wěn)定在 600 豪秒左右。普通線程池(Executors.newCachedThreadPool())耗時(shí) 1100 毫秒左右,足見工作竊取的優(yōu)勢。

    結(jié)束本文前,我們來圍觀一個(gè)最神奇的結(jié)果:單線程算法(使用 Files.walkFileTree(...))比這兩個(gè)都快,平均耗時(shí) 550 毫秒!這警告我們并非引入多線程就能優(yōu)化性能,并須要先經(jīng)過多次測試才能下結(jié)論。


    評(píng)論

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

    2012-02-24 14:53 by 恩亠
    600毫秒?不是600秒嗎?那你的D盤也太干凈了,我的有上百萬文件,根本就是半天沒有結(jié)果

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

    2012-02-24 22:48 by 蜀山兆孨龘
    確實(shí)是 600 毫秒,看來你下的片片太多了哈哈。上百萬的文件數(shù)量即使在 Windows 里面右鍵看屬性都很慢……
    主站蜘蛛池模板: 久久精品国产亚洲AV忘忧草18| 成人黄动漫画免费网站视频 | 中文字幕亚洲色图| 一个人免费视频在线观看www| 久久久久亚洲精品天堂久久久久久 | 亚洲综合无码精品一区二区三区| 日韩精品无码免费视频| 亚洲A丁香五香天堂网| 特级毛片免费观看视频| 一级毛片直播亚洲| 一区二区视频在线免费观看| 亚洲精品成人片在线观看| gogo免费在线观看| 亚洲区小说区激情区图片区| a视频在线观看免费| 亚洲AV无码精品色午夜在线观看| 久操免费在线观看| 亚洲首页在线观看| 美女裸身网站免费看免费网站| 久久精品国产亚洲AV大全| 亚洲黄色免费网址| 中文日韩亚洲欧美制服| 日韩a级毛片免费观看| 亚洲a无码综合a国产av中文| 亚洲第一视频在线观看免费| 国产免费A∨在线播放| 亚洲AV无码专区国产乱码4SE| 99爱在线观看免费完整版| 亚洲无成人网77777| 最近免费中文字幕视频高清在线看| 亚洲精品无码专区| 大胆亚洲人体视频| 在线看片免费人成视频播| 久久亚洲私人国产精品vA| 精品成在人线AV无码免费看| 亚洲成a人片在线不卡| 国产精品免费视频一区| 一级做a爰性色毛片免费| 亚洲AV无码码潮喷在线观看| 国产精品久久久久久久久免费| 亚洲色图激情文学|