• 使用多线程提高Rest服务性能


    ⒈使用Runnable异步处理Rest服务

     1     /**
     2      *使用Runnable异步处理Rest服务
     3      * @return
     4      */
     5     @GetMapping("/order")
     6     public Callable<String> callableOrder(){
     7         logger.info("主线程开始");
     8         System.out.println(Thread.currentThread().getId());
     9         Callable<String> result = new Callable<String>() {
    10             @Override
    11             public String call() throws Exception {
    12                 logger.info("副线程开始");
    13                 Thread.sleep(1000);
    14                 System.out.println(Thread.currentThread().getId());
    15                 logger.info("副线程返回");
    16                 return "seccess";
    17             }
    18         };
    19         logger.info("主线程返回");
    20         return result;
    21     }

    Runnable的这种形式并不能满足所有的应用场景,使用Runnable异步处理的时候,副线程必须是由主线程调起的,在实际开发的过程中,有些场景是非常复杂的。

    例如,如下场景:

     我们可以使用DeferredResult来解决上面复杂的场景

    ⒉使用DeferredResult异步处理Rest服务

      1.模拟队列

     1 package cn.coreqi.security.async;
     2 
     3 import org.slf4j.Logger;
     4 import org.slf4j.LoggerFactory;
     5 import org.springframework.stereotype.Component;
     6 
     7 /**
     8  * 用于模拟消息队列
     9  */
    10 @Component
    11 public class MockQueue {
    12 
    13     private String placeOrder;  //代表下单的消息
    14 
    15     private String completeOrder;   //代表订单完成的消息
    16 
    17     private Logger logger = LoggerFactory.getLogger(getClass());
    18 
    19     public String getPlaceOrder() {
    20         return placeOrder;
    21     }
    22 
    23     public void setPlaceOrder(String placeOrder){
    24         new Thread(() -> {
    25             logger.info("接到下单请求!" + placeOrder);
    26             try {
    27                 Thread.sleep(1000);
    28             } catch (InterruptedException e) {
    29                 e.printStackTrace();
    30             }
    31             this.completeOrder = placeOrder;
    32             logger.info("下单请求处理完成!" + placeOrder);
    33         }).start();
    34     }
    35 
    36     public String getCompleteOrder() {
    37         return completeOrder;
    38     }
    39 
    40     public void setCompleteOrder(String completeOrder) {
    41         this.completeOrder = completeOrder;
    42     }
    43 }

      2.模拟结果

      

     1 package cn.coreqi.security.async;
     2 
     3 import org.springframework.stereotype.Component;
     4 import org.springframework.web.context.request.async.DeferredResult;
     5 
     6 import java.util.HashMap;
     7 import java.util.Map;
     8 
     9 @Component
    10 public class DeferredResultHolder {
    11 
    12     private Map<String, DeferredResult<String>> map = new HashMap<>();  //K为ID,V代表处理结果
    13 
    14     public Map<String, DeferredResult<String>> getMap() {
    15         return map;
    16     }
    17 
    18     public void setMap(Map<String, DeferredResult<String>> map) {
    19         this.map = map;
    20     }
    21 }

      3.控制器处理

     1     @Autowired
     2     private MockQueue mockQueue;
     3 
     4     @Autowired
     5     private DeferredResultHolder deferredResultHolder;
     6 
     7     /**
     8      * 使用DeferredResult异步处理Rest服务
     9      * @return
    10      * @throws InterruptedException
    11      */
    12     @GetMapping("/order")
    13     public DeferredResult<String> deferredResultOrder() throws InterruptedException {
    14         logger.info("主线程开始");
    15         System.out.println(Thread.currentThread().getId());
    16         String orderNumber = new Random().longs(8).toString();  //生成订单号
    17         mockQueue.setPlaceOrder(orderNumber);   //放入到消息队列里面
    18         DeferredResult<String> result = new DeferredResult<>();
    19         deferredResultHolder.getMap().put(orderNumber,result);
    20         return result;
    21     }

      4.监听结果并返回

     1 package cn.coreqi.security.async;
     2 
     3 import org.slf4j.Logger;
     4 import org.slf4j.LoggerFactory;
     5 import org.springframework.beans.factory.annotation.Autowired;
     6 import org.springframework.context.ApplicationListener;
     7 import org.springframework.context.event.ContextRefreshedEvent;
     8 import org.springframework.stereotype.Component;
     9 import org.springframework.util.StringUtils;
    10 
    11 @Component
    12 public class QueueListener implements ApplicationListener<ContextRefreshedEvent> {
    13     @Autowired
    14     private MockQueue mockQueue;    //模拟的队列
    15     @Autowired
    16     private DeferredResultHolder deferredResultHolder;
    17 
    18     private Logger logger = LoggerFactory.getLogger(getClass());
    19     @Override
    20     public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
    21         new Thread(() -> {
    22             while (true){
    23                 if(StringUtils.hasText(mockQueue.getCompleteOrder())){
    24                     String oderNumber = mockQueue.getCompleteOrder();   //拿到订单号
    25                     logger.info("返回订单处理结果:" + oderNumber);
    26                     deferredResultHolder.getMap().get(oderNumber).setResult("place order success");
    27                     mockQueue.setCompleteOrder(null);
    28                 }else{
    29                     try {
    30                         Thread.sleep(100);
    31                     } catch (InterruptedException e) {
    32                         e.printStackTrace();
    33                     }
    34                 }
    35             }
    36         }).start();
    37     }
    38 }

     ⒊异步相关配置

     1 package cn.coreqi.security.config;
     2 
     3 import org.springframework.context.annotation.Configuration;
     4 import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
     5 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
     6 
     7 @Configuration
     8 public class WebConfig implements WebMvcConfigurer {
     9     
    10     /**
    11      * 配置异步支持
    12      * @param configurer
    13      */
    14     @Override
    15     public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
    16         //configurer.registerCallableInterceptors();  //设置异步的拦截器
    17         //configurer.registerDeferredResultInterceptors();    //设置异步的拦截器
    18         //configurer.setDefaultTimeout(20000);  //设置超时时间
    19         //configurer.setTaskExecutor();   //默认情况下Spring用自己简单的异步线程池来处理,不会重用池里面的线程,
    20                                         //而是每次调用时都会开启新的线程,可以自己设置一些可重用的线程池来替换
    21                                         //Spring默认的简单异步线程池。
    22     }
    23 }
  • 相关阅读:
    2019 学霸君java面试笔试题 (含面试题解析)
    2019 大众书网Java面试笔试题 (含面试题解析)
    2019 中细软java面试笔试题 (含面试题解析)
    2019 企叮咚java面试笔试题 (含面试题解析)
    js 去掉数组对象中的重复对象
    canvas霓虹雨
    nvm的安装
    socket.io 中文文档
    Nginx(三)------nginx 反向代理
    github入门到上传本地项目
  • 原文地址:https://www.cnblogs.com/fanqisoft/p/10612882.html
Copyright © 2020-2023  润新知