Spring中實現非同步呼叫的方式有哪些?
一位3年工作經驗的小夥伴被問到這樣一道面試題,說Spring中實現非同步呼叫的方式有哪些?
今天,我給大家分享一下我的理解。
在Spring中,實現非同步呼叫主要有三種方式,分別是註解方式、內建執行緒池方式和自定義執行緒池方式。
1、註解方式
可以在配置類和方法上加特定註解。首先,在配置類加上@EnableAsync來啟用非同步註解,
如程式碼所示:
@EnableAsync//啟用非同步支援 @Configuration public class AppConfig { }
然後,使用@Async註解標記需要非同步執行的方法,
如程式碼所示:
@Async void doSomething() { // this will be run asynchronously } @Async void doSomething(String s) { // this will be run asynchronously } @Async Future<String> returnSomething(int i) { // this will be run asynchronously }
使用@Async標記的非同步方法可以帶引數,也可以帶有返回值。返回值型別必須是java.util.concurrent.Future或其子類,可以是以下3種類型:
1)由Java原生API提供的Future。
2)由Spring提供的ListenableFuture後者AsyncResult。
3)Java 8提供的CompletableFuture。
需要說明的是,@Async預設會使用SimpleAsyncTaskExecutor來執行,而這個執行緒池不會複用執行緒。所以,通常要使用非同步處理,我們都會自定義執行緒池。
2、內建執行緒池方式
可以使用Spring內建的執行緒池來實現非同步呼叫,比如ThreadPoolTaskExecutor 和SimpleAsyncTaskExecutor。Spring提供了許多TaskExecutor的內建實現。下面簡單介紹5種內建的執行緒池。
1)SimpleAsyncTaskExecutor:它不會複用執行緒,每次呼叫都是啟動一個新執行緒。
2)ConcurrentTaskExecutor:它是Java API中Executor例項的介面卡。
3)ThreadPoolTaskExecutor:這個執行緒池是最常用的。它公開了用於配置的bean屬性,並將它包裝在TaskExecutor中。
4)WorkManagerTaskExecutor:它基於CommonJ WorkManager來實現的,並且是在Spring上下文中的WebLogic或WebSphere中設定CommonJ執行緒池的工具類。
5)DefaultManagedTaskExecutor:主要用於支援JSR-236相容的執行時環境,它是使用JNDI獲得ManagedExecutorService,作為CommonJ WorkManager的替代方案。
通常情況下,ThreadPoolTaskExecuto最為常用,只要當ThreadPoolTaskExecutor不能滿足需求時,可以使用ConcurrentTaskExecutor。如果在程式碼中聲明瞭多個執行緒池,Spring會預設按照以下搜尋順序來呼叫執行緒池:
第一步,檢查上下文中的唯一TaskExecutor Bean。
第二步,檢查名為“ taskExecutor”的Executor Bean。
第三步,以上都無法無法處理,就會使用SimpleAsyncTaskExecutor來執行。
3、自定義執行緒池方式
可以通過實現AsyncConfigurer介面或者直接繼承AsyncConfigurerSupport類來自定義執行緒池。但是非完全託管的Bean和完全託管的Bean實現方式有點小差異。
首先,來看非完全託管的Spring Bean,實現方式如程式碼所示:
@Configuration @EnableAsync public class AppConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(7); executor.setMaxPoolSize(42); executor.setQueueCapacity(11); executor.setThreadNamePrefix("MyExecutor-"); executor.initialize();//手動初始化 return executor; } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new MyAsyncUncaughtExceptionHandler(); } }
在這段程式碼中,ThreadPoolTaskExecutor不是完全託管的Spring bean。
然後,來看完全託管的Spring Bean,實現方式如程式碼所示:
@Configuration @EnableAsync public class AppConfig implements AsyncConfigurer { @Bean @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(7); executor.setMaxPoolSize(42); executor.setQueueCapacity(11); executor.setThreadNamePrefix("MyExecutor-"); //executor.initialize();//不用手動呼叫 return executor; } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new MyAsyncUncaughtExceptionHandler(); } }
只要在非同步方法上新增@Bean註解,不需要手動呼叫執行緒池的initialize()方法,在Bean在初始化之後會自動呼叫。需要注意的是,在同級類中直接呼叫非同步方法無法實現非同步。
以上就是我對Spring實現非同步呼叫的理解。
- Spring中實現非同步呼叫的方式有哪些?
- 帶引數的全型別 Python 裝飾器
- 整理了幾個Python正則表示式,拿走就能用!
- SOLID:開閉原則Go程式碼實戰
- React中如何引入CSS呢
- 一個新視角:前端框架們都卷錯方向了?
- 編碼中的Adapter,不僅是一種設計模式,更是一種架構理念與解決方案
- 手寫程式語言-遞迴函式是如何實現的?
- 一文搞懂模糊匹配:定義、過程與技術
- 新來個阿里 P7,僅花 2 小時,做出一個多執行緒永動任務,看完直接跪了
- Puzzlescript,一種開發H5益智遊戲的引擎
- @Autowired和@Resource到底什麼區別,你明白了嗎?
- CSS transition 小技巧!如何保留 hover 的狀態?
- React如此受歡迎離不開這4個主要原則
- LeCun再炮轟Marcus: 他是心理學家,不是搞AI的
- Java保證執行緒安全的方式有哪些?
- 19個殺手級 JavaScript 單行程式碼,讓你看起來像專業人士
- Python 的"self"引數是什麼?
- 別整一坨 CSS 程式碼了,試試這幾個實用函式
- 再有人問你什麼是MVCC,就把這篇文章發給他!