线程和同步性能
ForkJoinPool
配合分支算法设计,分支算法中的任务可以不断细分为子集,然后这些子集可以并行计算,
最后这些结果归纳合并为一个结果。
使用ThreadPoolExecutor并能高效执行分而治的算法,父任务依赖子任务的完成,一旦处于等待状态就不能继续执行任务
ForkJoinPool允许线程创建新的任务,然后挂起当前任务。当任务挂起,其线程可以执行其他待处理任务。
Example
private class ForkJoinTask extends RecursiveTask<Integer> {
private int first;
private int last;
public ForkJoinTask(int first, int last) {
this.first = first;
this.last = last;
}
protected Integer compute() {
int subCount;
if (last - first < 10) {
subCount = 0;
for (int i = first; i <= last; i++) {
if (d[i] < 0.5)
subCount++;
}
}
else {
int mid = (first + last) >>> 1;
ForkJoinTask left = new ForkJoinTask(first, mid);
left.fork();
ForkJoinTask right = new ForkJoinTask(mid + 1, last);
right.fork();
subCount = left.join();
subCount += right.join();
}
return subCount;
}
}
fork/join范式所实现的挂起使得所有任务只需要几个线程执行,而threadpoolexecutor可能需要更多的线程完成。
场景:
算法的合并部分会执行一些有趣的工作
算法的叶子计算所执行的工作足以抵消创建任务的开销
工作窃取
每个线程都有一个自己派生任务的队列,线程会优先处理自己队列的任务
如果队列是空的,那么会从其他线程队列中窃取任务执行。
自动并行化
JVM层面创建了一个公共的ForkJoinPool,一个静态元素,默认是目标机器的处理器数量————多个jvm同一个机器的性能处理
可以通过-Djava.util.concurrent.ForkJoinPool.common.parallelism=N设置公共池大小
Arrays中的很多方法都使用自动化并行
1.使用Arrays.parallelSort()方法:该方法可以按照指定比较器对数组元素进行排序,并使用多线程来实现并行化处理。
2.使用Arrays.parallelSetAll()方法:该方法可以使用给定的函数对数组元素进行并行处理,并设置返回的值作为新的数组元素。
3.使用Arrays.parallelPrefix()方法:该方法可以使用给定的BinaryOperator对数组元素进行并行处理,并返回一个新的数组。
4.使用Arrays.parallelReplaceAll()方法:该方法可以使用给定的UnaryOperator对数组元素进行并行处理,并对所有元素进行替换。