dubbo异步多线程调用
public List<LotteryCategoryVo> selectChildrenAll(List<String> pids) {
long start = System.currentTimeMillis();
log.info("selectChildrenAll start:{}",start);
List<Category> categories = null;
AbstractAsyncBatchInvokeUtils<List<Category>, String> abstractAsyncBatchInvokeUtils = new AbstractAsyncBatchInvokeUtils<List<Category>, String>() {
@Override
public void invoke(String pid) {
categoryService.selectChildren(Long.valueOf(pid));
}
};
try {
Iterable<List<String>> partition = Iterables.partition(pids, 10);
for (List<String> e : partition) {
List<List<Category>> list = abstractAsyncBatchInvokeUtils.asyncBatchInvoke(e, 100, 1);
for (List<Category> categoryList : list) {
categories.addAll(categoryList);
}
}
} catch (Exception e) {
log.error("导出查询会员信息失败,错误信息为:{}", e.getMessage(), e);
throw new GenericBusinessException("导出查询会员信息失败");
}
List<LotteryCategoryVo> result = convertCategoryVo(categories);
log.info("selectChildrenAll end:{} end-start:{} ms",System.currentTimeMillis(),System.currentTimeMillis()-start);
return result;
}
/**
* dubbo批量异步接口,调用者实现invoke方法,限制50条,超长的调用者自行分页
*
* todo 该方法存在优化点:需要依赖dubbo配置文件async=true ,如果能在RpcContext中修改RpcInvocation参数为异步可以在这里自定义参数将会摆脱配置文件的依赖
* @author:zxd
* @date: 9/3/21
* @time: 4:26 PM
*/
@Slf4j
public abstract class AbstractAsyncBatchInvokeUtils<T, V> {
/**
* 策略:某异步线程异常,方法停止,向上抛出
*/
public static final int UN_CATCH_EXCEPTION_HANDLER_STRATEGY = 0;
/**
* 策略:吞掉某异步线程异常
*/
public static final int CATCH_EXCEPTION_HANDLER_STRATEGY = 1;
/**
* 入参params的长度限制,批量执行,
*/
public static final int PARAM_SIZE_LIMIT = 50;
/**
* 基于dubbo消费者线程池异步消费方法的批量执行器,方法内是异步,对外返回的结果是同步的
* 注意:dubbo方法的配置文件需要async=true
* @param params params 参数集合
* @param singleWaitTime 单线程等待时间,单位毫秒,为0则表示使用dubbo.xml设置的方法调用时间
* @param handlerStrategyStatus 异常处理策略 NO_CATCH_EXCEPTION_HANDLER_STRATEGY 或者 CATCH_EXCEPTION_HANDLER_STRATEGY
* @return List<T> 直接返回结果
*/
public List<T> asyncBatchInvoke(Collection<V> params, long singleWaitTime, int handlerStrategyStatus)
throws InterruptedException, ExecutionException, TimeoutException {
if (CollectionUtils.isEmpty(params) || params.size() > PARAM_SIZE_LIMIT) {
throw new BadParameterException("参数异常");
}
List<Future<T>> futureList = batchInvoke(params);
List<T> list = Lists.newArrayList();
for (Future<T> future : futureList) {
// 某线程异常直接吞掉
if (handlerStrategyStatus == CATCH_EXCEPTION_HANDLER_STRATEGY) {
T t = null;
Object[] arguments = null;
try {
FutureAdapter future1 = (FutureAdapter) future;
DefaultFuture defaultFuture = (DefaultFuture)future1.getFuture();
Request request = defaultFuture.getRequest();
RpcInvocation data = (RpcInvocation)request.getData();
arguments = data.getArguments();
if (singleWaitTime <= 0L){
t = future.get();
}else {
t = future.get(singleWaitTime, TimeUnit.MILLISECONDS);
}
} catch (Exception e) {
if (log.isInfoEnabled()) {
log.info("AbstractAsyncBatchInvokeUtils.asyncBatchInvoke 批量方法执行报错," +
"失败线程参数arguments={},singleWaitTime={},handlerStrategyStatus={}",
JSON.toJSONString(arguments), singleWaitTime, handlerStrategyStatus, e);
}
Thread.currentThread().interrupt();
}
if (t != null) {
list.add(t);
}
} else if (handlerStrategyStatus == UN_CATCH_EXCEPTION_HANDLER_STRATEGY) {
// 不吞掉异常
T t = future.get(singleWaitTime, TimeUnit.MILLISECONDS);
if (t != null) {
list.add(t);
}
}
}
log.info("AbstractAsyncBatchInvokeUtils.asyncBatchInvoke 结果返回result={}", JSON.toJSONString(list));
return list;
}
/**
* 具体执行的方法,调用者实现该方法的具体业务逻辑
*
* @param v 参数
*/
public abstract void invoke(V v);
/**
* 基于dubbo消费者线程池异步消费方法的批量执行器,返回future类型结果,为异步的方法,调用者自行从future中拿结果
*
* @param params params 参数集合
* @return List<Future<T>> 返回future的集合结果
*/
public List<Future<T>> asyncBatchInvoke(Collection<V> params) {
if (CollectionUtils.isEmpty(params) || params.size() > PARAM_SIZE_LIMIT) {
throw new BadParameterException("参数异常");
}
List<Future<T>> futureList = batchInvoke(params);
return futureList;
}
/**
* 批量批异步执行目标方法
* @param params
* @return 返回 future,使用者可以根据实际逻辑,先做其他事情再获取future中的结果,做到真正的异步
* @throws Exception
*/
private List<Future<T>> batchInvoke(Collection<V> params) {
List<Future<T>> futureList = Lists.newArrayList();
for (V param : params) {
invoke(param);
Future<T> future = RpcContext.getContext().getFuture();
futureList.add(future);
}
return futureList;
}
}
@Configuration
@EnableAsync
@SuppressWarnings("all")
public class ThreadPoolConfiguration {
@Bean("lotteryCategoryTaskExecutor")
public ThreadPoolTaskExecutor lotteryCategoryTaskExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(10);
threadPoolTaskExecutor.setMaxPoolSize(20);
threadPoolTaskExecutor.setKeepAliveSeconds(200);
threadPoolTaskExecutor.setQueueCapacity(100);
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
return threadPoolTaskExecutor;
}
}
同步多线程调用:
@Override
public List<LotteryCategoryVo> selectChildrenAll(List<String> pids) {
List<LotteryCategoryVo> result = new ArrayList<>();
List<Future<List<LotteryCategoryVo>>> futureList = new ArrayList<>();
for (String pid : pids) {
Future<List<LotteryCategoryVo>> future = selectChildrenAllTaskExecutor.submit(CallableWrapper.of(() -> this.selectChildren(pid)));
futureList.add(future);
}
futureList.stream().forEach((task) -> {
try {
List<LotteryCategoryVo> lotteryCategoryVos = task.get();
result.addAll(lotteryCategoryVos);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
});
return result;
}
@Bean("selectChildrenAllTaskExecutor")
public ThreadPoolTaskExecutor selectChildrenAllTaskExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(10);
threadPoolTaskExecutor.setKeepAliveSeconds(200);
threadPoolTaskExecutor.setMaxPoolSize(20);
threadPoolTaskExecutor.setQueueCapacity(500);
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
return threadPoolTaskExecutor;
}
public LotteryCategoryQueryVo getCategory(String activityCode) {
log.info("查询分类耗时:t1:{}", System.currentTimeMillis());
LotteryCategoryRes lotteryCategoryRes = lotteryActivityService.queryCategory(activityCode);
if (ObjectUtils.isEmpty(lotteryCategoryRes)) {
return LotteryCategoryQueryVo.builder().isSelect(false).build();
}
List<String> levelOneSelect = lotteryCategoryRes.getLotteryCategory().getLevelOne();
List<String> levelTwoSelect = lotteryCategoryRes.getLotteryCategory().getLevelTwo();
List<String> levelThreeSelect = lotteryCategoryRes.getLotteryCategory().getLevelThree();
List<String> levelFourSelect = lotteryCategoryRes.getLotteryCategory().getLevelFour();
log.info("查询分类耗时:t3:{}", System.currentTimeMillis());
Future<List<LotteryCategoryVo>> levelFourFuture = lotteryCategoryTaskExecutor.submit(CallableWrapper.of(() -> selectChildrenAll(levelThreeSelect)));
Future<List<LotteryCategoryVo>> levelThreeFuture = lotteryCategoryTaskExecutor.submit(CallableWrapper.of(() -> selectChildrenAll(levelTwoSelect)));
Future<List<LotteryCategoryVo>> levelTwoFuture = lotteryCategoryTaskExecutor.submit(CallableWrapper.of(() -> selectChildrenAll(levelOneSelect)));
Future<List<LotteryCategoryVo>> levelOneFuture = lotteryCategoryTaskExecutor.submit(CallableWrapper.of(() -> selectByLevel(1)));
Future<Long> skuCountFuture = lotteryCategoryTaskExecutor.submit(CallableWrapper.of(() -> selectSkuCount(LotteryCategoryRequest
.builder()
.categoryIds(levelFourSelect)
.page(0)
.size(0)
.build())));
Long skuCount = null;
List<LotteryCategoryVo> levelOne = null;
List<LotteryCategoryVo> levelTwo = null;
List<LotteryCategoryVo> levelThree = null;
List<LotteryCategoryVo> levelFour = null;
try {
skuCount = skuCountFuture.get();
levelOne = levelOneFuture.get();
levelTwo = levelTwoFuture.get();
levelThree = levelThreeFuture.get();
levelFour = levelFourFuture.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
log.info("查询分类耗时:t2:{}", System.currentTimeMillis());
return LotteryCategoryQueryVo.builder()
.id(lotteryCategoryRes.getId())
.isSelect(true)
.levelOne(levelOne)
.levelTwo(levelTwo)
.levelThree(levelThree)
.levelFour(levelFour)
.levelOneSelect(levelOneSelect)
.levelTwoSelect(levelTwoSelect)
.levelThreeSelect(levelThreeSelect)
.levelFourSelect(levelFourSelect)
.count(skuCount)
.build();
}
public LotteryCategoryQueryVo getCategory(String activityCode) {
log.info("查询分类耗时:t1:{}", System.currentTimeMillis());
LotteryCategoryRes lotteryCategoryRes = lotteryActivityService.queryCategory(activityCode);
if (ObjectUtils.isEmpty(lotteryCategoryRes)) {
return LotteryCategoryQueryVo.builder().isSelect(false).build();
}
List<String> levelOneSelect = lotteryCategoryRes.getLotteryCategory().getLevelOne();
List<String> levelTwoSelect = lotteryCategoryRes.getLotteryCategory().getLevelTwo();
List<String> levelThreeSelect = lotteryCategoryRes.getLotteryCategory().getLevelThree();
List<String> levelFourSelect = lotteryCategoryRes.getLotteryCategory().getLevelFour();
log.info("查询分类耗时:t3:{}", System.currentTimeMillis());
Future<List<LotteryCategoryVo>> levelFourFuture = lotteryCategoryTaskExecutor.submit(CallableWrapper.of(() -> selectChildrenAll(levelThreeSelect)));
Future<List<LotteryCategoryVo>> levelThreeFuture = lotteryCategoryTaskExecutor.submit(CallableWrapper.of(() -> selectChildrenAll(levelTwoSelect)));
Future<List<LotteryCategoryVo>> levelTwoFuture = lotteryCategoryTaskExecutor.submit(CallableWrapper.of(() -> selectChildrenAll(levelOneSelect)));
Future<List<LotteryCategoryVo>> levelOneFuture = lotteryCategoryTaskExecutor.submit(CallableWrapper.of(() -> selectByLevel(1)));
Future<Long> skuCountFuture = lotteryCategoryTaskExecutor.submit(CallableWrapper.of(() -> selectSkuCount(LotteryCategoryRequest
.builder()
.categoryIds(levelFourSelect)
.page(0)
.size(0)
.build())));
Long skuCount = null;
List<LotteryCategoryVo> levelOne = null;
List<LotteryCategoryVo> levelTwo = null;
List<LotteryCategoryVo> levelThree = null;
List<LotteryCategoryVo> levelFour = null;
try {
skuCount = skuCountFuture.get();
levelOne = levelOneFuture.get();
levelTwo = levelTwoFuture.get();
levelThree = levelThreeFuture.get();
levelFour = levelFourFuture.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
log.info("查询分类耗时:t2:{}", System.currentTimeMillis());
return LotteryCategoryQueryVo.builder()
.id(lotteryCategoryRes.getId())
.isSelect(true)
.levelOne(levelOne)
.levelTwo(levelTwo)
.levelThree(levelThree)
.levelFour(levelFour)
.levelOneSelect(levelOneSelect)
.levelTwoSelect(levelTwoSelect)
.levelThreeSelect(levelThreeSelect)
.levelFourSelect(levelFourSelect)
.count(skuCount)
.build();
}
@Bean("lotteryCategoryTaskExecutor")
public ThreadPoolTaskExecutor lotteryCategoryTaskExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(10);
threadPoolTaskExecutor.setMaxPoolSize(20);
threadPoolTaskExecutor.setKeepAliveSeconds(200);
threadPoolTaskExecutor.setQueueCapacity(100);
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
return threadPoolTaskExecutor;
}
CountDownLatch写法多线程调用:
public List<EnvelopeRainShopVO> checkShops(List<String> shopIds,String activityCode) {
log.info("校验门店入参,活动代码为:{},门店为:{}",activityCode,shopIds);
List<MissionMappingDO> byShopId = missionMappingDataMapperEx.findByShopId(shopIds, MissionBizTypeEnum.ENVELOPE_RAIN.getBizId());
List<EnvelopeRainShopVO> res = Collections.synchronizedList(new ArrayList<>());
String circuitBreakConfig = null;
try {
circuitBreakConfig = ConfigManager.getInstance().getConfig("ACTIVITY", "rain-check-shop-break-config");
} catch (Exception e) {
log.error(e.getMessage());
}
// 降级开关
if (Objects.equals("1", circuitBreakConfig)) {
log.info("checkShops直接通过校验");
return res;
}
if(CollectionUtils.isEmpty(byShopId)){
return res;
}
//很多门店在同一个活动下
AtomicBoolean flag = new AtomicBoolean(false);
Map<String,ActivityInfo> activityInfoMap = new ConcurrentHashMap<>();
CountDownLatch cdl = new CountDownLatch(byShopId.size());
for (MissionMappingDO mission : byShopId) {
redRainCheckShopTaskExecutor.submit(()->{
try {
ActivityInfo activityInfo = activityInfoMap.get(mission.getRefId());
if (Objects.isNull(activityInfo)) {
activityInfo = activityCoreService.getActivityInfo(mission.getRefId());
if(Objects.isNull(activityInfo)){
return;
}
activityInfoMap.put(mission.getRefId(), activityInfo);
}
if (activityInfo.getActivityCode().equals(activityCode)) {
return;
}
Shop shopById = shopService.getAnyShopById(mission.getShopRef());
if(Objects.isNull(shopById)){
throw new GenericBusinessException(mission.getShopRef()+"门店不存在");
}
if (activityInfo.getStatus() == ActivityStatus.NOT_ENABLED
|| activityInfo.getStatus() == ActivityStatus.NOT_START
|| activityInfo.getStatus() == ActivityStatus.AVAILABLE
|| activityInfo.getStatus() == ActivityStatus.AUDITING) {
res.add(EnvelopeRainShopVO.builder()
.shopId(mission.getShopRef())
.shopName(shopById.getShopName())
.activityCode(mission.getRefId())
.build());
}
} catch (Exception e) {
flag.set(true);
log.error("RainMissionRuleServiceImpl.checkShops error",e);
} finally {
cdl.countDown();
}
});
}
try {
cdl.await();
} catch (InterruptedException e) {
log.error("RainMissionRuleServiceImpl.checkShops error",e);
}
if (flag.get()){
throw new GenericBusinessException("门店校验错误");
}
Map<String,EnvelopeRainShopVO> map =new HashMap<>();
res.stream().forEach(n->{
if(!map.containsKey(n.getActivityCode())){
map.put(n.getActivityCode(),n);
}else {
map.get(n.getActivityCode()).setShopName(map.get(n.getActivityCode()).getShopName()+","+n.getShopName());
map.get(n.getActivityCode()).setShopId(map.get(n.getActivityCode()).getShopId()+","+n.getShopId());
}
});
Set<String> keys = map.keySet();
List<EnvelopeRainShopVO> res1 = new ArrayList<>();
for(String key : keys){
res1.add(map.get(key));
}
log.info("校验门店出参,已有活动的门店为:{}",res1);
return res1;
}
@Bean
public ThreadPoolTaskExecutor redRainCheckShopTaskExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(10);
threadPoolTaskExecutor.setKeepAliveSeconds(200);
threadPoolTaskExecutor.setMaxPoolSize(10);
threadPoolTaskExecutor.setQueueCapacity(500);
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
return threadPoolTaskExecutor;
}
283

被折叠的 条评论
为什么被折叠?



