12-案例实现
案例实现
根据如下步骤来实现本案例。
1.创建一个名为 FolderProcessor
的类,并使之继承泛型类型为 List
的 Counted- Completer
类:
public class FolderProcessor extends
CountedCompleter<List<String>> {
2.声明一个名为 path
的私有 String
变量。该变量用于存储任务将要处理的文件夹全路径:
private String path;
3.声明一个名为 extension
的私有 String
变量。该变量用于存储任务要搜索的文件扩展名:
private String extension;
4.声明两个名为 tasks
和 resultList
的私有 List
变量。第一个变量将存储任务中所有已启动的子任务,第二个变量则存储任务的执行结果:
private List<FolderProcessor> tasks;
private List<String> resultList;
5.实现该类的构造方法并初始化全部属性和其父类。将构造方法声明成 protected
类型,这样它只能在内部使用:
protected FolderProcessor (CountedCompleter<?> completer,
String path, String extension) {
super(completer);
this.path=path;
this.extension=extension;
}
6.实现另一个公共构造方法来供外部调用。由于该方法创建的任务没有父任务,因此该实例对象不作为参数来传递:
public FolderProcessor (String path, String extension) {
this.path=path;
this.extension=extension;
}
7.实现 compute()
方法。因为任务的基类是 CountedCompleter
类,所以该方法返回值为空:
@Override
public void compute() {
8.初始化两个 List
变量:
resultList=new ArrayList<>();
tasks=new ArrayList<>();
9.获取文件夹的内容:
File file=new File(path);
File content[] = file.listFiles();
10.对于文件夹内的每一个元素,如果为子文件夹,则创建一个新的 FolderProcessor
实例对象,异步调用 fork()
方法来执行。使用第一个构造方法,传递当前任务作为已完成任务。同时调用 addToPendingCount()
方法,增加处理的任务数:
if (content != null) {
for (int i = 0; i < content.length; i++) {
if (content[i].isDirectory()) {
FolderProcessor task=new FolderProcessor(this,
content[i].getAbsolutePath(), extension);
task.fork();
addToPendingCount(1);
tasks.add(task);
11.否则,调用 checkFile()
方法对比当前文件和搜索文件的扩展名。若相同,则在之前声明的字符串列表中存储文件的全路径:
} else {
if (checkFile(content[i].getName())){
resultList.add(content[i].getAbsolutePath());
}
}
}
12.如果 FolderProcessor
子任务列表元素超过50个,则打印信息来说明这一情况:
if (tasks.size()>50) {
System.out.printf("%s: %d tasks ran.\n",
file.getAbsolutePath(),tasks.size());
}
}
13.调用 tryComplete()
方法来尝试结束当前任务:
tryComplete();
}
14.实现 onCompletion()方
法。该方法在全部子任务运行结束后执行,它将所有子任务的运行结果汇总到当前任务的返回结果列表:
@Override
public void onCompletion(CountedCompleter<?> completer) {
for (FolderProcessor childTask : tasks) {
resultList.addAll(childTask.getResultList());
}
}
15.实现 checkFile()
方法。该方法用于对比传递的文件参数和搜索的扩展名是否一致。若一致则返回 true
,否则返回 false
:
private boolean checkFile(String name) {
return name.endsWith(extension);
}
16.实现 getResultList()
方法来返回一个任务列表。因为该方法的代码很简短,所以此处不再列出。
17.至此,我们可以开始实现应用程序的入口,创建包含 main()
方法的 Main
类:
public class Main {
public static void main(String[] args) {
18.用默认构造方法创建 ForkJoinPool
实例对象:
ForkJoinPool pool=new ForkJoinPool();
19.创建3个 FolderProcessor
任务。初始化不同的文件夹路径:
FolderProcessor system=new FolderProcessor("C:\\Windows",
"log");
FolderProcessor apps=new FolderProcessor("C:\\Program Files",
"log");
FolderProcessor documents=new FolderProcessor("C:\\Documents
And Settings","log");
20.在池中用 execute()
方法来执行这3个任务:
pool.execute(system);
pool.execute(apps);
pool.execute(documents);
21.在3个任务执行完成前,每隔1s在控制台打印一次池中状态信息:
do {
System.out.printf("**********************************
********\n");
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()));
22.调用 shutdown()
方法关闭 ForkJoinPool
:
pool.shutdown();
23.在控制台打印每个任务生成的结果数:
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());