实战Java高并发程序设计笔记
分而治之:Fork/Join框架
-
ForkJoinPool线程池,对于fork而言并不急于开启线程,而是提交给ForkJoinPool线程池处理,以节省资源。使用ForkJoinPool进行数据处理的总机构图如下
Fork/join执行逻辑 - ForkJoinPool 简单例子:计算1到10000的和
private static final int THRESHOLD = 1000;
public static void main(String args[]) throws ExecutionException, InterruptedException {
System.out.println(System.currentTimeMillis() / 1000);
System.out.println(sum(1, 10000));
System.out.println(System.currentTimeMillis() / 1000);
System.out.println("¥¥¥¥¥¥¥¥¥");
System.out.println(System.currentTimeMillis() / 1000);
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<Long> task = pool.submit(new CountTask(1, 10000));
System.out.println( task.get());
System.out.println(System.currentTimeMillis() / 1000);
}
public static long sum(long start, long end) {
if (end - start + 1 > THRESHOLD) {
return sum(start, (start + end) / 2) + sum((start + end) / 2, end);
} else {
long sum = 0;
for (long i = start; i <= end; i++) {
sum += i;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return sum;
}
}
static class CountTask extends RecursiveTask<Long> {
private long end;
private long start;
public CountTask(long start, long end) {
this.end = end;
this.start = start;
}
@Override
protected Long compute() {
if (end - start + 1 > THRESHOLD) {
CountTask task1 = new CountTask(start, (start + end) / 2);
CountTask task2 = new CountTask((start + end) / 2, end);
task1.fork();
task2.fork();
return task1.join() + task2.join();
} else {
long sum = 0;
for (long i = start; i <= end; i++) {
sum += i;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return sum;
}
}
}
- 运行结构:
1480090749
50080000
1480090765
¥¥¥¥¥¥¥¥¥
1480090765
50080000
1480090768
可以看出,sum 计算需要16秒,而使用ForkJoinPool 仅仅需要3秒 - 使用ForkJoin时,任务的划分层次不能太深否则可能出现两种情况
- 系统内线程数量越来越多。导致性能严重下降
- 函数的调用层次变得很深,最终导致堆栈溢出
网友评论