高并发异步编程

本文介绍了一种基于CompletableFuture的异步支付方法及多线程优化方案,包括阻塞队列形式的实现与优化,提高了系统的并发处理能力。
一、CompletableFuture
private static boolean asyncPay() {
        CompletableFuture<Boolean> isVaild = CompletableFuture.supplyAsync(() -> CheckService.isVaild());
        CompletableFuture<Integer> orderSum = CompletableFuture.supplyAsync(() -> OrderService.create());
        CompletableFuture<Integer> money = CompletableFuture.supplyAsync(() -> basePay());
        CompletableFuture.allOf(isVaild, orderSum, money)
                .thenRun(() -> {
                    System.out.println("完成异步支付");
                }).join();
        try {
            System.out.println("完成异步支付all" + isVaild.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return true;
    }

二、多线程

public Object getUserInfoConcurrent(Long userId) {
        long start = System.currentTimeMillis();
        // 用户信息
        Callable userInfoCall = new Callable() {
            @Override
            public Object call() throws Exception {
                return remoteService.getUserInfo(userId);
            }
        };
        FutureTask<String> userFutureTask = new FutureTask<String>(userInfoCall);
        new Thread(userFutureTask).start();


        // 钱包余额信息
        Callable walletCall = new Callable() {
            @Override
            public Object call() throws Exception {
                return remoteService.getUserWallet(userId);
            }
        };
        FutureTask<String> walletFutureTask = new FutureTask<String>(walletCall);
        new Thread(walletFutureTask).start();

        Map result = null;
        try {
            result = new HashMap(2);
            result.put("userInfo", userFutureTask.get());
            result.put("userWallet", walletFutureTask.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("cost time=" + (System.currentTimeMillis() - start));
        return result;
    }

Servlet版

三、阻塞队列形式

*** 该方案建议读操作,不要用于写操作

// 请求实例
@GetMapping("/getInfo4")
    public Object getUserOrderInfo4(@RequestParam("userId") Long userId) throws Exception {
        // return userService.getUserInfo(userId);
        long start = System.currentTimeMillis();
        Map<String, Object> stringObjectMap = userService.queryOrderBatch(String.valueOf(userId));
        System.out.println("getUserInfo4:cost time=" + (System.currentTimeMillis() - start));
        return stringObjectMap;
    }

// 请求放入队列
public Map<String, Object> queryOrderBatch(String orderCode) {
        if (queue.size() > 2000) {
            System.out.println("超出限制。。。。。。。。");
            return new HashMap<>();
        }
        String uniqueSerialNo = UUID.randomUUID().toString();
        CompletableFuture<Map<String, Object>> future = new CompletableFuture<>();
        Request request = new Request();
        request.uniqueSerialNo = uniqueSerialNo;
        request.orderFuture = future;
        request.orderCode = orderCode;
        queue.add(request);
        try {
            return future.get(3,TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
        return new HashMap<>();
    }
static class Request {
        String uniqueSerialNo;
        String orderCode;
        CompletableFuture<Map<String, Object>> orderFuture;
    }

    /**
     * <p>队列(阻塞队列)</p>
     */
    LinkedBlockingDeque<Request> queue = new LinkedBlockingDeque<>();
// 定时任务处理
 @PostConstruct
    public void initScheduledPool() throws InterruptedException {
        System.out.println("initScheduledPool->初始化线程池子");
        ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(7);
        threadPool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                int size = queue.size();
                // System.out.println("批量请求1size=" + size);
                if (size < 1) {
                    return;
                }
                // 根据接口来封装批量参数
                List<Map<String, Object>> params = new ArrayList<>(size);
                ArrayList<Request> requests = new ArrayList<>(size);
                for (int i = 0; i < size; i++) {
                    Request request = queue.poll();
                    HashMap<String, Object> paramMap = new HashMap<>();
                    paramMap.put("uniqueSerialNo", request.uniqueSerialNo);
                    paramMap.put("orderCode", request.orderCode);
                    params.add(paramMap);
                    requests.add(request);
                }
                System.out.println(Thread.currentThread().getName() + "->批量请求size=" + size);
                List<Map<String, Object>> responses = null;
                try {
                    responses = remoteService.getOrderInfoByOrderCodeBatch(params);
                } catch (Exception e) {
                    e.printStackTrace();
                    // 处理异常
                    for (Request request : requests) {
                        // request.orderFuture.complete(null);
                        request.orderFuture.completeExceptionally(e);
                    }
                }
                if (CollectionUtils.isEmpty(responses)) {
                    return;
                }
                for (Request request : requests) {
                    for (Map<String, Object> res : responses) {
                        if (request.uniqueSerialNo.equals(String.valueOf(res.get("uniqueSerialNo")))) {
                            request.orderFuture.complete(res);
                            break;
                        }
                    }
                }

            }
        }, 100, 10, TimeUnit.MILLISECONDS);
    }

四、阻塞队列形式优化版

/**
 * <p>Note:
 * 1、接收请求
 * 2、将请求封装成TransferContext
 * 3、将TransferContext添加到阻塞队列transferContextQueue
 * 4、利用任务线程池,执行ScheduledTask任务消费阻塞队列的TransferContext,
 * 5、ScheduledTask处理调用接口并封装返回结果
 * 6、填充completeFuture中的返回结果
 * *** 该方案建议读操作,不要用于写操作
 * @author xiaocuizi
 * @since 1.0.0 2022/3/27 下午10:00
 */
public final class TransferStation {
    /**
     * <p>阻塞队列最大容量</p>
     */
    private final int capacity;

    public TransferStation() {
        this(2000);
    }

    public TransferStation(int capacity) {
        if (capacity <= 0) {
            throw new IllegalArgumentException();
        }
        this.capacity = capacity;
        this.transferContextQueue = new LinkedBlockingQueue<>(this.capacity);
    }

    /**
     * <p>队列(阻塞队列)</p>
     */
    private final BlockingQueue<TransferContext> transferContextQueue;

    public BlockingQueue<TransferContext> getTransferContextQueue() {
        return transferContextQueue;
    }

    /**
     * -------------------------------------------------------------------------------------------------------------------------------------------
     */
    public static class ScheduledTask<T, R> implements Runnable {

        private final TransferService<T, R> service;
        private final BlockingQueue<TransferContext> transferContextQueue;


        public ScheduledTask(BlockingQueue<TransferContext> transferContextQueue, TransferService service) {
            this.transferContextQueue = transferContextQueue;
            this.service = service;
        }

        @Override
        public void run() {
            int size = transferContextQueue.size();
            if (size < 1) {
                return;
            }
            // 根据接口来封装批量参数
            List<TransferContext> transferContexts = new ArrayList<>(size);
            for (int i = 0; i < size; i++) {
                // 从队列中获取请求
                TransferContext transferContext = transferContextQueue.poll();
                if (transferContext == null) {
                    continue;
                }
                transferContexts.add(transferContext);
            }
            if (CollectionUtils.isEmpty(transferContexts)) {
                return;
            }
            // todo 日志修改
            // System.out.println(Thread.currentThread().getName() + "->批量请求size=" + size);
            List<TransferContext> responseContextList = null;
            try {
                responseContextList = service.invokeRemote(transferContexts);
            } catch (Exception e) {
                // todo 日志打印
                e.printStackTrace();
                transferContexts.forEach(req -> req.comFuture.completeExceptionally(e));
            }
            if (CollectionUtils.isEmpty(responseContextList)) {
                return;
            }

            // 单条数据
            if (transferContexts.size() == 1 && responseContextList.size() == 1) {
                if (transferContexts.get(0).uniqueSerialNo.equals(responseContextList.get(0).uniqueSerialNo)) {
                    transferContexts.get(0).comFuture.complete(responseContextList.get(0).getData());
                } else {
                    transferContexts.get(0).comFuture.complete(null);
                }
                return;
            }
            // 多条数据
            // uniqueSerialNo ->TransferContext
            Map<String, TransferContext> responseContextMap = responseContextList.stream()
                    .collect(Collectors.toMap(TransferContext::getUniqueSerialNo, Function.identity()));
            // 根据uniqueSerialNo进行匹配返回响应结果
            for (TransferContext transferContext : transferContexts) {
                TransferContext resp = responseContextMap.get(transferContext.uniqueSerialNo);
                if (resp != null) {
                    // 填充返回结果
                    transferContext.comFuture.complete(resp.data);
                }
            }

        }

    }


    public static class TransferContext<T, R> {

        /**
         * <p>请求唯一序列号</p>
         */
        private String uniqueSerialNo;
        /**
         * <p>请求参数
         */
        private T param;

        /**
         * <p>返回结果
         */
        private Object data;


        /**
         * <p>CompletableFuture
         */
        private CompletableFuture<R> comFuture;

        public TransferContext(String uniqueSerialNo, T param, CompletableFuture<R> comFuture) {
            this.uniqueSerialNo = uniqueSerialNo;
            this.param = param;
            this.comFuture = comFuture;
        }

        public String getUniqueSerialNo() {
            return uniqueSerialNo;
        }

        public void setUniqueSerialNo(String uniqueSerialNo) {
            this.uniqueSerialNo = uniqueSerialNo;
        }

        public T getParam() {
            return param;
        }

        public void setParam(T param) {
            this.param = param;
        }

        public CompletableFuture<R> getComFuture() {
            return comFuture;
        }

        public void setComFuture(CompletableFuture<R> comFuture) {
            this.comFuture = comFuture;
        }

        public Object getData() {
            return data;
        }

        public void setData(Object data) {
            this.data = data;
        }
    }

    /**
     * <p>
     * 主要初始化线程池执行ScheduledTask任务
     *
     * </p>
     */
    public interface TransferService<T, R> {
        /**
         * <p>初始化线程池子</p>
         */
        void initScheduledPool();

        /**
         * <p>将请求封装,添加至阻塞队列中</p>
         *
         * @param param 请求参数
         * @return {@link R} 返回结果
         * @throws Exception
         */
        R doRequest(T param) throws Exception;

        /**
         * <p>将请求封装,添加至阻塞队列中</p>
         *
         * @param transferStation 对象
         * @param param           请求参数
         * @return {@link R} 返回结果
         * @throws Exception
         */
        default R baseRequest(T param, TransferStation transferStation) throws Exception {
            BlockingQueue<TransferContext> transferContextQueue = transferStation.getTransferContextQueue();
            if (transferContextQueue.size() > transferStation.capacity) {
                throw new RuntimeException("队列已经满了!");
            }
            CompletableFuture<R> future = new CompletableFuture<>();
            boolean offer = transferContextQueue.offer(new TransferContext(UUID.randomUUID().toString(), param, future));
            if (!offer) {
                throw new RuntimeException("队列已经满了~");
            }
            return future.get(3, TimeUnit.SECONDS);
        }

        /**
         * <p>封装返回结果</p>
         * 业务端务必实现该接口完成,并将远端返回的响应结果封装到TransferContext#data中
         * 并将TransferContext返回
         * 默认方法中的作为实例
         *
         * @param transferContexts 请求上下文
         * @return {@link List<TransferContext>}
         * @throws Exception
         */
        default List<TransferContext> invokeRemote(List<TransferContext> transferContexts) throws Exception {
            if (CollectionUtils.isEmpty(transferContexts)) {
                return null;
            }
            Iterator<TransferContext> iterator = transferContexts.iterator();
            while (iterator.hasNext()) {
                TransferContext req = iterator.next();
                if (req != null) {
                    // 填充数据
                    // req.setData(invoke(transferContexts));
                    Map<String, java.io.Serializable> map = new HashMap<>();
                    map.put("orderTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                    map.put("orderMoney", (BigDecimal.valueOf((long) (Math.random() * 10000), 2)));
                    req.setData(map);
                }

            }
            return transferContexts;
        }

    }

}
// 实现接口
@Service("OrderTransferService")
public class OrderTransferService<T, R> implements TransferStation.TransferService<T, R> {

    @Autowired
    private RemoteService remoteService;
    // 初始化TransferStation
    private final TransferStation transferStation = new TransferStation(100);


    @Override
    @PostConstruct
    public void initScheduledPool() {
        // todo 日志修改
        System.out.println("初始化线程池子->>>>>>>>>>>>>>>>>>>>>>>-----------");
        ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors());
        threadPool.scheduleAtFixedRate(new TransferStation.ScheduledTask(transferStation.getTransferContextQueue(), this)
                , 100, 10, TimeUnit.MILLISECONDS);
    }


    @Override
    public R doRequest(T param) throws Exception {
        return baseRequest(param, transferStation);
    }

    @Override
    public List<TransferStation.TransferContext> invokeRemote(List<TransferStation.TransferContext> transferContexts) throws Exception {
        // todo 修改日志打印
        System.out.println("handDataDefault:调用远端接口..........................................");
        List<TransferStation.TransferContext> transferContextTemp = transferContexts;
        if (CollectionUtils.isEmpty(transferContextTemp)) {
            return null;
        }
        //
        List<String> orderCodeList = transferContextTemp.stream().map(r -> String.valueOf(r.getParam())).collect(Collectors.toList());
        // todo 这里调用远程接口批量查询
        List<Map<String, Object>> remoteOrderList = remoteService.getOrderInfoByOrderCodeBatch2(orderCodeList);
        if (CollectionUtils.isEmpty(remoteOrderList)) {
            return null;
        }
        for (TransferStation.TransferContext request : transferContextTemp) {
            for (Map<String, Object> resp : remoteOrderList) {
                // 通过唯一字段进行匹配,将返回结果进行设置在TransferContext#data
                if (resp.get("orderCode").equals(request.getParam())) {
                    request.setData(resp);
                }
            }
        }
        return transferContextTemp;
    }
}

// 请求实例
 @Autowired
private OrderTransferService<String, Map<String, Object>> service;

// 调用方法doRequest
public Map<String, Object> queryOrderBatch2(String orderCode) throws Exception {
        return service.doRequest(orderCode);
}


API

CompletableFuture

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值