当前位置:嗨网首页>书籍在线阅读

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 中执行的全部任务。由于 ForkJoinPoolForkJoinTask 类的限制,我们将使用该类来取消 ForkJoinPool 类中的全部任务:

public class TaskManager {

3.声明一个名为 tasksForkJoinTask 类的队列,泛型为 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.声明两个名为 startend 的私有 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() 方法。该方法开头会在控制台打印 startend 的值:

@Override
protected Integer compute() {
  System.out.println("Task: "+start+":"+end);

15.如果 startend 的值差距超过 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");