前言
在当前的系统中,我们可能会在一个事务中,执行多项操作,调用多个外部服务,查询数据或者更新数据,进行一系列逻辑处理之后返回给客户一个结果。
例如,以下是一个顾客下单的流程模拟:
1、获取基本产品信息(此处查询数据库)
2、获取每一个产品的价格(假设此处需要通过第三方服务平台进行实时定价,产品不同调用的平台亦不同,所有此处是挨个获取)
3、计算产品总价
4、获取用户余额(此处也是调取第三方服务,获取用户账户余额)
5、比对余额是否充足
6、如果余额充足则提示购买成功,并扣去花费,更新用户余额(此处也是调取第三方服务,更新用户账户余额)
7、返回是否购买成功
这七个步骤,如果顺序执行,那么耗时甚多。
仔细观察,我们可以发现,步骤1和步骤4是上下文无关的可以并发执行;步骤2获取各个产品的价格也是互不相关的,可以并发执行;之后步骤3、5、6、7则只能顺序执行。
Java提供了这样的并发查询,异步获取结果的工具,那就是Future和Callable。
Callable 是一个函数式接口:
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
Future则是一个未来才会有结果的结果。采用future.get()方法会阻塞线程直到结果返回。
为了方便使用,我封装了一个简单的工具类:
package cn.hengyumo.dawn.utils;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
/**
* 并发工具类
*
* @author hengyumo
* @since 2021-07-13
*
*/
public class ConcurrentUtil {
/**
* 执行任务
*
* @param executorService ExecutorService
* @param callable 回调
* @param <T> 返回的结果集Future泛型
* @return Future泛型
*/
public static <T> Future<T> doJob(ExecutorService executorService, Callable<T> callable) {
return executorService.submit(callable);
}
/**
* 获取结果集,执行时会阻塞直到有结果,中间的异常不会被静默
*
* @param future Future
* @param <T> 返回的结果集泛型
* @return T
*/
public static <T> T futureGet(Future<T> future) {
try {
return future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
throw