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


1. 為什么要異步

當我們開發中涉及短信發送,郵件發送等耗時請求時可以通過執行異步操作,從而加快請求響應,使用戶體驗更友好

2. 具體操作

創建springboot項目引入weblombok
完整的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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>thread-pool-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>thread-pool-demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.1 配置application.yml

#線程池配置參數
task:
  pool:
    corePoolSize: 5 #設置核心線程數
    maxPoolSize: 20  #設置最大線程數
    keepAliveSeconds: 300 #設置線程活躍時間(秒)
    queueCapacity: 50 #設置隊列容量
    threadNamePrefix: # 線程名稱前綴

2.2 編寫線程池配置類

@ConfigurationProperties(prefix = "task.pool")
@Data
public class TaskThreadPoolConfig {
    private int corePoolSize;           // 核心線程數(默認線程數)
    private int maxPoolSize;              // 最大線程數
    private int keepAliveTime;         // 允許線程空閑時間(單位:默認為秒)
    private int queueCapacity;        // 緩沖隊列數
    private String threadNamePrefix; // 線程池名前綴
}

2.3 在啟動類上開啟線程異步支持

@SpringBootApplication
@EnableAsync        //開啟線程異步支持
@EnableConfigurationProperties({TaskThreadPoolConfig.class}) // 引入自定義線程池配置
public class ThreadPoolDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(ThreadPoolDemoApplication.class, args);
    }

}

2.4 創建自定義線程池

@Configuration
public class MyThreadPoolTaskExecutor {
    @Autowired
    private TaskThreadPoolConfig config;

    /**
     * 默認異步線程池
     *
     * @return
     */
    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
        pool.setThreadNamePrefix(config.getThreadNamePrefix());
        pool.setCorePoolSize(config.getCorePoolSize());
        pool.setMaxPoolSize(config.getMaxPoolSize());
        pool.setKeepAliveSeconds(config.getKeepAliveTime());
        pool.setQueueCapacity(config.getQueueCapacity());
        // 直接在execute方法的調用線程中運行
        pool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任務結束后再關閉線程池
        pool.setWaitForTasksToCompleteOnShutdown(true);
        // 初始化
        pool.initialize();
        return pool;
    }

}

2.5 編寫測試ServiceController

@Service
public class TaskService {
    @Async
    public void doTaskA() throws InterruptedException {
        System.out.println("TaskA thread name->" + Thread.currentThread().getName() + "start");
        Long startTime = System.currentTimeMillis();
        TimeUnit.SECONDS.sleep(3);
        Long endTime = System.currentTimeMillis();
        System.out.println("TaskA thread name->" + Thread.currentThread().getName() + "finish");
        System.out.println("TaskA 耗時:" + (endTime - startTime));
    }

    @Async
    public void doTaskB() throws InterruptedException {
        System.out.println("TaskB thread name->" + Thread.currentThread().getName() + "start");
        Long startTime = System.currentTimeMillis();
        TimeUnit.SECONDS.sleep(3);
        Long endTime = System.currentTimeMillis();
        System.out.println("TaskB thread name->" + Thread.currentThread().getName() + "finish");
        System.out.println("TaskB耗時:" + (endTime - startTime));
    }
}

@RestController
public class HelloController {
    @Autowired
    private TaskService taskService;

    @GetMapping("/async")
    public String testAsync() throws Exception {
        System.out.println("主線程 name -->" + Thread.currentThread().getName() + "start");
        Long startTime = System.currentTimeMillis();
        taskService.doTaskA();
        taskService.doTaskB();
        Long endTime = System.currentTimeMillis();
        System.out.println("主線程 name -->" + Thread.currentThread().getName() + "finish");
        System.out.println("主線程" + Thread.currentThread().getName() + "耗時:" + (endTime - startTime));
        return "Hello World";
    }
}

測試結果

代碼

微雲下載

參考

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


免責聲明!

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



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