业务场景
保存/复制某棵树,还需要保存树的分支节点以及分支上的叶子特征
业务分析
保存树节点到A表,遍历得到树分支节点,查询对应叶子信息,批量保存到B表。如果查询某个叶子节点失败则提示保存树失败。因为保存的树就不是之前树的结构和样子了(业务需要保存一模一样整棵树)。
业务探讨
如果串行执行,那就是每个节点查询以及保存的时间总和。于是引入多线程,但异步执行不获取返回值的话,时间是主线程的时间,但也得不到子线程的状态,捕获不到子线程的异常在主线程处理。所以引入Callable,带返回值的线程,返回值有两种Future和FutureTask,使用泛型能很好的兼容业务,根据不同场景定义不同返回值。
更重要的是,在子线程业务处理时,如果出现异常返回null或者false了,可以根据泛型定义不同类型,在最后循环处理线程执行结果。达到主线程子线程的一致性。
private final static ExecutorService THREAD_EXECUTOR = Executors.newFixedThreadPool(16);
public int getSum(int n) throws ExecutionException, InterruptedException {
int sum = 0;
List<Future<Integer>> list = new ArrayList<Future<Integer>>();
for (int i = 0; i < n; i++) {
Future<Integer> future = executeThread(i);
sum += future.get();
}
return sum;
}
private Future<Integer> executeThread(final int i) {
Future<Integer> future = THREAD_EXECUTOR.submit(new Callable<Integer>() {
public Integer call() throws Exception {
Thread.sleep(5000);
return i;
}
});
return future;
}
虽然写了多线程,但边执行边get返回值,实际相当于程序是同步执行,并没有达到异步线程的目的,所以改造后代码,只有改造线程调用的方法,如下:
public int getSum(int n) throws ExecutionException, InterruptedException {
int sum = 0;
List<Future<Integer>> list = new ArrayList<Future<Integer>>();
for (int i = 0; i < n; i++) {
Future<Integer> future = executeThread(i);
list.add(future);
}
for (Future<Integer> future : list) {
if (null != future.get()) {
sum += future.get();
}
}
return sum;
}