20-案例实现
案例实现
根据如下步骤来实现本案例。
1.创建一个名为 ArrayGenerator 的类。该类用来生成一个由随机整数组成的大小给定的数组。实现名为 generateArray() 的方法—用来生成数组中的数字。该方法接收数组的大小作为参数:
public class ArrayGenerator {
public int[] generateArray(int size) {
int array[]=new int[size];
Random random=new Random();
for (int i=0; i<size; i++){
array[i]=random.nextInt(10);
}
return array;
}
2.创建一个名为 TaskManager 的类。该类用于存储在 ForkJoinPool 中执行的全部任务。由于 ForkJoinPool 和 ForkJoinTask 类的限制,我们将使用该类来取消 ForkJoinPool 类中的全部任务:
public class TaskManager {
3.声明一个名为 tasks 的 ForkJoinTask 类的队列,泛型为 Integer 类:
private final ConcurrentLinkedDeque<ForkJoinTask> tasks;
4.实现该类的构造方法,并初始化任务队列:
public TaskManager(){
tasks=new ConcurrentLinkedDeque<SearchNumberTask>();
}
5.实现 addTask() 方法。该方法将一个 ForkJoinTask 实例对象提交到任务列表中:
public void addTask(ForkJoinTask<Integer> task){
tasks.add(task);
}
6.实现 cancelTasks() 方法。该方法将使用 cancel() 方法取消列表中存储的全部 ForkJoinTask 任务。它接收想要取消其他任务的 ForkJoinTask 实例对象作为参数。该方法会取消其他全部任务:
public void cancelTasks(SearchNumberTask cancelTask){
for (SearchNumberTask task :tasks) {
if (task!=cancelTask) {
task.cancel(true);
task.logCancelMessage();
}
}
}
7.实现 SearchNumberTask 类,它继承 RecursiveTask 类,泛型为 Integer 类。该类将在一个整型数组中搜索给定数字:
public class SearchNumberTask extends RecursiveTask<Integer> {
8.声明一个名为 numbers 的私有 int 数组:
private int numbers[];
9.声明两个名为 start 和 end 的私有 int 变量。它们决定任务要处理数组中的哪些元素:
private int start, end;
10.声明一个名为 number 的私有 int 变量,用来存储将要搜索的数字:
private int number;
11.声明一个名为 manager 的私有 TaskManager 型变量。我们将使用该实例对象来取消全部任务:
private TaskManager manager;
12.声明一个私有 int 常量并将其初始化为−1。它将是未搜索到数字的任务的返回值:
private final static int NOT_FOUND=-1;
13.实现该类的构造方法并初始化全部属性:
public SearchNumberTask(int numbers[], int start, int end,
int number, TaskManager manager){
this.numbers=numbers;
this.start=start;
this.end=end;
this.number=number;
this.manager=manager;
}
14.实现 compute() 方法。该方法开头会在控制台打印 start 和 end 的值:
@Override
protected Integer compute() {
System.out.println("Task: "+start+":"+end);
15.如果 start 和 end 的值差距超过 10 ,则调用 launchTasks() 方法来将任务分割为两个子任务:
int ret;
if (end-start>10) {
ret=launchTasks();
16.否则,调用 lookForNumber() 方法在数组待处理元素块中搜索给定数字:
} else {
ret=lookForNumber();
}
17.返回任务结果:
return ret;
18.实现 lookForNumber() 方法:
private int lookForNumber() {
19.在需要处理的全部元素中,比对元素和搜索数字的值。若相同,则在控制台打印出相关信息,并使用 TaskManager 类的 cancelTasks() 方法来取消全部任务:
for (int i=start; i<end; i++){
if (numbers[i]==number) {
System.out.printf("Task: Number %d found in position %d\n",
number,i);
manager.cancelTasks(this);
return i;
}
20.在循环中,让当前任务休眠1s:
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
21.最后,返回−1:
return NOT_FOUND;
}
22.实现 launchTasks() 方法。首先,将任务中需要处理的一组数字分割为两组,并创建两个 Task 实例对象来处理它们:
private int launchTasks() {
int mid=(start+end)/2;
Task task1=new Task(numbers,start,mid,number,manager);
Task task2=new Task(numbers,mid,end,number,manager);
23.将任务添加到 TaskManager 实例对象中:
manager.addTask(task1);
manager.addTask(task2);
24.调用 fork() 方法异步执行这两个任务:
task1.fork();
task2.fork();
25.等待任务执行结束,如果返回值不为−1,则返回第一个任务的返回结果,否则返回第二个任务的返回结果:
int returnValue;
returnValue=task1.join();
if (returnValue!=-1) {
return returnValue;
}
returnValue=task2.join();
return returnValue;
26.实现 writeCancelMessage() 方法。该方法用于在任务取消时打印信息:
public void logCancelMessage(){
System.out.printf("Task: Canceled task from %d to %d",
start,end);
}
27.至此,我们可以开始实现应用程序的入口,创建包含 main() 方法的 Main 类:
public class Main {
public static void main(String[] args) {
28.使用 ArrayGenerator 类创建一个包含 1000 个数字的数组:
ArrayGenerator generator=new ArrayGenerator();
int array[]=generator.generateArray(1000);
29.创建一个 TaskManager 实例对象:
TaskManager manager=new TaskManager();
30.使用默认的构造方法创建一个 ForkJoinPool 实例对象:
ForkJoinPool pool=new ForkJoinPool();
31.创建一个 Task 对象来处理之前生成的数组:
SearchNumberTask task=new SearchNumberTask (array,0,1000,
5,manager);
32.调用 execute() 方法在池中异步执行任务:
pool.execute(task);
33.调用 shutdown() 方法关闭池:
pool.shutdown();
34.调用 ForkJoinPool 类的 awaitTermination() 方法来等待任务完成:
try {
pool.awaitTermination(1, TimeUnit.DAYS);
} catch (InterruptedException e) {
e.printStackTrace();
}
35.在控制台打印信息以表明程序结束:
System.out.printf("Main: The program has finished\n");