不同多线程场景下CompletionService 和 CompletableFuture 的使用

一、CompletionService 原理

内部通过阻塞队列+FutureTask,实现了任务先完成可优先获取到,即结果按照完成先后顺序排序,内部有一个先进先出的阻塞队列,用于保存已经执行完成的Future,通过调用它的take方法或poll方法可以获取到一个已经执行完成的Future,进而通过调用Future接口实现类的get方法获取最终的结果

  1. 并行地调用多个服务实例,只要有一个成功就返回结果
    场景:判断用户是否有购买过权益卡(共9种类型权益卡)。只要购买过其中一种就算购买。
	@Autowired
    @Qualifier(ThreadPoolConfig.CBS_IO_EXECUTOR)
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
	public ResultMessage<Boolean> haveSucessRightOrder(String custNo) {
         // 创建CompletionService
        CompletionService<Integer> cs = new ExecutorCompletionService<>(threadPoolTaskExecutor);
        // 用于保存Future对象,共9个查询任务
        List<Future<Integer>> futures = new ArrayList<>(9);
        //提交异步任务,并保存future到futures
        futures.add(cs.submit(() -> {
            List<CardOrderV0> cardOrderV0s = advServiceClient.pageEnjoycard(custNo, com.smy.ibs.enums.OrderStatus.pay_suc.getCode());
            return Optional.ofNullable(cardOrderV0s).map(k -> k.size()).orElse(0);
        }));
        
        futures.add(cs.submit(() -> {
            List<TEnjoymentCardOrder> tEnjoymentCardOrders = advServiceClient.queryEnjoymentCards(custNo);
            return Optional.ofNullable(tEnjoymentCardOrders).map(k -> k.size()).orElse(0);
        }));
        
        futures.add(cs.submit(() -> {
            List<IbsInsuranceBorrowerOrder> orders = advServiceClient.getInsuranceOrdersByParam(custNo, 3);
            return Optional.ofNullable(orders).map(k -> k.size()).orElse(0);
        }));
        
        futures.add(cs.submit(() -> {
            List<TSaveMoneyCardOrder> saveMoneyCardOrders = cbsSaveMoneyCardService.getOrders(SaveMoneyCardOrderOmsReq.builder().custNo(custNo).orderStatus(OrderStatus.PAY.getCode()).start(0).length(1).build());
            return Optional.ofNullable(saveMoneyCardOrders).map(k -> k.size()).orElse(0);
        }));
        
        futures.add(cs.submit(() -> {
            List<VipPayOrderOmsResp> xshkOrders = cbsVipUserXshkService.getPayOrderRecs(VipPayOrderOmsReq.builder().custNo(custNo).orderStatus(OrderStatus.PAY.getCode()).start(0).length(1).build());
            return Optional.ofNullable(xshkOrders).map(k -> k.size()).orElse(0);
        }));
        
        futures.add(cs.submit(() -> {
            VipOwnOrderRequst requst = new VipOwnOrderRequst();
            requst.setOrderStatus(OrderStatus.PAY.getCode());
            requst.setCustNo(custNo);
            ResultMessage<List<VipOwnOrderResponse>> myOrders = cbsVipUserOwnService.getMyOrders(requst);
            if (!myOrders.getResult()) {
                return 0;
            }
            return Optional.ofNullable(myOrders.getData()).map(k -> k.size()).orElse(0);
        }));
        
        futures.add(cs.submit(() -> {
            GetMoneyCardOrderOmsReq req = new GetMoneyCardOrderOmsReq();
            req.setCustNo(custNo);
            req.setOrderStatus(OrderStatus.PAY.getCode());
            List<GetMoneyCardOrderOmsResp> resps = cbsGetMoneyCardService.queryGetMoneyCardOrders(req);
            return Optional.ofNullable(resps).map(k -> k.size()).orElse(0);
        }));
        
        futures.add(cs.submit(() -> {
            List<TQuickenCardOrder> cardOrderRecs = cbsQuickenCardService.getCardOrderRecs(OmsCardOrderReq.builder().custNo(custNo).orderStatus(OrderStatus.PAY.getCode()).start(0).length(1).build());
            return Optional.ofNullable(cardOrderRecs).map(k -> k.size()).orElse(0);
        }));
        
        futures.add(cs.submit(() -> {
            CardOrderDto cardOrderDto = new CardOrderDto();
            cardOrderDto.setCustNo(custNo);
            cardOrderDto.setOrderStatus(OrderStatus.PAY.getCode());
            ResultMessage<List<CardOrderExtend>> resultMessage = cbsCardService.queryCardOrders(cardOrderDto);
            if (!resultMessage.getResult()) {
                return 0;
            }
            return Optional.ofNullable(resultMessage.getData()).map(k -> k.size()).orElse(0);
        }));
        // 获取最快返回的任务执行结果
        Integer r = 0;
        try {
            // 只要有一个成功返回,则break
            for (int i = 0; i < 9; ++i) {
                try {
                    r = cs.take().get();
                }  catch (Exception e) {
                    log.error("客户号在执行任务出现异常custNo:{},异常e:{}", custNo,  e);
                }
                //通过判空和查询结果是否大于0来检查是否成功返回
                if (r != null && r > 0) {
                    break;
                }
                
            }
        } finally {
            //取消所有任务
            for (Future<Integer> f : futures)
                f.cancel(true);
        }
        return ResultMessage.success(r > 0);
    }

