相对于串行编程来说,并行编程有如下三个主要目标:
package com.nuaa.ldm;
import java.util.*;
import java.util.concurrent.*;
import static java.util.Arrays.asList;
public class TaskTest {
static class Sum implements Callable {
private final longfrom;
private final long to;
Sum(long from,long to) {
this.from = from;
this.to = to;
}
@Override
public Long call() {
long acc = 0;
for (long i =from; i <= to; i++) {
acc = acc + i;
}
return acc;
}
}
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(2);
List> results = executor.invokeAll(asList(
new Sum(0, 10),new Sum(100, 1000), new Sum(10000, 1000000)
));
executor.shutdown();
for(Future result : results) {
System.out.println(result.get());
}
}
}
这种方法的优点是减少了争用,因为工作线程从头获取任务,而窃取线程从尾部窃取任务。这种调度算法较适用于递归算法,递归算法采用分治思想,使得早期产生的任务单元较大,因而窃取的较大任务进一步递归分解,因此减少尾部窃取次数。另外,父任务很可能要等待子任务(join),所以从队列头部子任务开始执行也是一种优化。
总之,它会使用有限的线程执行大量任务,同时保持各线程的任务都处于繁忙的执行状态,而尽量不让线程处于等待状态。为了做到这点可能会从其它线程的任务队列中窃取任务来执行,所以叫work-stealing。
package com.nuaa.ldm;
import java.math.BigInteger;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;
public class Fibonacci extends RecursiveTask{
int n ;
public Fibonacci() {
}
Fibonacci(int i) {
this.n = i;
}
private BigInteger compute(int small) {
final int[] results = { 1, 1, 2, 3, 5,8, 13, 21, 34, 55, 89 };
return new BigInteger(results[small]+"");
}
@Override
protected BigIntegercompute() {
if(n < 10){ //任务足够小,直接查表返回
return compute(n);
}
System.out.println(Thread.currentThread().getName()+"");
Fibonacci f1= new Fibonacci(n-1);//创建子任务
Fibonacci f2= new Fibonacci(n-2);//创建子任务
f2.fork();//子任务执行
return f1.compute().add(f2.join());//两个子任务结果的合并
}
public static voidmain(String[] args) {
/*线程的数量有限,超过一定的数量会报错,内存溢出*/
ForkJoinPool forkJoinPool = new ForkJoinPool();
Fibonacci fibonacci = new Fibonacci(50);//创建任务
Future result = forkJoinPool.submit(fibonacci);
try {
System.out.println(result.get());
} catch(InterruptedException e) {
e.printStackTrace();
} catch(ExecutionException e) {
e.printStackTrace();
}
}
}
package com.nuaa.ldm;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
/** 计算1^2+2^2+3^2+4^2+5^2+6^2通过二分来分段计算,而二分法的会将数组分成若干段,然后分别进行计算
* */
public class FibonacciAction extends RecursiveAction{
final double[] array;
final int lo, hi;
double result;
FibonacciAction next; // keeps track ofright-hand-side tasks
FibonacciAction(double[] array, int lo, inthi, FibonacciAction next) {
this.array = array; this.lo = lo; this.hi= hi;
this.next = next;
}
/*计算数组下表从[l,h)平方和*/
double atLeaf(int l, int h) {
double sum = 0;
for (int i = l; i < h; ++i) // performleftmost base step
sum += array[i] * array[i];
return sum;
}
/*分治(递归过程)*/
protected void compute() {
int l = lo;
int h = hi;
FibonacciAction right = null;
/*二分,并且要求SurplusQueuedTaskCount小于3*/
while (h - l > 1 &&getSurplusQueuedTaskCount() <= 3) {
int mid = (l + h) >>> 1;
/*创建一个子任务*/
right = new FibonacciAction(array, mid,h, right);
right.fork();
h = mid;
}
double sum = atLeaf(l, h);
while (right != null) {
/*用剩余时间去执行队列中的其他线程任务,提高效率,使得线程处于忙碌状态*/
if (right.tryUnfork()) // directlycalculate if not stolen
sum += right.atLeaf(right.lo,right.hi);
else {
/*等待执行结果*/
right.join();
sum += right.result;
}
right = right.next;
}
result = sum;
}
public static voidmain(String[] args) {
System.out.println(sumOfSquares(newForkJoinPool(),new double[]{1,2,3,4,5,6}));
}
static double sumOfSquares(ForkJoinPool pool,double[] array) {
int n = array.length;
FibonacciAction a = newFibonacciAction(array, 0, n, null);
pool.invoke(a);
return a.result;
}
}