目录
RecursiveTask
ForkJoinTask的子类,该类可以返回执行结果。
案例说明
模拟一个文档,在文档中查找匹配单词的数量。该功能分为两步:
- 文档任务,在文档中的一个行集合中查找单词数量。
- 行任务,在文档的一行中查找单词数量。
一、主程序
package xyz.jangle.thread.test.n5_3.recursivetask;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
/**
* 5.3、合并任务的执行结果
* 模拟一个文档,在文档中查找匹配单词的数量。
* 每10行以内作为一个1级任务,该1级任务再细分为每一行的2级任务。
*
* @author jangle
* @email jangle@jangle.xyz
* @time 2020年8月27日 下午6:13:34
*
*/
public class M {
public static void main(String[] args) {
DocumentMock mock = new DocumentMock();
String[][] document = mock.generateDocument(100, 10000, "java");
DocumentTask task = new DocumentTask(document, 0, 100, "java");
// 获取默认的ForkJoinPool
ForkJoinPool pool = ForkJoinPool.commonPool();
pool.execute(task);
do {
System.out.println("***********************");
System.out.println("Main:Active Thread活跃的线程数:" + pool.getActiveThreadCount());
System.out.println("Main:Task Count任务数:" + pool.getQueuedTaskCount());
System.out.println("Main:Steal Count线程窃取数量:" + pool.getStealCount());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (!task.isDone());
pool.shutdown();
try {
pool.awaitTermination(1, TimeUnit.DAYS);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
System.out.println("Main:单词统计结果:" + task.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
二、文档工厂
package xyz.jangle.thread.test.n5_3.recursivetask;
import java.util.Random;
/**
* 模拟文档的工厂
* @author jangle
* @email jangle@jangle.xyz
* @time 2020年8月27日 下午6:14:07
*
*/
public class DocumentMock {
private String words[] = { "the", "hello", "goodbye", "packt", "java", "thread", "pool", "random", "class",
"main" };
/**
* 生产一个N行M列的单词二维数组(模拟文档)
* @param numLines 行数
* @param numWords 单词数
* @param word 待查找的单词
* @return
*/
public String[][] generateDocument(int numLines, int numWords, String word) {
int counter = 0;
String[][] document = new String[numLines][numWords];
Random random = new Random();
for (int i = 0; i < numLines; i++) {
for (int j = 0; j < numWords; j++) {
int index = random.nextInt(words.length);
document[i][j] = words[index];
if (document[i][j].equals(word)) {
counter++;
}
}
}
System.out.println("DocumentMock:匹配的单词数量:"+counter);
return document;
}
}
三、文档统计任务
文档统计任务会将任务划分为10行以内的子任务,该子任务还将委托行任务进行处理。
package xyz.jangle.thread.test.n5_3.recursivetask;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.RecursiveTask;
/**
* 统计文档中指定单词出现次数的任务类
*
* @author jangle
* @email jangle@jangle.xyz
* @time 2020年8月27日 下午6:24:38
*
*/
public class DocumentTask extends RecursiveTask<Integer> {
/**
*
*/
private static final long serialVersionUID = 1L;
private String[][] document;
private int start, end;
private String word;
public DocumentTask(String[][] document, int start, int end, String word) {
super();
this.document = document;
this.start = start;
this.end = end;
this.word = word;
}
@Override
protected Integer compute() {
Integer result = null;
if (end - start < 10) {
// 统计并返回单词数
result = processLines(document, start, end, word);
} else {
// 将其拆分为2个子任务
int mid = (start + end) / 2;
DocumentTask task = new DocumentTask(document, start, mid, word);
DocumentTask task2 = new DocumentTask(document, mid, end, word);
invokeAll(task, task2);
try {
// 汇总子任务的结果
result = task.get() + task2.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
return result;
}
/**
* 统计当前段落中单词匹配的数量(为段落的每一行创建一个任务,查询单词数量并汇总)
*
* @param document2
* @param start2
* @param end2
* @param word2
* @return
*/
private Integer processLines(String[][] document2, int start2, int end2, String word2) {
ArrayList<LineTask> tasks = new ArrayList<LineTask>();
for (int i = start2; i < end2; i++) {
LineTask task = new LineTask(document2[i], 0, document2[i].length, word2);
tasks.add(task);
}
// 执行所有任务
invokeAll(tasks);
// 统计任务结果
int result = 0;
for (LineTask lineTask : tasks) {
try {
result += lineTask.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
return result;
}
}
四、行统计任务
最小的任务处理单元
package xyz.jangle.thread.test.n5_3.recursivetask;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.TimeUnit;
/**
* 统计每一行匹配单词数的任务类
*
* @author jangle
* @email jangle@jangle.xyz
* @time 2020年8月27日 下午6:32:42
*
*/
public class LineTask extends RecursiveTask<Integer> {
private static final long serialVersionUID = 1L;
private String[] line;
private int start, end;
private String word;
public LineTask(String[] line, int start, int end, String word) {
this.line = line;
this.start = start;
this.end = end;
this.word = word;
}
@Override
protected Integer compute() {
Integer result = null;
if (end - start < 100) {
// 统计该行匹配单词的数量
result = count(line, start, end, word);
} else {
// 拆分为2个子任务
int middle = (start + end) / 2;
LineTask task1 = new LineTask(line, start, middle, word);
LineTask task2 = new LineTask(line, middle, end, word);
invokeAll(task1, task2);
try {
// 将子任务的结果汇总
result = task1.get() + task2.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
return result;
}
/**
* 统计指定部分单词匹配的数量
*
* @param line2
* @param start2
* @param end2
* @param word2
* @return
*/
private Integer count(String[] line2, int start2, int end2, String word2) {
Integer count = 0;
for (int i = start2; i < end2; i++) {
if (line2[i].equals(word2)) {
count++;
}
}
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
return count;
}
}
五、处理结果
DocumentMock:匹配的单词数量:100371
***********************
Main:Active Thread活跃的线程数:1
Main:Task Count任务数:0
Main:Steal Count线程窃取数量:0
***********************
Main:Active Thread活跃的线程数:7
Main:Task Count任务数:56
Main:Steal Count线程窃取数量:0
***********************
Main:Active Thread活跃的线程数:7
Main:Task Count任务数:51
Main:Steal Count线程窃取数量:0
***********************
Main:Active Thread活跃的线程数:7
Main:Task Count任务数:54
Main:Steal Count线程窃取数量:0
***********************
Main:Active Thread活跃的线程数:7
Main:Task Count任务数:47
Main:Steal Count线程窃取数量:0
***********************
Main:Active Thread活跃的线程数:7
Main:Task Count任务数:39
Main:Steal Count线程窃取数量:0
***********************
Main:Active Thread活跃的线程数:7
Main:Task Count任务数:34
Main:Steal Count线程窃取数量:0
***********************
Main:Active Thread活跃的线程数:7
Main:Task Count任务数:40
Main:Steal Count线程窃取数量:0
***********************
Main:Active Thread活跃的线程数:7
Main:Task Count任务数:28
Main:Steal Count线程窃取数量:0
***********************
Main:Active Thread活跃的线程数:7
Main:Task Count任务数:57
Main:Steal Count线程窃取数量:1
***********************
Main:Active Thread活跃的线程数:7
Main:Task Count任务数:36
Main:Steal Count线程窃取数量:1
***********************
Main:Active Thread活跃的线程数:7
Main:Task Count任务数:41
Main:Steal Count线程窃取数量:1
***********************
Main:Active Thread活跃的线程数:7
Main:Task Count任务数:32
Main:Steal Count线程窃取数量:1
***********************
Main:Active Thread活跃的线程数:7
Main:Task Count任务数:40
Main:Steal Count线程窃取数量:6
***********************
Main:Active Thread活跃的线程数:7
Main:Task Count任务数:50
Main:Steal Count线程窃取数量:8
***********************
Main:Active Thread活跃的线程数:7
Main:Task Count任务数:42
Main:Steal Count线程窃取数量:8
***********************
Main:Active Thread活跃的线程数:7
Main:Task Count任务数:40
Main:Steal Count线程窃取数量:8
***********************
Main:Active Thread活跃的线程数:6
Main:Task Count任务数:36
Main:Steal Count线程窃取数量:15
***********************
Main:Active Thread活跃的线程数:6
Main:Task Count任务数:29
Main:Steal Count线程窃取数量:15
***********************
Main:Active Thread活跃的线程数:7
Main:Task Count任务数:21
Main:Steal Count线程窃取数量:20
Main:单词统计结果:100371