- 主要的Fork/Join类
- ForkJoinTask<V>:用来定义任务的抽象类
-
- ForkJoinTask与Thread不同,ForkJoinTask表示任务的轻量级抽象,而不是执行线程
- final ForkJoinTask<V> fork()
-
- 为调用任务的异步执行提交调用任务,意味着调用fork()方法的线程将持续运行
- 意味着调用代码不会等待任务完成,相反调用代码将继续异步执行
- final V join()
-
- 等待调用该方法的任务终止,终止结果被返回
- 调用代码会进行等待,直到有结果返回
- final V invoke()
-
- 将并行(fork)和连接(join)操作合并到单个调用中
- 返回调用的结果
- 意味着调用代码进行等待
- static void invokeAll(ForkJoinTask<?> taskA, ForkJoinTask<?> taskB), static void invokeAll(ForkJoinTask<?> ... taskList)
- boolean cancel(boolean interruptOK)
-
- 用来取消任务,如果被取消就返回true,不能被取消就返回false
- 默认实现没有使用interruptOK参数,通常是从任务外部的代码调用cancel()方法
- final boolean isCancelled()
-
- 如果调用任务在结束之前已经取消,就返回true,否则返回false
- final boolean isCompletedNormally()
- final boolean isCompletedAbnormally()
- void reinitialize()
-
- 用于重新启动任务
- static boolean inForkJoinPool()
-
- Returns
true
if the current thread is aForkJoinWorkerThread
executing as a ForkJoinPool computation. - 像invokeAll()和fork()这样的方法只能在ForkJoinTask中调用,遵守这条规则通常很容易,但是在有些情况下,可能会具有能够在任务内部或外部执行的代码。可用通过使用inForkJoinPool()方法,确定代码是否在任务内部执行(判断当前线程是否在ForkJoinPool中运行)
- Returns
- ForkJoinPool:管理ForkJoinTask的执行
-
- 构造函数
-
- ForkJoinPool()
-
- 创建默认池,支持的并行级别等于系统中可用处理器的数量
- ForkJoinPool(int pLevel)
-
- 指定并行级别
- 创建好ForkJoinPool实例后,就可以通过大量不同方法开始执行任务,第一个常被认为是主任务
- 通常由主任务开始其他的由池管理的子任务
- <T> T invoke(ForkJoinTask<T> task)
-
- 一种常用的开始主任务的方式
- 这个方法开始由task指定的任务,并且返回任务结果。这意味着调用代码会进行等待,直到invoke()方法返回为止
- void execute(ForkJoinTask<?> task), void execute(Runnable task)
-
- 这个方法开始由task指定的任务,但是调用代码不会等待任务完成,相反,调用代码将继续异步执行
- int getParalleism()
-
- 返回当前起作用的并行级别
- Runtime.getRuntime().availableProcessors()
-
- 返回系统中可用处理器的数量
- RecursiveAction:ForkJoinTask<V>的子类,用于不返回值的任务
-
- 通常代码回扩展RecursiveAction以创建具有void返回类型的任务
- 一般来说,用于为不返回结果的任务实现递归的、分而治之的策略
- protected abstract void compute()
-
- 将定义任务的代码放在compute()中。compute()方法代表任务的计算部分
- RecursiveTask<V>:ForkJoinTask<V>的子类,用于返回值的任务
-
- 一般来说,用于为返回结果的任务实现递归的、分而治之的策略
- protected abstract V compute()
-
- 表示任务的计算部分,将定义任务的代码放到compute()中
- 使用RecursiveAction的实例
// A simple example of the basic divide-and-conquer strategy.
// In this case, RecursiveAction is used.
import java.util.concurrent.*;
import java.util.*;
// A ForkJoinTask (via RecursiveAction) that transforms
// the elements in an array of doubles into their square roots.
class SqrtTransform extends RecursiveAction {
// The threshold value is arbitrarily set at 1,000 in this example.
// In real world code, its optimal value can be determined by
// profiling and experimentation.
final int seqThreshold = 1000;
// Array to be accessed.
double[] data;
// Deterines what part of data to process.
int start, end;
SqrtTransform(double[] vals, int s, int e ) {
data = vals;
start = s;
end = e;
}
// This is the method in which parallel computation will occur.
protected void compute() {
// If number of elements is below the sequential threshold,
// then process sequentially.
if(
(end - start) < seqThreshold) {
// Transform each element into its square root.
for(int i = start; i < end; i++) {
data[i] = Math.sqrt(data[i]);
}
}
else {
// Otherwise, continue to break the data into smaller peices.
// Find the midpoint.
int middle = (start + end) / 2;
// Invoke new tasks, using the subdivided data.
invokeAll(new SqrtTransform(data, start, middle),
new SqrtTransform(data, middle, end));
}
}
}
// Demonstrate parallel execution.
class ForkJoinDemo {
public static void main(String args[]) {
// Create a task pool.
ForkJoinPool fjp = new ForkJoinPool();
double[] nums = new double[100000];
// Give nums some values.
for(int i = 0; i < nums.length; i++)
nums[i] = (double) i;
System.out.println("A portion of the original sequence:");
for(int i=0; i < 10; i++)
System.out.print(nums[i] + " ");
System.out.println("\n");
SqrtTransform task = new SqrtTransform(nums, 0, nums.length);
// Start the main ForkJoinTask.
fjp.invoke(task);
System.out.println("A portion of the transformed sequence" +
" (to four decimal places):");
for(int i=0; i < 10; i++)
System.out.format("%.4f ", nums[i]);
System.out.println();
}
}
- RecursiveTask<V>实例
// A simple example that uses RecursiveTask<V>.
import java.util.concurrent.*;
// A RecursiveTask that computes the summation of an array of doubles.
class Sum extends RecursiveTask<Double> {
// The sequential threshold value.
final int seqThresHold = 500;
// Array to be accessed.
double[] data;
// Deterines what part of data to process.
int start, end;
Sum(double[] vals, int s, int e ) {
data = vals;
start = s;
end = e;
}
// Find the summation of an array of doubles.
protected Double compute() {
double sum = 0;
// If number of elements is below the sequential threshold,
// then process sequentially.
if(
(end - start) < seqThresHold) {
// Sum the elements.
for(int i = start; i < end; i++) sum += data[i];
}
else {
// Otherwise, continue to break the data into smaller peices.
// Find the midpoint.
int middle = (start + end) / 2;
// Invoke new tasks, using the subdivided data.
Sum subTaskA = new Sum(data, start, middle);
Sum subTaskB = new Sum(data, middle, end);
// Start each subtask by forking.
subTaskA.fork();
subTaskB.fork();
// Wait for the subtasks to return, and aggregate the results.
sum = subTaskA.join() + subTaskB.join();
}
// Return the final sum.
return sum;
}
}
// Demonstrate parallel execution.
class RecurTaskDemo {
public static void main(String args[]) {
// Create a task pool.
ForkJoinPool fjp = new ForkJoinPool();
double[] nums = new double[5000];
// Initialize nums with values that alternate between
// positive and negative.
for(int i=0; i < nums.length; i++)
nums[i] = (double) (((i%2) == 0) ? i : -i) ;
Sum task = new Sum(nums, 0, nums.length);
// Start the ForkJoinTasks. Notice that in this case,
// invoke() returns a result.
double summation = fjp.invoke(task);
System.out.println("Summation " + summation);
}
}