1. 分支合并框架
1. ForkJoin原理
- Fork:把一个复杂任务进行分拆,大事化小
- Join:把分拆任务的结果进行合并
2. 相关类
- ForkJoinPool
分支合并池 类比=> 线程池
- ForkJoinTask
ForkJoinTask 类比=> FutureTask
ForkJoinTask 是抽象方法,所以需要被继承
RecursiveTask 类继承了 ForkJoinTask
- RecursiveTask
递归任务:继承后可以实现递归(自己调自己)调用的任务
3.使用
- 题目
- 给定一个起始值(begin)和一个结束值(end),计算出[ begin,end ]区间内整数的和
2.代码
public class JUC14_ForkJoin {
public static void main(String[] args) throws Exception{
// 线程操作资源类,这里的资源类就是 MyTask
MyTask task = new MyTask(1, 100);
// 获取分支合并池
ForkJoinPool forkJoinPool = new ForkJoinPool();
// 提交池中任务,获得任务对象
ForkJoinTask<Integer> forkJoinTask = forkJoinPool.submit(task);
// 通过 .get() 方法获得任务的结果
System.out.println(forkJoinTask.get());
// 关闭池
forkJoinPool.shutdown();
}
}
// 继承 RecursiveTask 覆写 compute 方法,写出处理任务的具体操作
class MyTask extends RecursiveTask<Integer>{
//设置以下阈值,一个最小的问题的规模
private static final Integer value = 10;
private int begin;
private int end;
private int result;
public MyTask(int begin, int end) {
this.begin = begin;
this.end = end;
}
// 进行计算
@Override
protected Integer compute() {
if (end - begin >= value){
for (int i = begin; i <= end; i++){
result += i;
}
}else {
int mid = (end + begin) / 2;
MyTask task1 = new MyTask(begin,mid);
MyTask task2 = new MyTask(mid+1,end);
// 进行递归,分治
task1.fork();
task2.fork();
// 合并
result = task1.join()+task2.join();
}
return result;
}
}
2.异步回调
1. 原理
- 有多个任务同时访问,线程但是同一时间只能处理一个任务,那其他任务就先离开,等到线程忙完了,主动回调来找它的任务
- 同步、异步、异步回调
2. 使用
- CompletableFuture.runAsync() 【没有返回值】
public static void main(String[] args) throws Exception {
// 需要传入一个 Runnable 接口类型的参数
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
System.out.println(Thread.currentThread().getName() + "执行任务--runAsync--没有返回");
});
completableFuture.get();
}
- CompletableFuture.supplyAsync() 【有返回值】
-
whenComplete
这里的参数类型是 BiConsumer =》 Binary Consumer ,也就是需要两个参数,且没有返回值 -
exceptionally
该项表示:如果执行任务出现异常,则执行 exceptionally 中的代码块,并且需要一个返回值
这里的参数是一个 Function 类型的函数式接口 -
代码示例
-
public static void main(String[] args) throws Exception {
// supplyAsync 有返回
// 需要传入一个 Supplier 类型的参数,Supplier类型可以没有输入参数
CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "执行任务--supplyAsync--有返回");
// 模拟异常
int a = 10 / 0;
return 1024;
});
// whenComplete : 参数列表 (T t, U u),如果执行过程正常完成,则执行该分支
// exceptionally : , 如果执行过程出现异常,则走该分支
completableFuture2.whenComplete((t,u) -> {
System.out.println("-----t(异步回调,输出结果):"+t);
System.out.println("-----u(执行过程中的异常信息):"+u);
}).exceptionally((f) -> {
// 打印异常信息
System.out.println("+++++++Exception: "+f.getMessage());
return 9999;
}).get();
// 这里的 .get() 方法,获取任务的执行结果
// 如果在正常执行的情况下,则得到任务的返回值 —— 1024
// 如果出现异常,则返回 exceptionally() 中异常处理时设置的返回值 —— 9999
// 可以把用 System.out.print 打印验证
}
正常执行
出现异常