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");