Java Fork/Join:收集结果
我在玩fork/join,想到了以下示例:Java Fork/Join:收集结果,java,multithreading,concurrency,fork,Java,Multithreading,Concurrency,Fork,我在玩fork/join,想到了以下示例: App1:2 for循环生成一些随机数到ArrayList并将其传递给fork MyTask(Fork):遍历ArrayLists并将所有数字相加,然后返回值 import java.util.ArrayList; import java.util.concurrent.ForkJoinPool; public class App1 { ArrayList list = new ArrayList(); static final
App1
:2 for循环生成一些随机数到ArrayList
并将其传递给fork
MyTask
(Fork):遍历ArrayLists
并将所有数字相加,然后返回值
import java.util.ArrayList;
import java.util.concurrent.ForkJoinPool;
public class App1 {
ArrayList list = new ArrayList();
static final ForkJoinPool mainPool = new ForkJoinPool();
public App1() {
for (int i = 0; i < 10; i++) {
list.clear();
for (int j = 1000; j <= 100000; j++) {
int random = 1 + (int)(Math.random() * ((100 - 1) + 1));
list.add(random);
}
mainPool.invoke(new MyTask(list));
}
// At the end showing all results
// System.out.println (result1 + result2 + result3...);
}
public static void main(String[] args) {
App1 app = new App1();
}
}
import java.util.ArrayList;
import java.util.concurrent.RecursiveTask;
public class MyTask extends RecursiveTask<Integer> {
ArrayList list = new ArrayList();
int result;
public MyTask(ArrayList list) {
this.list = list;
}
@Override
protected Integer compute() {
for(int i=0; i<=list.size(); i++){
result += (int)list.get(i); // adding up all numbers
}
return result;
}
}
import java.util.ArrayList;
导入java.util.concurrent.ForkJoinPool;
公共类App1{
ArrayList=新建ArrayList();
静态最终ForkJoinPool mainPool=新ForkJoinPool();
公共App1(){
对于(int i=0;i<10;i++){
list.clear();
对于(int j=1000;j只需使用调用的结果即可:
Integer result = mainPool.invoke(new MyTask(list));
System.out.println(i + "\t" + result);
您需要根据需要扩展RecursiveAction
或RecursiveTask
,以确定是否需要返回某些内容
在这两个类中,您都需要重写以下函数:
protected abstract void compute();//in RecursiveAction
protected abstract V compute(); //in RecursiveTask
以下是修改后的快速排序。请注意这一点并尝试实现您自己的排序:
public class ForkJoinQuicksortTask extends RecursiveAction {
static final int SEQUENTIAL_THRESHOLD = 10000;
private final int[] a;
private final int left;
private final int right;
public ForkJoinQuicksortTask(int[] a) {
this(a, 0, a.length - 1);
}
private ForkJoinQuicksortTask(int[] a, int left, int right) {
this.a = a;
this.left = left;
this.right = right;
}
@Override
protected void compute() {
if (serialThresholdMet()) {
Arrays.sort(a, left, right + 1);
} else {
int pivotIndex = partition(a, left, right);
ForkJoinQuicksortTask t1 = new ForkJoinQuicksortTask(a, left, pivotIndex-1);
ForkJoinQuicksortTask t2 = new ForkJoinQuicksortTask(a, pivotIndex + 1, right);
t1.fork();
t2.compute();
t1.join();
}
}
int partition(int[] a, int p, int r){
int i=p-1;
int x=a[r];
for(int j=p;j<r;j++){
if(a[j]<x){
i++;
swap(a, i, j);
}
}
i++;
swap(a, i, r);
return i;
}
void swap(int[] a, int p, int r){
int t=a[p];
a[p]=a[r];
a[r]=t;
}
private boolean serialThresholdMet() {
return right - left < SEQUENTIAL_THRESHOLD;
}
public static void main(String[] args){
ForkJoinPool fjPool = new ForkJoinPool();
int[] a=new int[3333344];
for(int i=0;i<a.length;i++){
int k=(int)(Math.random()*22222);
a[i]=k;
}
ForkJoinQuicksortTask forkJoinQuicksortTask=new ForkJoinQuicksortTask(a, 0, a.length-1);
long start=System.nanoTime();
fjPool.invoke(forkJoinQuicksortTask);
System.out.println("Time: "+ (System.nanoTime()-start));
}
}
公共类ForkJoinQuicksortTask扩展了RecursiveAction{
静态最终整数顺序_阈值=10000;
私人最终int[]a;
左二等兵;
私权;
公共ForkJoinQuicksortTask(int[]a){
这(a,0,a.长度-1);
}
私有ForkJoinQuicksortTask(int[]a,int左,int右){
这个a=a;
this.left=左;
这个。右=右;
}
@凌驾
受保护的void compute(){
if(serialThresholdMet()){
数组。排序(a,左,右+1);
}否则{
int pivotIndex=分区(a,左,右);
ForkJoinQuicksortTask t1=新的ForkJoinQuicksortTask(a,左侧,数据透视索引-1);
ForkJoinQuicksortTask t2=新的ForkJoinQuicksortTask(a,数据透视索引+1,右);
t1.fork();
t2.compute();
t1.join();
}
}
int分区(int[]a,int-p,int-r){
int i=p-1;
int x=a[r];
对于(int j=p;j虽然您的代码看起来不错,但您以错误的方式使用了ForkJoinPool。这是一个用于任务的工具,可以拆分为独立的子任务,并且可以通过多线程提高速度
您的任务可能不够大,无法真正从多线程中获益,但抛开它不谈,因为它是一个学习练习,您仍然需要将主任务拆分为子任务,但您所做的只是对整个阵列进行一次计数
您可以在代码中执行的操作:
- 使用更适合的不同多线程模式
- 分叉任务并在数组中移交开始和结束位置,然后在完成这些子任务后汇总结果
由于您可能对后一种方法感兴趣,下面是一个如何进行此操作的示例:
public class MyTask extends RecursiveTask<Integer> {
final ArrayList<Integer> list;
final int start, end;
public MyTask(ArrayList<Integer> list, int start, int end) {
this.list = list;
this.start = start;
this.end = end;
}
@Override
protected Integer compute() {
if (end - start > 10) { // is this task big enough to justify more threading?
final int half = (end + start) / 2;
final MyTask firstHalf = new MyTask(list, start, half);
final MyTask secondHalf = new MyTask(list, half+1, end);
invokeAll(firstHalf, secondHalf);
return firstHalf.get() + secondHalf.get();
} else {
int result = 0;
for(int i=start; i<=end; i++){
result += list.get(i);
}
return result;
}
}
}
公共类MyTask扩展了RecursiveTask{
最终阵列列表;
最终整数开始,结束;
公共MyTask(数组列表、整型开始、整型结束){
this.list=列表;
this.start=start;
this.end=end;
}
@凌驾
受保护整数计算(){
如果(end-start>10){//,这个任务是否足够大,以证明需要更多线程?
最终整数一半=(结束+开始)/2;
final MyTask firstHalf=新MyTask(列表、开始、一半);
final MyTask secondHalf=新MyTask(列表,一半+1,结束);
调用全部(上半部分、下半部分);
返回firstHalf.get()+secondHalf.get();
}否则{
int结果=0;
对于(int i=start;i您使用的是RecursiveTask
方法不正确。您必须将任务称为recursive,请查看下面可能的解决方案
因此,最终所有工作都被递归地分割成
部分
更新:
您可能想看一看,只需下载jar并执行它,它有一个很好的可视化解释,说明了事情是如何工作的
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
public class RecursiveListSum {
private static class RecursiveSum extends RecursiveTask<Long> {
private static final long serialVersionUID = 1L;
private static final int THRESHOLD = 1000;
private final List<Integer> list;
private final int begin;
private final int end;
public RecursiveSum(List<Integer> list, int begin, int end) {
super();
this.list = list;
this.begin = begin;
this.end = end;
}
@Override
protected Long compute() {
final int size = end - begin;
// if the work to be done is below some threshold, just compute directly.
if (size < THRESHOLD) {
long sum = 0;
for (int i = begin; i < end; i++)
sum += list.get(i);
return sum;
} else {
// split the work to other tasks - recursive (that's why it is called recursive task!)
final int middle = begin + ((end - begin) / 2);
RecursiveSum sum1 = new RecursiveSum(list, begin, middle);
// invoke the first portion -> will be invoked in thread pool
sum1.fork();
RecursiveSum sum2 = new RecursiveSum(list, middle, end);
// now do a blocking! compute on the second task and wait for the result of the first task.
return sum2.compute() + sum1.join();
}
}
}
public static void main(String[] args) {
// First fill the list
List<Integer> list = new ArrayList<>();
long expectedSum = 0;
for (int i = 0; i < 10000; i++) {
int random = 1 + (int) (Math.random() * ((100 - 1) + 1));
list.add(random);
expectedSum += random;
}
System.out.println("expected sum: " + expectedSum);
// now let the RecursiveTask calc the sum again.
final ForkJoinPool forkJoinPool = new ForkJoinPool(Runtime.getRuntime().availableProcessors());
final RecursiveSum recursiveSum = new RecursiveSum(list, 0, list.size());
long recSum = forkJoinPool.invoke(recursiveSum);
System.out.println("recursive-sum: " + recSum);
}
}
import java.util.ArrayList;
导入java.util.List;
导入java.util.concurrent.ForkJoinPool;
导入java.util.concurrent.RecursiveTask;
公共类递归ListSum{
私有静态类RecursiveSum扩展了RecursiveTask{
私有静态最终长serialVersionUID=1L;
私有静态最终整数阈值=1000;
私人最终名单;
私人决赛开始;
私人终端;
公共递归求和(列表、整数开始、整数结束){
超级();
this.list=列表;
this.begin=开始;
this.end=end;
}
@凌驾
受保护的长计算(){
最终整数大小=结束-开始;
//如果要做的工作低于某个阈值,直接计算即可。
如果(大小<阈值){
长和=0;
for(int i=begin;i将在线程池中调用
sum1.fork();
RecursiveSum sum2=新的RecursiveSum(列表、中间、结尾);
//现在对第二个任务执行阻塞!计算并等待第一个任务的结果。
返回sum2.compute()+sum1.join();
}
}
}
公共静态void main(字符串[]args){
//首先填写清单
列表=新的ArrayList();
长期望和=0;
对于(int i=0;i<10000;i++){
int random=1+(int)(Math.random()*((100-1)+1));
列表。添加(随机);
期望和+=随机;
}
System.out.println(“预期金额:+expectedSum”);
//现在让RecursiveTask再次计算总和。
final ForkJoinPool ForkJoinPool=新的ForkJoinPool(Runtime.getRuntime().availableProcessors());
final RecursiveSum RecursiveSum=新的RecursiveSum(list,0,list.size());
long recSum=forkJoinPool.invoke