默认情况下,被一个 ForkJoinPool 类执行的任务是 ForkJoinTask 类对象。 您也可以提交 Runnable 和 Callable 对象到一个 ForkJoinPool 类,但这样享受不到任何 Fork/Join 框架的好处。 一般提交到 ForkJoinPool 的是 ForkJoinTask 类的2个子类:
在本节中,将学习如何通过实现一个扩展 ForkJoinTask 类的任务为 Fork/Join 框架实现您自己的任务。 将实现的任务测算并输出它的执行时间到终端,这样您能控制它的进展。 您也能实现您自己的 Fork/Join 任务来写日志、在任务中获取资源或对结果进行后处理。
本节的示例代码在 com.elanzone.books.noteeg.chpt7.sect08 package中
定制工作任务类: MyWorkerTask : extends ForkJoinTask<Void>
无返回,故泛型参数为 Void
private String name; public MyWorkerTask(String name) { this.name = name; }
@Override public Void getRawResult() { return null; } @Override protected void setRawResult(Void value) { }
@Override protected boolean exec() { Date startDate = new Date(); compute(); Date finishDate = new Date(); long diff = finishDate.getTime() - startDate.getTime(); System.out.printf("MyWorkerTask: %s : %d Milliseconds to complete.\n", name, diff); return true; }
public String getName() { return name; }
protected abstract void compute();
任务类 : Task : extends MyWorkerTask
private int array[]; private int start, end; public Task(int[] array, int start, int end) { this.array = array; this.end = end; this.start = start; }
@Override protected void compute() { if ((end - start) > 100) { int mid = (end + start) / 2; Task task1 = new Task(this.getName() + "1", array, start, mid); Task task2 = new Task(this.getName() + "2", array, mid, end); invokeAll(task1, task2); } else { for (int i = start; i < end; i++) { array[i]++; } try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } }
控制类 : Main
public static void main(String[] args) throws Exception { int array[] = new int[10000]; ForkJoinPool pool = new ForkJoinPool(); Task task = new Task("Task", array, 0, array.length); pool.invoke(task); pool.shutdown(); System.out.printf("Main: End of the program.\n"); }
在本节中,实现了扩展 ForkJoinTask 类的 MyWorkerTask 类。 它是实现能被放在 ForkJoinPool 执行者中执行、并能有 ForkJoinPool 执行者的各样好处(如工作窃取算法)的任务的基类。 此类相当于 RecursiveAction 和 RecursiveTask 类。
扩展 ForkJoinTask 类必须实现以下3个方法:
最后,在例子的主类中,创建了一个有 10000 个元素的数组、一个 ForkJoinPool 执行者 和 一个处理整个数组的 Task 对象。 运行此程序,您将看到被执行的不同的任务是如何输出运行时间到终端的。