在 ForkJoinPool 中执行 ForkJoinTask,可以同步或异步方式执行。
两者有一个大的不同:
实现一个程序在一个文件夹及其子文件夹中搜索有指定后缀的文件。 您将实现的 ForkJoinTask 类将处理文件夹的内容。对于文件夹的每个子文件夹,它将以异步方式提交一个新任务到 ForkJoinPool 类。 对文件夹中的每个文件,检查文件的后缀,如果匹配则加到结果列表。
本节的示例代码在 com.elanzone.books.noteeg.chpt5.sect04 package中
文件夹处理类 : FolderProcessor : extends RecursiveTask<List<String>>
private static final long serialVersionUID = 1L;
private String path; private String extension; public FolderProcessor(String path, String extension) { this.path = path; this.extension = extension; }
@Override protected List<String> compute() { List<String> list = new ArrayList<>(); List<FolderProcessor> tasks = new ArrayList<>(); File file = new File(path); File content[] = file.listFiles(); if (content != null) { for (File aContent : content) { if (aContent.isDirectory()) { FolderProcessor task = new FolderProcessor(aContent.getAbsolutePath(), extension); task.fork(); tasks.add(task); } else { if (checkFile(aContent.getName())) { list.add(aContent.getAbsolutePath()); } } } } if (tasks.size() > 50) { System.out.printf("%s: %d tasks ran.\n", file.getAbsolutePath(), tasks.size()); } addResultsFromTasks(list, tasks); return list; }
private void addResultsFromTasks(List<String> list, List<FolderProcessor> tasks) { for (FolderProcessor item : tasks) { list.addAll(item.join()); } }
private boolean checkFile(String name) { return name.endsWith(extension); }
控制类 :Main
ForkJoinPool pool = new ForkJoinPool(); FolderProcessor system = new FolderProcessor("C:\\Windows", "log"); FolderProcessor apps = new FolderProcessor("C:\\Program Files", "log"); FolderProcessor documents = new FolderProcessor("C:\\Documents And Settings", "log");
pool.execute(system); pool.execute(apps); pool.execute(documents);
do { System.out.printf("******************************************\n"); System.out.printf("Main: Parallelism: %d\n", pool.getParallelism()); System.out.printf("Main: Active Threads: %d\n", pool.getActiveThreadCount()); System.out.printf("Main: Task Count: %d\n", pool.getQueuedTaskCount()); System.out.printf("Main: Steal Count: %d\n", pool.getStealCount()); System.out.printf("******************************************\n"); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } while ((!system.isDone()) || (!apps.isDone()) || (!documents.isDone()));
pool.shutdown();
List<String> results; results = system.join(); System.out.printf("System: %d files found.\n", results.size()); results = apps.join(); System.out.printf("Apps: %d files found.\n", results.size()); results = documents.join(); System.out.printf("Documents: %d files found.\n", results.size());
本例的关键在 FolderProcessor 类。每个任务处理一个文件夹的内容。内容有以下2中元素:
如果任务找到一个文件夹,它创建另一个 Task 对象来处理那个文件夹并用 fork() 方法将其提交到池子里。 池子如果有空闲的工作线程则直接用,否则创建一个新的线程来执行此任务。fork() 方法立即返回,所以任务能持续处理文件夹的内容。 对每个文件,任务将比较它的后缀是否与要查找的一致,如果一致则将文件名加入到结果列表。
当任务已经处理了被分配的文件夹的所有内容,它用 join() 方法等待所有它提交到池子里的任务结束。 join() 方法等待被调用的任务运行结束,并返回由 compute() 方法的返回值。 任务将所有子任务及自己的结果汇总并将此列表作为 compute() 方法的返回值返回。
ForkJoinPool 类允许任务以异步的方式执行。您用 execute() 方法送了3个任务到池子中。 在 Main 类中,您用 shutdown() 方法结束池子并将在池子中运行的任务的状态情况输出。 ForkJoinPool 类还有更多的方法可用。详见后述。
本例使用了 join() 方法等待任务的结束并获得其结果。也可以使用以下2个版本的 get() 方法:
get() 和 join() 方法有2个主要区别: