Springboot執行緒池的使用和擴充套件

nintyuui發表於2021-09-09

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

實戰環境

  • windowns10;

  • jdk1.8;

  • springboot 1.5.9.RELEASE;

  • 開發工具:IntelliJ IDEA;

實戰原始碼

本次實戰的原始碼可以在我的GitHub下載,地址:

git@github.com:zq2599/blog_demos.git,

專案主頁:

https://github.com/zq2599/blog_demos

這裡面有多個工程,本次用到的工程為threadpooldemoserver,如下圖紅框所示:

實戰步驟梳理

本次實戰的步驟如下:

  1. 建立springboot工程;

  2. 建立Service層的介面和實現;

  3. 建立controller,開發一個http服務介面,裡面會呼叫service層的服務;

  4. 建立執行緒池的配置;

  5. 將Service層的服務非同步化,這樣每次呼叫都會都被提交到執行緒池非同步執行;

  6. 擴充套件ThreadPoolTaskExecutor,在提交任務到執行緒池的時候可以觀察到當前執行緒池的情況;

建立springboot工程

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


    xsi:schemaLocation=" ">
    4.0.0
    com.bolingcavalry
    threadpooldemoserver
    0.0.1-SNAPSHOT
    jar
    threadpooldemoserver
    Demo project for Spring Boot
    
        org.springframework.boot
        spring-boot-starter-parent
        1.5.9.RELEASE
         <!-- lookup parent from repository --&gt
    

    
        UTF-8
        UTF-8
        1.8
    

    
        
            org.springframework.boot
            spring-boot-starter-web
        

    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            

        

    


建立Service層的介面和實現

建立一個service層的介面AsyncService,如下:

public interface AsyncService {

    /**
     * 執行非同步任務
     */
    void executeAsync();
}

對應的AsyncServiceImpl,實現如下:

@Service
public class AsyncServiceImpl implements AsyncService {

    private static final Logger logger = LoggerFactory.getLogger(AsyncServiceImpl.class);

    @Override
    public void executeAsync() {
        logger.info("start executeAsync");
        try{
            Thread.sleep(1000);
        }catch(Exception e){
            e.printStackTrace();
        }
        logger.info("end executeAsync");
    }
}

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

建立controller

建立一個controller為Hello,裡面定義一個http介面,做的事情是呼叫Service層的服務,如下:

@RestController
public class Hello {

    private static final Logger logger = LoggerFactory.getLogger(Hello.class);

    @Autowired
    private AsyncService asyncService;

    @RequestMapping("/")
    public String submit(){
        logger.info("start submit");

        //呼叫service層的任務
        asyncService.executeAsync();

        logger.info("end submit");

        return "success";
    }
}

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

springboot的執行緒池配置

建立一個配置類ExecutorConfig,用來定義如何建立一個ThreadPoolTaskExecutor,要使用@Configuration和@EnableAsync這兩個註解,表示這是個配置類,並且是執行緒池的配置類,如下所示:

@Configuration
@EnableAsync
public class ExecutorConfig {

    private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class);

    @Bean
    public Executor asyncServiceExecutor() {
        logger.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方法建立的,如下:

@Override
    @Async("asyncServiceExecutor")
    public void executeAsync() {
        logger.info("start executeAsync");
        try{
            Thread.sleep(1000);
        }catch(Exception e){
            e.printStackTrace();
        }
        logger.info("end executeAsync");
    }

驗證效果

  1. 將這個springboot執行起來(pom.xml所在資料夾下執行mvn spring-boot:run);

  2. 在瀏覽器輸入:;

  3. 在瀏覽器用F5按鈕快速多重新整理幾次;

  4. 在springboot的控制檯看見日誌如下:

2018-01-21 22:43:18.630  INFO 14824 --- [nio-8080-exec-8] c.b.t.controller.Hello                   : start submit
2018-01-21 22:43:18.630  INFO 14824 --- [nio-8080-exec-8] c.b.t.controller.Hello                   : end submit
2018-01-21 22:43:18.929  INFO 14824 --- [async-service-1] c.b.t.service.impl.AsyncServiceImpl      : end executeAsync
2018-01-21 22:43:18.930  INFO 14824 --- [async-service-1] c.b.t.service.impl.AsyncServiceImpl      : start executeAsync
2018-01-21 22:43:19.005  INFO 14824 --- [async-service-2] c.b.t.service.impl.AsyncServiceImpl      : end executeAsync
2018-01-21 22:43:19.006  INFO 14824 --- [async-service-2] c.b.t.service.impl.AsyncServiceImpl      : start executeAsync
2018-01-21 22:43:19.175  INFO 14824 --- [async-service-3] c.b.t.service.impl.AsyncServiceImpl      : end executeAsync
2018-01-21 22:43:19.175  INFO 14824 --- [async-service-3] c.b.t.service.impl.AsyncServiceImpl      : start executeAsync
2018-01-21 22:43:19.326  INFO 14824 --- [async-service-4] c.b.t.service.impl.AsyncServiceImpl      : end executeAsync
2018-01-21 22:43:19.495  INFO 14824 --- [async-service-5] c.b.t.service.impl.AsyncServiceImpl      : end executeAsync
2018-01-21 22:43:19.930  INFO 14824 --- [async-service-1] c.b.t.service.impl.AsyncServiceImpl      : end executeAsync
2018-01-21 22:43:20.006  INFO 14824 --- [async-service-2] c.b.t.service.impl.AsyncServiceImpl      : end executeAsync
2018-01-21 22:43:20.191  INFO 14824 --- [async-service-3] c.b.t.service.impl.AsyncServiceImpl      : end executeAsync

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


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/3209/viewspace-2807285/,如需轉載,請註明出處,否則將追究法律責任。

相關文章