在 Spring Boot 中,默認的線程池配置由?TaskExecutionAutoConfiguration
?類提供,使用的是?SimpleAsyncTaskExecutor
。
SimpleAsyncTaskExecutor特點
-
每次調用創建新線程:
SimpleAsyncTaskExecutor
?每次執行任務時都會創建一個新線程,不會重用線程。這使得它非常簡單,但在高并發情況下可能會導致大量的線程被創建。 -
線程命名:
可以通過?setThreadNamePrefix
?方法設置線程名前綴,這對調試和監控有幫助。 -
無需線程池:
不像?ThreadPoolTaskExecutor
,SimpleAsyncTaskExecutor
?不使用線程池管理線程。 -
并發控制:
沒有隊列、沒有核心線程數或最大線程數的限制。當需要創建的線程數量大于并發數時,會等待,等待有任務結束,才創建新線程。如果我們不設置并發數量,那么每次就會直接創建新線程(無限創建)。
使用場景
由于?SimpleAsyncTaskExecutor
?的簡單性,它適用于以下場景:
開發和測試:
在開發和測試環境中快速驗證異步任務的執行,而不需要復雜的線程池配置。
-
低并發任務:
適用于任務數量較少、執行頻率較低的場景。 -
臨時任務:
適用于臨時的、一次性的任務。
注意事項
使用?SimpleAsyncTaskExecutor
?時需要注意以下幾點:
-
高并發性能問題:
由于每次任務都會創建一個新線程,這可能會導致大量線程被創建,增加資源開銷。因此,不適合高并發場景。 -
線程管理:
由于沒有線程池管理,線程的創建和銷毀開銷較大,可能導致性能問題。 -
內存消耗:
大量創建新線程可能會導致內存消耗過大,需謹慎使用。 -
線程命名:
為了便于調試和監控,建議設置線程名前綴。
結論:
實際項目中我們應該盡量避免使用SimpleAsyncTaskExecutor,使用其他真正的線程池,比如jdk 的 ThreadPoolTaskExecutor?
創建一個配置類來定義?ThreadPoolTaskExecutor
?bean。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.Executor;@Configuration
public class ThreadPoolConfig {@Bean(name = "taskExecutor")public Executor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5); // 核心線程數executor.setMaxPoolSize(10); // 最大線程數executor.setQueueCapacity(25); // 隊列容量executor.setThreadNamePrefix("MyExecutor-"); // 線程名前綴executor.initialize();return executor;}
}
在你的主應用類或任意配置類上啟用異步支持。?
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;@SpringBootApplication
@EnableAsync
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
在需要使用異步任務的服務類中,通過?@Async
?注解使用配置好的線程池。
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;@Service
public class MyService {@Async("taskExecutor")public void asyncMethod() {System.out.println("Execute method asynchronously - " + Thread.currentThread().getName());// 模擬長時間任務try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Async method completed - " + Thread.currentThread().getName());}
}