SpringBoot如何實(shí)現(xiàn)并發(fā)任務(wù)并返回結(jié)果
SpringBoot并發(fā)任務(wù)并返回結(jié)果
并發(fā)的實(shí)現(xiàn)以及結(jié)果獲取
并發(fā)即多個(gè)線程同時(shí)進(jìn)行任務(wù),即異步任務(wù),以下例子測(cè)試了并發(fā)進(jìn)行四個(gè)任務(wù),并同時(shí)返回結(jié)果的案例。
service層
@Service public class AsyncTest { ? ? ? ? @Async ? ? ? ? public Future<Boolean> doReturn1(){ ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? // 這個(gè)方法需要調(diào)用500毫秒 ? ? ? ? ? ? ? ? Thread.sleep(500); ? ? ? ? ? ? } catch (InterruptedException e) { ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? } ? ? ? ? ? ? for (int i = 0; i < 10; i++) { ? ? ? ? ? ? ? ? System.out.println("一號(hào)線程:"+i); ? ? ? ? ? ? } ? ? ? ? ? ? // 消息匯總 ? ? ? ? ? ? return new AsyncResult<>(true); ? ? ? ? } ? ? ? ? @Async ? ? ? ? public Future<Boolean> doReturn2(){ ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? // 這個(gè)方法需要調(diào)用500毫秒 ? ? ? ? ? ? ? ? Thread.sleep(500); ? ? ? ? ? ? } catch (InterruptedException e) { ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? } ? ? ? ? ? ? for (int i = 0; i < 10; i++) { ? ? ? ? ? ? ? ? System.out.println("二號(hào)線程:"+i); ? ? ? ? ? ? } ? ? ? ? ? ? // 消息匯總 ? ? ? ? ? ? return new AsyncResult<>(true); ? ? ? ? } ? ? ? ? @Async ? ? ? ? public Future<Boolean> doReturn3(){ ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? // 這個(gè)方法需要調(diào)用500毫秒 ? ? ? ? ? ? ? ? Thread.sleep(500); ? ? ? ? ? ? } catch (InterruptedException e) { ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? } ? ? ? ? ? ? for (int i = 0; i < 10; i++) { ? ? ? ? ? ? ? ? System.out.println("三號(hào)線程:"+i); ? ? ? ? ? ? } ? ? ? ? ? ? // 消息匯總 ? ? ? ? ? ? return new AsyncResult<>(true); ? ? ? ? } ? ? ? ? @Async ? ? ? ? public Future<Boolean> doReturn4(){ ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? // 這個(gè)方法需要調(diào)用500毫秒 ? ? ? ? ? ? ? ? Thread.sleep(500); ? ? ? ? ? ? } catch (InterruptedException e) { ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? } ? ? ? ? ? ? for (int i = 0; i < 10; i++) { ? ? ? ? ? ? ? ? System.out.println("四號(hào)線程:"+i); ? ? ? ? ? ? } ? ? ? ? ? ? // 消息匯總 ? ? ? ? ? ? return new AsyncResult<>(true); ? ? ? ? } }
controller層
@RequestMapping("/async") ? ? public String async(){ ? ? ? ? List<Future<Boolean>> futures = new ArrayList<>(); ? ? ? ? Future<Boolean> flag1 = asyncTest.doReturn1(); ? ? ? ? Future<Boolean> flag2 = asyncTest.doReturn2(); ? ? ? ? Future<Boolean> flag3 = asyncTest.doReturn3(); ? ? ? ? Future<Boolean> flag4 = asyncTest.doReturn4(); ? ? ? ? futures.add(flag1); ? ? ? ? futures.add(flag2); ? ? ? ? futures.add(flag3); ? ? ? ? futures.add(flag4); ? ? ? ? List<Boolean> response = new ArrayList<>(); ? ? ? ? for (Future future : futures) { ? ? ? ? ? ? Boolean flag = null; ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? flag = (Boolean) future.get(); ? ? ? ? ? ? } catch (InterruptedException e) { ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? } catch (ExecutionException e) { ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? } ? ? ? ? ? ? response.add(flag); ? ? ? ? } ? ? ? ? System.out.println(response); ? ? ? ? return response.toString(); ? ? }
這種方法即可在并發(fā)的時(shí)候攔截到全部完成后的結(jié)果進(jìn)行判斷,滿足才進(jìn)行下一步。
SpringBoot并發(fā)配置
Spring Boot 提供了一些默認(rèn)的并發(fā)配置,可以通過配置文件或代碼進(jìn)行調(diào)整。
下面介紹一些常用的 Spring Boot 并發(fā)配置:
線程池配置
可以在 application.properties 或 application.yml 文件中配置線程池的參數(shù),例如最大線程數(shù)、核心線程數(shù)等:
# application.yml spring: ? task: ? ? execution: ? ? ? pool: ? ? ? ? max-threads: 10 ? ? ? ? core-threads: 5
異步處理配置
可以通過 @EnableAsync 注解開啟異步處理,并且可以配置線程池的參數(shù):
@Configuration @EnableAsync public class AppConfig { ? ? @Bean ? ? public Executor taskExecutor() { ? ? ? ? ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); ? ? ? ? executor.setCorePoolSize(5); ? ? ? ? executor.setMaxPoolSize(10); ? ? ? ? executor.setQueueCapacity(25); ? ? ? ? return executor; ? ? } }
WebMvc 配置
可以通過配置 WebMvcConfigurerAdapter 來配置 Spring Boot 的 MVC 框架的線程池大小和異步處理:
@Configuration public class WebMvcConfig extends WebMvcConfigurerAdapter { ? ? @Override ? ? public void configureAsyncSupport(final AsyncSupportConfigurer configurer) { ? ? ? ? configurer.setTaskExecutor(asyncTaskExecutor()); ? ? } ? ? @Bean ? ? public AsyncTaskExecutor asyncTaskExecutor() { ? ? ? ? ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); ? ? ? ? executor.setCorePoolSize(5); ? ? ? ? executor.setMaxPoolSize(50); ? ? ? ? executor.setQueueCapacity(100); ? ? ? ? executor.setThreadNamePrefix("MySpringAsyncThread-"); ? ? ? ? executor.initialize(); ? ? ? ? return executor; ? ? } }
Tomcat 連接器配置
Tomcat 是 Spring Boot 的默認(rèn) Web 服務(wù)器,可以通過配置 Tomcat 的連接器參數(shù)來進(jìn)行并發(fā)調(diào)優(yōu):
server: ? ? tomcat: ? ? ? ? max-connections:2000 ? ? ? ? max-threads:200 ? ? ? ? min-spare-threads:10 ? ? ? ? accept-count:100
undertow 配置
如果springboot 配置undertow作為web服務(wù)器 則可通過如下參數(shù)進(jìn)行并發(fā)調(diào)優(yōu)
? # undertow 配置 ? undertow: ? ? # HTTP post內(nèi)容的最大大小。當(dāng)值為-1時(shí),默認(rèn)值為大小是無限的 ? ? max-http-post-size: -1 ? ? # 以下的配置會(huì)影響buffer,這些buffer會(huì)用于服務(wù)器連接的IO操作,有點(diǎn)類似netty的池化內(nèi)存管理 ? ? # 每塊buffer的空間大小,越小的空間被利用越充分 ? ? buffer-size: 512 ? ? # 是否分配的直接內(nèi)存 ? ? direct-buffers: true ? ? threads: ? ? ? # 設(shè)置IO線程數(shù), 它主要執(zhí)行非阻塞的任務(wù),它們會(huì)負(fù)責(zé)多個(gè)連接, 默認(rèn)設(shè)置每個(gè)CPU核心一個(gè)線程 ? ? ? io: 8 ? ? ? # 阻塞任務(wù)線程池, 當(dāng)執(zhí)行類似servlet請(qǐng)求阻塞操作, undertow會(huì)從這個(gè)線程池中取得線程,它的值設(shè)置取決于系統(tǒng)的負(fù)載 ? ? ? worker: 256
其中 max-connections 表示最大連接數(shù),max-threads 表示最大線程數(shù),min-spare-threads 表示最小空閑線程數(shù),accept-count 表示請(qǐng)求等待隊(duì)列的大小。
綜上所述,可以通過線程池配置、異步處理配置、WebMvc 配置以及 Tomcat 連接器配置來調(diào)整 Spring Boot 應(yīng)用的并發(fā)性能和并發(fā)能力。在實(shí)際應(yīng)用中,需要結(jié)合具體的業(yè)務(wù)場景和系統(tǒng)架構(gòu)來進(jìn)行配置和優(yōu)化。
通常需要考慮硬件性能、IO模型、網(wǎng)絡(luò)、壓測(cè)、服務(wù)器監(jiān)控的實(shí)際數(shù)據(jù)。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
解決Spring?Security升級(jí)到5.5.7、5.6.4及以上啟動(dòng)報(bào)錯(cuò)出現(xiàn)版本不兼容的問題
這篇文章主要介紹了解決Spring?Security升級(jí)到5.5.7、5.6.4及以上啟動(dòng)報(bào)錯(cuò)出現(xiàn)版本不兼容的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08如何解決項(xiàng)目中java heap space的問題
這篇文章主要介紹了如何解決項(xiàng)目中java heap space的問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07使用?Spring?AI?+?Ollama?構(gòu)建生成式?AI?應(yīng)用的方法
通過集成SpringBoot和Ollama,本文詳細(xì)介紹了如何構(gòu)建生成式AI應(yīng)用,首先,介紹了AI大模型服務(wù)的兩種實(shí)現(xiàn)方式,選擇使用ollama進(jìn)行部署,隨后,通過SpringBoot+SpringAI來實(shí)現(xiàn)應(yīng)用構(gòu)建,本文為開發(fā)者提供了一個(gè)實(shí)用的指南,幫助他們快速入門生成式AI應(yīng)用的開發(fā)2024-11-11Mybatis的Mapper代理對(duì)象生成及調(diào)用過程示例詳解
這篇文章主要為大家介紹了Mybatis的Mapper代理對(duì)象生成及調(diào)用過程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09保證緩存和數(shù)據(jù)庫的數(shù)據(jù)一致性詳解
在實(shí)際開發(fā)過程中,緩存的使用頻率是非常高的,只要使用緩存和數(shù)據(jù)庫存儲(chǔ),就難免會(huì)出現(xiàn)雙寫時(shí)數(shù)據(jù)一致性的問題,本文主要介紹了如何保證緩存和數(shù)據(jù)庫的數(shù)據(jù)一致性,需要的小伙伴可以參考閱讀2023-04-04