日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Springboot线程池的使用和扩展

發布時間:2024/9/16 javascript 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Springboot线程池的使用和扩展 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

????我們常用ThreadPoolExecutor提供的線程池服務,springboot框架提供了@Async注解,幫助我們更方便的將業務邏輯提交到線程池中異步執行,今天我們就來實戰體驗這個線程池服務;

實戰環境

  • jdk 1.8
  • springboot?2.1.4.RELEASE
  • 開發工具:IntelliJ IDEA

實戰源碼

https://github.com/vincentduan/mavenProject.git,其中的threadpooldemoserver目錄

實戰步驟梳理

本次實戰的步驟如下:

  • 創建springboot工程;
  • 創建Service層的接口和實現;
  • 創建controller,開發一個http服務接口,里面會調用service層的服務;
  • 創建線程池的配置;
  • 將Service層的服務異步化,這樣每次調用都會都被提交到線程池異步執行;
  • 擴展ThreadPoolTaskExecutor,在提交任務到線程池的時候可以觀察到當前線程池的情況;
  • ?創建springboot工程

    用IntelliJ IDEA創建一個springboot的web工程threadpooldemoserver,pom.xml內容如下:

    <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.vincent</groupId><artifactId>threadpooldemoserver</artifactId><version>1.0-SNAPSHOT</version><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.1.4.RELEASE</version><scope>import</scope><type>pom</type></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.6</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.1.4.RELEASE</version><configuration><mainClass>cn.ac.iie.App</mainClass></configuration><executions><execution><goals><goal>repackage</goal></goals></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><configuration><skip>true</skip></configuration></plugin></plugins></build></project>

    創建Service層的接口和實現

    創建一個service層的接口AsyncService,如下:

    public interface AsyncService {/*** 執行異步任務*/void executeAsync(); }

    對應的AsyncServiceImpl,實現如下:

    @Service @Slf4j public class AsyncServiceImpl implements AsyncService {@Overridepublic void executeAsync() {log.info("start executeAsync");try{Thread.sleep(1000);}catch(Exception e){e.printStackTrace();}log.info("end executeAsync");} }

    這個方法做的事情很簡單:sleep了一秒鐘;

    創建controller

    創建一個controller為Hello,里面定義一個http接口,做的事情是調用Service層的服務,如下:

    @RestController @Slf4j public class Hello {@Autowiredprivate AsyncService asyncService;@RequestMapping("/")public String submit() {log.info("start submit");//調用service層的任務asyncService.executeAsync();log.info("end submit");return "success";} }

    至此,我們已經做好了一個http請求的服務,里面做的事情其實是同步的,接下來我們就開始配置springboot的線程池服務,將service層做的事情都提交到線程池中去處理;

    springboot的線程池配置

    創建一個配置類ExecutorConfig,用來定義如何創建一個ThreadPoolTaskExecutor,要使用@Configuration和@EnableAsync這兩個注解,表示這是個配置類,并且是線程池的配置類,如下所示:

    @Configuration @EnableAsync @Slf4j public class ExecutorConfig {@Beanpublic Executor asyncServiceExecutor() {log.info("start asyncServiceExecutor");ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();//配置核心線程數executor.setCorePoolSize(5);//配置最大線程數executor.setMaxPoolSize(5);//配置隊列大小executor.setQueueCapacity(99999);//配置線程池中的線程的名稱前綴executor.setThreadNamePrefix("async-service-");// rejection-policy:當pool已經達到max size的時候,如何處理新任務// CALLER_RUNS:不在新線程中執行任務,而是有調用者所在的線程來執行executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//執行初始化executor.initialize();return executor;} }

    注意,上面的方法名稱為asyncServiceExecutor,稍后馬上用到;

    將Service層的服務異步化

    打開AsyncServiceImpl.java,在executeAsync方法上增加注解@Async(“asyncServiceExecutor”),asyncServiceExecutor是前面ExecutorConfig.java中的方法名,表明executeAsync方法進入的線程池是asyncServiceExecutor方法創建的,如下:

    @Service @Slf4j public class AsyncServiceImpl implements AsyncService {@Override@Async("asyncServiceExecutor")public void executeAsync() {log.info("start executeAsync");try{Thread.sleep(1000);}catch(Exception e){e.printStackTrace();}log.info("end executeAsync");} }

    驗證效果

  • 將這個springboot運行起來(pom.xml所在文件夾下執行mvn spring-boot:run);
  • 在瀏覽器輸入:http://localhost:8080;
  • 在瀏覽器用F5按鈕快速多刷新幾次;
  • 在springboot的控制臺看見日志如下:
  • 2019-08-12 15:23:00.320 INFO 5848 --- [nio-8080-exec-2] cn.ac.iie.controller.Hello : start submit 2019-08-12 15:23:00.327 INFO 5848 --- [nio-8080-exec-2] cn.ac.iie.controller.Hello : end submit 2019-08-12 15:23:00.327 INFO 5848 --- [async-service-1] cn.ac.iie.service.impl.AsyncServiceImpl : start executeAsync 2019-08-12 15:23:01.329 INFO 5848 --- [async-service-1] cn.ac.iie.service.impl.AsyncServiceImpl : end executeAsync 2019-08-12 15:24:17.449 INFO 5848 --- [nio-8080-exec-5] cn.ac.iie.controller.Hello : start submit 2019-08-12 15:24:17.450 INFO 5848 --- [nio-8080-exec-5] cn.ac.iie.controller.Hello : end submit 2019-08-12 15:24:17.450 INFO 5848 --- [async-service-2] cn.ac.iie.service.impl.AsyncServiceImpl : start executeAsync 2019-08-12 15:24:18.125 INFO 5848 --- [nio-8080-exec-6] cn.ac.iie.controller.Hello : start submit 2019-08-12 15:24:18.126 INFO 5848 --- [nio-8080-exec-6] cn.ac.iie.controller.Hello : end submit 2019-08-12 15:24:18.128 INFO 5848 --- [async-service-3] cn.ac.iie.service.impl.AsyncServiceImpl : start executeAsync 2019-08-12 15:24:18.451 INFO 5848 --- [async-service-2] cn.ac.iie.service.impl.AsyncServiceImpl : end executeAsync 2019-08-12 15:24:18.685 INFO 5848 --- [nio-8080-exec-7] cn.ac.iie.controller.Hello : start submit 2019-08-12 15:24:18.688 INFO 5848 --- [nio-8080-exec-7] cn.ac.iie.controller.Hello : end submit 2019-08-12 15:24:18.703 INFO 5848 --- [async-service-4] cn.ac.iie.service.impl.AsyncServiceImpl : start executeAsync 2019-08-12 15:24:19.130 INFO 5848 --- [async-service-3] cn.ac.iie.service.impl.AsyncServiceImpl : end executeAsync 2019-08-12 15:24:19.704 INFO 5848 --- [async-service-4] cn.ac.iie.service.impl.AsyncServiceImpl : end executeAsync

    ?如上日志所示,我們可以看到controller的執行線程是"nio-8080-exec-5",這是tomcat的執行線程,而service層的日志顯示線程名為“async-service-1”,顯然已經在我們配置的線程池中執行了,并且每次請求中,controller的起始和結束日志都是連續打印的,表明每次請求都快速響應了,而耗時的操作都留給線程池中的線程去異步執行;

    擴展ThreadPoolTaskExecutor

    雖然我們已經用上了線程池,但是還不清楚線程池當時的情況,有多少線程在執行,多少在隊列中等待呢?這里我創建了一個ThreadPoolTaskExecutor的子類,在每次提交線程的時候都會將當前線程池的運行狀況打印出來,代碼如下:

    @Slf4j public class VisiableThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {private void showThreadPoolInfo(String prefix){ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();if(null==threadPoolExecutor){return;}log.info("{}, {},taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]",this.getThreadNamePrefix(),prefix,threadPoolExecutor.getTaskCount(),threadPoolExecutor.getCompletedTaskCount(),threadPoolExecutor.getActiveCount(),threadPoolExecutor.getQueue().size());}@Overridepublic void execute(Runnable task) {showThreadPoolInfo("1. do execute");super.execute(task);}@Overridepublic void execute(Runnable task, long startTimeout) {showThreadPoolInfo("2. do execute");super.execute(task, startTimeout);}@Overridepublic Future<?> submit(Runnable task) {showThreadPoolInfo("1. do submit");return super.submit(task);}@Overridepublic <T> Future<T> submit(Callable<T> task) {showThreadPoolInfo("2. do submit");return super.submit(task);}@Overridepublic ListenableFuture<?> submitListenable(Runnable task) {showThreadPoolInfo("1. do submitListenable");return super.submitListenable(task);}@Overridepublic <T> ListenableFuture<T> submitListenable(Callable<T> task) {showThreadPoolInfo("2. do submitListenable");return super.submitListenable(task);} }

    如上所示,showThreadPoolInfo方法中將任務總數、已完成數、活躍線程數,隊列大小都打印出來了,然后Override了父類的execute、submit等方法,在里面調用showThreadPoolInfo方法,這樣每次有任務被提交到線程池的時候,都會將當前線程池的基本情況打印到日志中;

    修改ExecutorConfig.java的asyncServiceExecutor方法,將ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor()改為ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor(),如下所示:

    @Beanpublic Executor asyncServiceExecutor() {log.info("start asyncServiceExecutor");ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();//配置核心線程數executor.setCorePoolSize(5);//配置最大線程數executor.setMaxPoolSize(5);//配置隊列大小executor.setQueueCapacity(99999);//配置線程池中的線程的名稱前綴executor.setThreadNamePrefix("async-service-");// rejection-policy:當pool已經達到max size的時候,如何處理新任務// CALLER_RUNS:不在新線程中執行任務,而是有調用者所在的線程來執行executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//執行初始化executor.initialize();return executor;}

    修改hello.java,方便查看線程池結果:

    @RequestMapping("/")public Object submit() {log.info("start submit");//調用service層的任務asyncService.executeAsync();log.info("end submit");JSONObject jsonObject = new JSONObject();ThreadPoolExecutor threadPoolExecutor = visiableThreadPoolTaskExecutor.getThreadPoolExecutor();jsonObject.put("ThreadNamePrefix", visiableThreadPoolTaskExecutor.getThreadNamePrefix());jsonObject.put("TaskCount", threadPoolExecutor.getTaskCount());jsonObject.put("completedTaskCount", threadPoolExecutor.getCompletedTaskCount());jsonObject.put("activeCount", threadPoolExecutor.getActiveCount());jsonObject.put("queueSize", threadPoolExecutor.getQueue().size());return jsonObject;}

    再次啟動該工程,再瀏覽器反復刷新http://localhost:8080,看到的日志如下:

    {"activeCount": 2,"queueSize": 1,"TaskCount": 26,"completedTaskCount": 23,"ThreadNamePrefix": "async-service-" }

    這時其中一條的返回結果。

    這說明提交任務到線程池的時候,調用的是submit(Callable task)這個方法,當前已經提交了26個任務,完成了23個,當前有2個線程在處理任務,還剩1個任務在隊列中等待,線程池的基本情況一目了然;

    總結

    以上是生活随笔為你收集整理的Springboot线程池的使用和扩展的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。