二、CompletableFuture

CompletableFuture是Future接口的扩展和增强。CompletableFuture实现了Future接口,并在此基础上进行了丰富地扩展,完美地弥补了Future上述的种种问题。更为重要的是,CompletableFuture实现了对任务的编排能力

  1. 并行地调用多个服务实例,并获取到所有处理结果
//获取短链后缀
Map<String, String> shorLinkMap = new HashMap<>();
Lists.partition(linkList, groupSize).stream()
        .map(k -> CompletableFuture.supplyAsync(() -> this.getLinkMap(k), threadPoolTaskExecutor))
        .map(CompletableFuture::join).filter(MapUtils::isNotEmpty).forEach(k -> shorLinkMap.putAll(k));

注意:这里不管是CompletionService 还是 CompletableFuture,我们都没有使用系统默认的线程池,而是用的自己定义好并Autowired注入的线程池。
原因是:

  • 如果所有 CompletableFuture 共享一个线程池,那么一旦有任务执行一些很慢的 I/O 操作,就会导致线程池中所有线程都阻塞在 I/O 操作上,从而造成线程饥饿,进而影响整个系统的性能
  • 自定义线程池中,可以设置线程名,可以根据名字区分不同的业务场景,做到场景隔离。

所以,强烈建议你要根据不同的业务类型创建不同的线程池,以避免互相干扰。下一章我们来讲解下线程池~

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的多线程编程是一个重要的概念,它可以充分利用计算机的多个核心以提高程序的性能。在Java中,你可以使用Thread或Runnable来实现基本的线程编程。而CompletableFuture则是Java 8引入的一个强大的工具,它提供了异步编程的能力,可以更方便地处理异步任务。 下面是一个使用CompletableFuture和runAsync方法结合的例子: ```java import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; public class Main { public static void main(String[] args) { // 创建一个CompletableFuture对象 CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { // 这里是你要异步执行的任务 try { // 模拟一个耗时操作 Thread.sleep(3000); System.out.println("任务执行完成"); } catch (InterruptedException e) { e.printStackTrace(); } }); // 在主线程做一些其他的工作 try { Thread.sleep(100); // 主线程休眠一下 } catch (InterruptedException e) { e.printStackTrace(); } // 等待异步任务完成,返回结果(在这个例子中为null) try { future.get(); // 注意这会阻塞,除非有并发修改,否则在正常应用场景中应避免使用 } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } } ``` 在这个例子中,我们创建了一个CompletableFuture对象,并使用`runAsync`方法来启动一个新的线程来执行一个任务。这个任务只是一个简单的模拟耗时操作(这里使用了`Thread.sleep`)。在主线程中,我们等待异步任务完成,并获取其结果。注意,这个例子中的`future.get()`会阻塞主线程,除非有并发修改,否则在正常应用场景中应避免使用。在实际应用中,你可能需要使用更复杂的方式来处理异步任务的结果。 CompletableFuture还提供了许多其他的方法,如`thenApply`、`thenAccept`、`thenCompose`等,可以更方便地处理异步任务的结果和异常。你可以根据需要选择合适的方法来处理你的异步任务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值