日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

優化SpringBoot吞吐量的七個高效策略

來源: 責編: 時間:2024-06-28 17:15:11 140觀看
導讀1、異步執行實現方式二種:使用異步注解 @aysnc、啟動類:添加 @EnableAsync 注解JDK 8 本身有一個非常好用的 Future 類——CompletableFuture@AllArgsConstructorpublic class AskThread implements Runnable{ priva

1、異步執行pGJ28資訊網——每日最新資訊28at.com

實現方式二種:pGJ28資訊網——每日最新資訊28at.com

  • 使用異步注解 @aysnc、啟動類:添加 @EnableAsync 注解
  • JDK 8 本身有一個非常好用的 Future 類——CompletableFuture
@AllArgsConstructorpublic class AskThread implements Runnable{    private CompletableFuture<Integer> re = null;    public void run() {        int myRe = 0;        try {            myRe = re.get() * re.get();        } catch (Exception e) {            e.printStackTrace();        }        System.out.println(myRe);    }    public static void main(String[] args) throws InterruptedException {        final CompletableFuture<Integer> future = new CompletableFuture<>();        new Thread(new AskThread(future)).start();        //模擬長時間的計算過程        Thread.sleep(1000);        //告知完成結果        future.complete(60);    }}

在該示例中,啟動一個線程,此時 AskThread 對象還沒有拿到它需要的數據,執行到  myRe = re.get() * re.get() 會阻塞。pGJ28資訊網——每日最新資訊28at.com

我們用休眠 1 秒來模擬一個長時間的計算過程,并將計算結果告訴 future 執行結果,AskThread 線程將會繼續執行。pGJ28資訊網——每日最新資訊28at.com

public class Calc {    public static Integer calc(Integer para) {        try {            //模擬一個長時間的執行            Thread.sleep(1000);        } catch (InterruptedException e) {            e.printStackTrace();        }        return para * para;    }    public static void main(String[] args) throws ExecutionException, InterruptedException {        final CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> calc(50))                .thenApply((i) -> Integer.toString(i))                .thenApply((str) -> "/"" + str + "/"")                .thenAccept(System.out::println);        future.get();    }}

CompletableFuture.supplyAsync 方法構造一個 CompletableFuture 實例,在 supplyAsync() 方法中,它會在一個新線程中,執行傳入的參數。pGJ28資訊網——每日最新資訊28at.com

在這里它會執行 calc() 方法,這個方法可能是比較慢的,但這并不影響 CompletableFuture 實例的構造速度,supplyAsync() 會立即返回。pGJ28資訊網——每日最新資訊28at.com

而返回的 CompletableFuture 實例就可以作為這次調用的契約,在將來任何場合,用于獲得最終的計算結果。pGJ28資訊網——每日最新資訊28at.com

supplyAsync 用于提供返回值的情況,CompletableFuture 還有一個不需要返回值的異步調用方法 runAsync(Runnable runnable),一般我們在優化 Controller 時,使用這個方法比較多。pGJ28資訊網——每日最新資訊28at.com

這兩個方法如果在不指定線程池的情況下,都是在 ForkJoinPool.common 線程池中執行,而這個線程池中的所有線程都是 Daemon(守護)線程,所以,當主線程結束時,這些線程無論執行完畢都會退出系統。pGJ28資訊網——每日最新資訊28at.com

核心代碼:pGJ28資訊網——每日最新資訊28at.com

CompletableFuture.runAsync(() ->   this.afterBetProcessor(betRequest,betDetailResult,appUser,id));

異步調用使用 Callable 來實現:pGJ28資訊網——每日最新資訊28at.com

@RestController  public class HelloController {    private static final Logger logger = LoggerFactory.getLogger(HelloController.class);    @Autowired      private HelloService hello;    @GetMapping("/helloworld")    public String helloWorldController() {        return hello.sayHello();    }    /**     * 異步調用restful     * 當controller返回值是Callable的時候,springmvc就會啟動一個線程將Callable交給TaskExecutor去處理     * 然后DispatcherServlet還有所有的spring攔截器都退出主線程,然后把response保持打開的狀態     * 當Callable執行結束之后,springmvc就會重新啟動分配一個request請求,然后DispatcherServlet就重新     * 調用和處理Callable異步執行的返回結果, 然后返回視圖     *     * @return     */      @GetMapping("/hello")    public Callable<String> helloController() {        logger.info(Thread.currentThread().getName() + " 進入helloController方法");        Callable<String> callable = new Callable<String>() {            @Override              public String call() throws Exception {                logger.info(Thread.currentThread().getName() + " 進入call方法");                String say = hello.sayHello();                logger.info(Thread.currentThread().getName() + " 從helloService方法返回");                return say;            }        };        logger.info(Thread.currentThread().getName() + " 從helloController方法返回");        return callable;    }}

異步調用的方式 WebAsyncTask:pGJ28資訊網——每日最新資訊28at.com

@RestController  public class HelloController {    private static final Logger logger = LoggerFactory.getLogger(HelloController.class);    @Autowired      private HelloService hello;    /**     * 帶超時時間的異步請求 通過WebAsyncTask自定義客戶端超時間     * @return     */      @GetMapping("/world")    public WebAsyncTask<String> worldController() {        logger.info(Thread.currentThread().getName() + " 進入helloController方法");        // 3s鐘沒返回,則認為超時        WebAsyncTask<String> webAsyncTask = new WebAsyncTask<>(3000, new Callable<String>() {            @Override              public String call() throws Exception {                logger.info(Thread.currentThread().getName() + " 進入call方法");                String say = hello.sayHello();                logger.info(Thread.currentThread().getName() + " 從helloService方法返回");                return say;            }        });        logger.info(Thread.currentThread().getName() + " 從helloController方法返回");        webAsyncTask.onCompletion(new Runnable() {            @Override              public void run() {                logger.info(Thread.currentThread().getName() + " 執行完畢");            }        });        webAsyncTask.onTimeout(new Callable<String>() {            @Override              public String call() throws Exception {                logger.info(Thread.currentThread().getName() + " onTimeout");                // 超時的時候,直接拋異常,讓外層統一處理超時異常                throw new TimeoutException("調用超時");            }        });        return webAsyncTask;    }    /**     * 異步調用,異常處理,詳細的處理流程見MyExceptionHandler類     * @return     */      @GetMapping("/exception")    public WebAsyncTask<String> exceptionController() {        logger.info(Thread.currentThread().getName() + " 進入helloController方法");        Callable<String> callable = new Callable<String>() {            @Override              public String call() throws Exception {                logger.info(Thread.currentThread().getName() + " 進入call方法");                throw new TimeoutException("調用超時!");            }        };        logger.info(Thread.currentThread().getName() + " 從helloController方法返回");        return new WebAsyncTask<>(20000, callable);    }}


pGJ28資訊網——每日最新資訊28at.com

2、增加內嵌 Tomcat 的最大連接數pGJ28資訊網——每日最新資訊28at.com

代碼如下:pGJ28資訊網——每日最新資訊28at.com

@Configurationpublic class TomcatConfig {    @Bean    public ConfigurableServletWebServerFactory webServerFactory() {        TomcatServletWebServerFactory tomcatFactory = new TomcatServletWebServerFactory();        tomcatFactory.addConnectorCustomizers(new MyTomcatConnectorCustomizer());        tomcatFactory.setPort(8005);        tomcatFactory.setContextPath("/api-g");        return tomcatFactory;    }    class MyTomcatConnectorCustomizer implements TomcatConnectorCustomizer {        public void customize(Connector connector) {            Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();            //設置最大連接數            protocol.setMaxConnections(20000);            //設置最大線程數            protocol.setMaxThreads(2000);            protocol.setConnectionTimeout(30000);        }    }}

3、使用 @ComponentScan()pGJ28資訊網——每日最新資訊28at.com

使用 @ComponentScan() 定位掃包比 @SpringBootApplication 掃包更快。pGJ28資訊網——每日最新資訊28at.com

4、默認 Tomcat 容器改為 UndertowpGJ28資訊網——每日最新資訊28at.com

默認 Tomcat 容器改為 Undertow(Jboss 下的服務器,Tomcat 吞吐量 5000,Undertow 吞吐量 8000)pGJ28資訊網——每日最新資訊28at.com

<exclusions>  <exclusion>     <groupId>org.springframework.boot</groupId>     <artifactId>spring-boot-starter-tomcat</artifactId>  </exclusion></exclusions>

改為:pGJ28資訊網——每日最新資訊28at.com

<dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-undertow</artifactId></dependency>

5、使用 BufferedWriter 進行緩沖pGJ28資訊網——每日最新資訊28at.com

這里不給大家舉例,可自行嘗試。pGJ28資訊網——每日最新資訊28at.com

6、Deferred 方式實現異步調用pGJ28資訊網——每日最新資訊28at.com

代碼如下:pGJ28資訊網——每日最新資訊28at.com

@RestControllerpublic class AsyncDeferredController {    private final Logger logger = LoggerFactory.getLogger(this.getClass());    private final LongTimeTask taskService;    @Autowired    public AsyncDeferredController(LongTimeTask taskService) {        this.taskService = taskService;    }    @GetMapping("/deferred")    public DeferredResult<String> executeSlowTask() {        logger.info(Thread.currentThread().getName() + "進入executeSlowTask方法");        DeferredResult<String> deferredResult = new DeferredResult<>();        // 調用長時間執行任務        taskService.execute(deferredResult);        // 當長時間任務中使用deferred.setResult("world");這個方法時,會從長時間任務中返回,繼續controller里面的流程        logger.info(Thread.currentThread().getName() + "從executeSlowTask方法返回");        // 超時的回調方法        deferredResult.onTimeout(new Runnable(){   @Override   public void run() {    logger.info(Thread.currentThread().getName() + " onTimeout");    // 返回超時信息    deferredResult.setErrorResult("time out!");   }  });        // 處理完成的回調方法,無論是超時還是處理成功,都會進入這個回調方法        deferredResult.onCompletion(new Runnable(){   @Override   public void run() {    logger.info(Thread.currentThread().getName() + " onCompletion");   }  });        return deferredResult;    }}

7、異步調用可以使用 AsyncHandlerInterceptor 進行攔截pGJ28資訊網——每日最新資訊28at.com

代碼如下:pGJ28資訊網——每日最新資訊28at.com

@Componentpublic class MyAsyncHandlerInterceptor implements AsyncHandlerInterceptor { private static final Logger logger = LoggerFactory.getLogger(MyAsyncHandlerInterceptor.class); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)   throws Exception {  return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,   ModelAndView modelAndView) throws Exception {// HandlerMethod handlerMethod = (HandlerMethod) handler;  logger.info(Thread.currentThread().getName()+ "服務調用完成,返回結果給客戶端"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)   throws Exception {  if(null != ex){   System.out.println("發生異常:"+ex.getMessage());  } } @Override public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler)   throws Exception {  // 攔截之后,重新寫回數據,將原來的hello world換成如下字符串  String resp = "my name is chhliu!";  response.setContentLength(resp.length());  response.getOutputStream().write(resp.getBytes());  logger.info(Thread.currentThread().getName() + " 進入afterConcurrentHandlingStarted方法"); }}


pGJ28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-97290-0.html優化SpringBoot吞吐量的七個高效策略

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 列表大揭秘:一文掌握 Python 列表的高級玩法

下一篇: C#/.NET這些實用的技巧和知識點你都知道嗎?

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 临洮县| 芜湖县| 西林县| 乐昌市| 汽车| 浮梁县| 宿迁市| 于田县| 农安县| 永德县| 宜兴市| 沙坪坝区| 宁夏| 商洛市| 杭锦后旗| 巴南区| 常宁市| 固原市| 印江| 城市| 饶河县| 牡丹江市| 西平县| 屯昌县| 郸城县| 延津县| 鄱阳县| 绥中县| 星座| 阳西县| 沐川县| 黄山市| 安国市| 广汉市| 扬中市| 甘孜县| 新巴尔虎左旗| 海盐县| 德格县| 莫力| 赣榆县|