利用Fork/Join框架来统计某个字符串在某个文件夹的文件中出现的次数

需求:利用Fork/Join框架来统计某个字符串在某个文件夹的文件中出现的次数。主要用到的技术点:JDK8的Stream、Lambda表达式、Fork/Join框架.

如果对于Fork/Join不了解的话可以参考这里:http://www.infoq.com/cn/articles/fork-join-introductionhttp://ifeve.com/fork-join-1/http://www.iteye.com/topic/643724。主要代码如下:

package com.zkn.fullstacktraining.seventh;

import com.google.common.collect.Lists;
import javafx.util.Pair;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * Created by wb-zhangkenan on 2017/2/6.
 * 通过Fork/Join的方式来统计某个字符串在某个文件夹下的文件中出现的次数
 */
public class SearchStringByForkJoin extends RecursiveTask<List<Pair<String, Integer>>> {
    //任务的阀值
    private static final int THRESHOLD = 5;
    //任务区间的开始值
    private int start;
    //任务区间的结束值
    private int end;
    //所有的路径信息
    private List<Path> allPaths;

    public SearchStringByForkJoin(int start, int end, List<Path> allPaths) {
        this.start = start;
        this.end = end;
        this.allPaths = allPaths;
    }

    public static void main(String[] args) {

        ForkJoinPool forkJoinPool = new ForkJoinPool();
        try {
            List<Path> pathList = Files.walk(Paths.get("D:\\CUST\\WORK\\Exercises\\FullStackTraining\\src\\main\\java\\com\\zkn"), 4)
                    .filter(file -> !Files.isDirectory(file) && file.toString().endsWith("java"))
                    .collect(Collectors.toList());
            SearchStringByForkJoin searchStringByForkJoin = new SearchStringByForkJoin(0, pathList.size(), pathList);
            Future<List<Pair<String, Integer>>> result =
                    forkJoinPool.submit(searchStringByForkJoin);
            List<Pair<String, Integer>> pairList = result.get();
            pairList.stream()
                    .filter(pair -> pair.getValue() > 0)
                    .sorted((s1, s2) -> Integer.compare(s2.getValue(), s1.getValue()))
                    .forEach(pair -> System.out.println(String.format("%d次出现在%s文件中", pair.getValue(), pair.getKey().toString())));
            forkJoinPool.shutdown();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    /**
     * The main computation performed by this task.
     * @return the result of the computation
     */
    @Override
    protected List<Pair<String, Integer>> compute() {
        List<Pair<String, Integer>> pairList = Lists.newArrayList();
        boolean canCompute = end - start <= THRESHOLD;
        if (canCompute) {
            pairList = IntStream.range(start, end + 1).mapToObj(i -> {
                //到集合的结尾了
                if (i == allPaths.size())
                    return new Pair<>("", 0);
                int sum = 0;
                try {
                    Optional optional = Files.lines(allPaths.get(i)).map(file -> {
                        int count = 0;
                        int flag = file.indexOf("main");
                        if (flag >= 0) {
                            do {
                                count++;
                            } while ((flag = file.indexOf("main", flag + 1)) > 0);
                        }
                        return count;
                    }).reduce(Integer::sum);
                    sum = optional.isPresent() ? (int) optional.get() : 0;
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return new Pair<>(allPaths.get(i).toString(), sum);
            }).collect(Collectors.toList());
        } else {
            //取中间值
            int middle = (end + start) / 2;
            //创建Fork子任务
            SearchStringByForkJoin leftFork = new SearchStringByForkJoin(start, middle, allPaths);
            //创建Fork子任务
            SearchStringByForkJoin rightFork = new SearchStringByForkJoin(middle + 1, end, allPaths);
            //执行子任务
            leftFork.fork();
            rightFork.fork();
            //合并子任务的结果集
            pairList.addAll(leftFork.join());
            pairList.addAll(rightFork.join());
        }
        return pairList;
    }
}
时间: 2024-09-29 19:27:03

利用Fork/Join框架来统计某个字符串在某个文件夹的文件中出现的次数的相关文章

《Java 7并发编程实战手册》第五章Fork/Join框架

感谢人民邮电大学授权并发网发布此书样章,新书已上市,购买请进当当网 本章内容包含: 创建Fork/Join线程池 合并任务的结果 异步运行任务 在任务中抛出异常 取消任务 5.1 简介 通常,使用Java来开发一个简单的并发应用程序时,会创建一些Runnable对象,然后创建对应的Thread 对象来控制程序中这些线程的创建.执行以及线程的状态.自从Java 5开始引入了Executor和ExecutorService接口以及实现这两个接口的类(比如ThreadPoolExecutor)之后,使

Fork/Join框架(三)加入任务的结果

加入任务的结果 Fork/Join框架提供了执行返回一个结果的任务的能力.这些任务的类型是实现了RecursiveTask类.这个类继承了ForkJoinTask类和实现了执行者框架提供的Future接口. 在任务中,你必须使用Java API方法推荐的结构: 1 If (problem size < size){ 2 tasks=Divide(task); 3 execute(tasks); 4 groupResults() 5 return result; 6 } else { 7 reso

Java Fork/Join框架_java

Fork/Join框架是ExecutorService接口的一个实现,通过它我们可以实现多进程.Fork/Join可以用来将一个大任务递归的拆分为多个小任务,目标是充分利用所有的资源尽可能增强应用的性能. 和任何ExecutorService接口的实现一样,Fork/Join也会使用线程池来分布式的管理工作线程.Fork/Join框架的独特之处在于它使用了work-stealing(工作窃取)算法.通过这个算法,工作线程在无事可做时可以窃取其它正在繁忙的线程的任务来执行. Fork/Join框架

Fork/Join框架(四)异步运行任务

异步运行任务 当你在ForkJoinPool中执行ForkJoinTask时,你可以使用同步或异步方式来实现.当你使用同步方式时,提交任务给池的方法直到提交的任务完成它的执行,才会返回结果.当你使用异步方式时,提交任务给执行者的方法将立即返回,所以这个任务可以继续执行. 你应该意识到这两个方法有很大的区别,当你使用同步方法,调用这些方法(比如:invokeAll()方法)的任务将被阻塞,直到提交给池的任务完成它的执行.这允许ForkJoinPool类使用work-stealing算法,分配一个新

聊聊并发(八)——Fork/Join框架介绍

本文首发于InfoQ 1. 什么是Fork/Join框架 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架. 我们再通过Fork和Join这两个单词来理解下Fork/Join框架,Fork就是把一个大任务切分为若干子任务并行的执行,Join就是合并这些子任务的执行结果,最后得到这个大任务的结果.比如计算1+2+..+10000,可以分割成10个子任务,每个子任务分别对1000个数进行求和,最终汇

Fork/Join框架简介

1. 什么是Fork/Join框架 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务 ,最终汇总每个小任务结果后得到大任务结果的框架. 我们再通过Fork和Join这两个单词来理解下Fork/Join框架,Fork就是把一个大任务切分为若干子任务 并行的执行,Join就是合并这些子任务的执行结果,最后得到这个大任务的结果.比如计算1+2+..+ 10000,可以分割成10个子任务,每个子任务分别对1000个数进行求和,最终汇总这10个子任务

定制并发类(八)自定义在 Fork/Join 框架中运行的任务

声明:本文是< Java 7 Concurrency Cookbook>的第七章, 作者: Javier Fernández González 译者:郑玉婷 自定义在 Fork/Join 框架中运行的任务 执行者框架分开了任务的创建和运行.这样,你只要实现 Runnable 对象来使用 Executor 对象.你可以发送 Runnable 任务给执行者,然后它会创建,管理,并终结必要的线程来执行这些任务. Java 7 在 Fork/Join 框架中提供了特殊的执行者.这个框架是设计用来解决那

定制并发类(七)实现ThreadFactory接口生成自定义的线程给Fork/Join框架

声明:本文是< Java 7 Concurrency Cookbook>的第七章,作者: Javier Fernández González     译者:许巧辉 实现ThreadFactory接口生成自定义的线程给Fork/Join框架 Fork/Join框架是Java7中最有趣的特征之一.它是Executor和ExecutorService接口的一个实现,允许你执行Callable和Runnable任务而不用管理这些执行线程. 这个执行者面向执行能被拆分成更小部分的任务.主要组件如下: 一

Java Fork Join 框架(四)性能

原文 http://gee.cs.oswego.edu/dl/papers/fj.pdf   作者:Doug Lea   译者:萧欢 4性能 如今,随着编译器与Java虚拟机性能的不断提升,性能测试结果也仅仅只能适用一时.但是,本节中所提到的测试结果数据却能揭示Fork/join框架的基本特性. 下面表格中简单介绍了在下文将会用到的一组fork/join测试程序.这些程序是从util.concurrent包里的示例代码改编而来,用来展示fork/join框架在解决不同类型的问题模型时所表现的差异