1 工作窃取模式
当执行新的任务时,可以将其拆分成更小的任务执行,并将小任务加到线程队列中。然后再从一个随机线程的队列中偷取一个并把它放在自己的队列中。相对于一般的线程池实现,fork/join框架的优势体现在对其中包含的任务的处理方式上,在一般的线程池中,如果一个线程正在执行的任务由于某些原因无法继续运行,那么该线程会处于等待状态。而在fork/join框架实现中,如果某个子问题由于等待另外一个子问题的完成而无法继续运行。那么处理该子问题的线程会主动寻找其他尚未运行的子问题来执行.这种方式减少了线程的等待时间,提高了性能。
2 实际使用
package JUC;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.RecursiveTask;
import java.util.stream.LongStream;
public class ForkJoinTest {
public static void main(String[] args) {
test01();
test02();
}
public static void test01() {
// 获取开始时间
Instant start = Instant.now();
// 需要依托ForkJoinPool使用框架
ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinTask<Long> task = new ForkJoin(0L, 100000000L);
// 获取返回值
Long sum = forkJoinPool.invoke(task);
System.out.println(sum);
// 获取结束时间
Instant end = Instant.now();
// 计算用时
System.out.println("用时:" + Duration.between(start, end).toMillis() + "ms");
}
/*
* Java8 新特性
*/
public static void test02() {
Instant start = Instant.now();
Long sum = LongStream.rangeClosed(0L, 100000000L).parallel().reduce(0L, Long::sum);
System.out.println(sum);
Instant end = Instant.now();
System.out.println("用时:" + Duration.between(start, end).toMillis() + "ms");
}
}
/*
* 继承RecursiveTask是具有返回值的compute方法
* 继承RecursiveAction是没有返回值的compute方法
*/
class ForkJoin extends RecursiveTask<Long>{
// 版本号,向JVM声明可以被序列化
private static final long serialVersionUID = -259195479995561737L;
private long start;
private long end;
// 定义临界值
private static final long THURSHOLD = 10000L;
public ForkJoin(long start, long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
long length = end - start;
if (length <= THURSHOLD) {
long sum = 0L;
for (long i = start; i <= end; i++) {
sum += i;
}
return sum;
} else {
long middle = (start + end) / 2;
ForkJoin left = new ForkJoin(start, middle);
left.fork(); // 进行拆分,同时压入线程队列
ForkJoin right = new ForkJoin(middle + 1, end);
right.fork();
return left.join() + right.join();
}
}
}