SpringBoot自定義線程池處理異步任務


@Async異步調用

就不解釋什么是異步調用了,Spring Boot中進行異步調用很簡單

1.通過使用@Async注解就能簡單的將原來的同步函數變為異步函數

package com.winner.service; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit; /** * @author winner_0715 * @date 2018/12/06 */ @Service public class TaskServer { @Async public void doTaskA() throws InterruptedException { System.out.println("TaskA thread name->" + Thread.currentThread().getName()); Long startTime = System.currentTimeMillis(); TimeUnit.SECONDS.sleep(2); Long endTime = System.currentTimeMillis(); System.out.println("TaskA 耗時:" + (endTime - startTime)); } @Async public void doTaskB() throws InterruptedException { System.out.println("TaskB thread name->" + Thread.currentThread().getName()); Long startTime = System.currentTimeMillis(); TimeUnit.SECONDS.sleep(2); Long endTime = System.currentTimeMillis(); System.out.println("TaskB耗時:" + (endTime - startTime)); } }

為了讓@Async注解能夠生效,還需要在Spring Boot的主程序中配置@EnableAsync,如下所示:

package com.winner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableAsync; /** * @author winner_0715 * @date 2018/12/06 */ @SpringBootApplication @EnableAsync public class SpringBootAsyncApplication { public static void main(String[] args) { SpringApplication.run(SpringBootAsyncApplication.class, args); } }

注: @Async所修飾的函數不要定義為static類型,這樣異步調用不會生效

測試

package com.winner.web; import com.winner.service.TaskServer; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; /** * @author winner_0715 * @description: * @date 2018/12/6 */ @RestController public class HelloController { @Resource private TaskServer taskServer; @GetMapping("/async") public String testAsync() throws Exception { System.out.println("主線程 name -->" + Thread.currentThread().getName()); taskServer.doTaskA(); taskServer.doTaskB(); return "Hello World"; } }

任務線程和主線程的名稱不同,表明是異步執行的!

自定義線程池

前面介紹使用@Async注解來實現異步調用了。對於這些異步執行的控制是我們保障自身應用健康的基本技能。下面介紹通過自定義線程池的方式來控制異步調用的並發。

定義線程池

第一步,定義一個線程池,比如:

package com.winner.threadpool; import com.google.common.util.concurrent.ThreadFactoryBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * @author winner_0715 */ @Configuration public class ThreadPoolExecutorConfig { private static final int THREADS = Runtime.getRuntime().availableProcessors() + 1; final ThreadFactory threadFactory = new ThreadFactoryBuilder() // -%d不要少
            .setNameFormat("async-task-name-%d") .setDaemon(true) .build(); @Bean("taskExecutor") public Executor taskExecutor() { return new ThreadPoolExecutor(THREADS, 2 * THREADS, 5, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1024), threadFactory, (r, executor) -> { // 打印日志,添加監控等
            System.out.println("task is rejected!"); }); } }

上面我們通過使用ThreadPoolExecutor創建了一個線程池

使用線程池

在定義了線程池之后,我們如何讓異步調用的執行任務使用這個線程池中的資源來運行呢?方法非常簡單,我們只需要在@Async注解中指定線程池名即可,比如:

package com.winner.service; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit; /** * @author winner_0715 * @date 2018/12/06 */ @Service public class TaskServer { @Async("taskExecutor") public void doTaskA() throws InterruptedException { System.out.println("MsgServer send A thread name->" + Thread.currentThread().getName()); Long startTime = System.currentTimeMillis(); TimeUnit.SECONDS.sleep(2); Long endTime = System.currentTimeMillis(); System.out.println("MsgServer send A 耗時:" + (endTime - startTime)); } @Async("taskExecutor") public void doTaskB() throws InterruptedException { System.out.println("MsgServer send B thread name->" + Thread.currentThread().getName()); Long startTime = System.currentTimeMillis(); TimeUnit.SECONDS.sleep(2); Long endTime = System.currentTimeMillis(); System.out.println("MsgServer send B耗時:" + (endTime - startTime)); } }

測試

package com.winner.web; import com.winner.service.TaskServer; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; /** * @author winner_0715 * @description: * @date 2018/12/6 */ @RestController public class HelloController { @Resource private TaskServer taskServer; @GetMapping("/async") public String testAsync() throws Exception { System.out.println("主線程 name -->" + Thread.currentThread().getName()); taskServer.doTaskA(); taskServer.doTaskB(); return "Hello World"; } }

測試結果:

主線程 name -->http-nio-8080-exec-1 MsgServer send A thread name->async-task-name-0 MsgServer send B thread name->async-task-name-1 MsgServer send A 耗時:2001 MsgServer send B耗時:2001

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM