异步并发实战

13.1 同步阻塞调用

13.2 异步Future

private void FutureTest() {
    //请求
    Future<?> userInfoTask = POOL.submit(() -> {/**请求客户信息**/});
    Future<?> orderInfoTask = POOL.submit(() -> {/**请求订单数据**/});

    try {
        Object userInfo = userInfoTask.get(300, TimeUnit.MILLISECONDS);
        Object orderInfo = orderInfoTask.get(300, TimeUnit.MILLISECONDS);
    } catch (Exception e) {
        if (userInfoTask != null) {
            userInfoTask.cancel(true);
        }
        if (orderInfoTask != null) {
            orderInfoTask.cancel(true);
        }
        throw new RuntimeException(e);
    }
}

 

13.3 异步Callback

13.4 异步编排CompletableFuture

   CompletableFuture可以对多个异步处理进行编排,实现更复杂的异步处理。内部使用ForkJoinPool实现异步处理。ForkJoinPool内部使用双端队列实现工作密取。

13.5 异步Web服务实现

AsyncContext示例:

当Tomcat封装请求和响应传递给Servlet,Servlet通常要阻塞等待业务处理完毕才能返回。使用startAsync开启异步,自己则继续处理下一个请求,后续的处理由AsyncContext完成,并返回客户端。对于客户端来说,依然是同步等待,但是对于Tomcat来说,是异步处理请求的。

@Service
public class AsyncContextTest {

    @Autowired
    private HttpServletRequest request;

    private static final ExecutorService POOL = Executors.newCachedThreadPool();

    public void test() {
        //释放servlet线程让其继续接待其他请求
        AsyncContext asyncContext = request.startAsync();
        //先不设置超时自己控制
        asyncContext.setTimeout(0);

        POOL.submit(() -> {
            try {
                //模拟处理过程
                Thread.sleep(1000);
                //返回客户端
                PrintWriter writer = asyncContext.getResponse().getWriter();
                writer.println("handle success");
                //任务执行完成,通知回调
                asyncContext.complete();
            } catch (Exception ignore) {
                //
            }
        });
    }
}

 结合CompletableFuture

public void test2(Callable<CompletableFuture> task) throws Exception {
    final String uri = request.getRequestURI();
    final Map<String, String[]> params = request.getParameterMap();
    //释放Servlet
    AsyncContext asyncContext = request.startAsync();
    asyncContext.getRequest().setAttribute("uri", uri);
    asyncContext.getRequest().setAttribute("params", params);
    asyncContext.setTimeout(5000);

    //执行任务
    CompletableFuture call = task.call();
    //执行完成后
    call.thenAccept(result -> {
        //返回调用方
        HttpServletResponse httpServletResponse = (HttpServletResponse) asyncContext.getResponse();
        try {
            byte[] bytes;
            if (result instanceof String) {
                bytes = ((String) result).getBytes("GBK");
            } else {
                bytes = JSON.toJSONBytes(result);
            }
            httpServletResponse.setContentType("text/html;charset=gbk");
            httpServletResponse.setContentLength(bytes.length);
            httpServletResponse.getOutputStream().write(bytes);
        } catch (Exception e) {
            httpServletResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            System.out.println(e.getMessage());
        } finally {
            asyncContext.complete();
        }
    }).exceptionally(exception -> {
        //异常处理
        asyncContext.complete();
        return null;
    });

}

  

13.6 请求缓存

  一次请求中重复调用同一个接口。譬如一次用户查询,调用多次商品详情接口。一般的解决方法是对商品详情查询接口包装一层缓存。另这一种可行的方法是使用Hystrix提供的HystrixRequestContext

  注意一下HystrixCommand

13.7 请求合并

  CompletableFuture需要事先定义好多个任务,而Hystrix支持将多个单请求合并成一个批量请求。

  注意一下HystrixCollapser

 

posted @ 2021-04-26 21:54  walker993  阅读(110)  评论(0编辑  收藏  举报