Java21在spring boot中使用虛擬線程的方法
前置知識(shí)
0.環(huán)境說(shuō)明
用于驗(yàn)證的版本:
- spring boot: 3.3.3
- jdk: OpenJDK 21.0.5
spring boot 3.1中就支持使用jdk21的虛擬線程了,但是在spring boot 3.2中可以直接通過(guò)配置的方式開(kāi)啟虛擬線程。不過(guò)本文編寫(xiě)的時(shí)候spring boot 3.3.3已經(jīng)GA了,他在3.2的基礎(chǔ)上又對(duì)虛擬線程進(jìn)行了進(jìn)一步地適配,所以本文章中的版本為3.3
在spring boot 3.2.9中配置
spring.threads.virtual.enabled=true即可啟用虛擬線程
1.原理解析
開(kāi)啟了這個(gè)配置后,對(duì)我們的spring boot服務(wù)有什么影響呢?
我們?cè)趕pring boot的源碼中搜索spring.threads.virtual.enabled即可看到這個(gè)配置在spring boot中生效在了什么地方。
首先我們可以看到如下的代碼(通過(guò)代碼注釋也能看出,這個(gè)配置就是在3.2.0引入的)
/**
* Threading of the application.
*
* @author Moritz Halbritter
* @since 3.2.0
*/
public enum Threading {
/**
* Platform threads. Active if virtual threads are not active.
*/
PLATFORM {
@Override
public boolean isActive(Environment environment) {
return !VIRTUAL.isActive(environment);
}
},
/**
* Virtual threads. Active if {@code spring.threads.virtual.enabled} is {@code true}
* and running on Java 21 or later.
*/
VIRTUAL {
@Override
public boolean isActive(Environment environment) {
return environment.getProperty("spring.threads.virtual.enabled", boolean.class, false)
&& JavaVersion.getJavaVersion().isEqualOrNewerThan(JavaVersion.TWENTY_ONE);
}
};
/**
* Determines whether the threading is active.
* @param environment the environment
* @return whether the threading is active
*/
public abstract boolean isActive(Environment environment);
}接下來(lái)我們看一下VIRTUAL.isActive(environment)這個(gè)方法都用在了哪里(哪里用到了,就說(shuō)明哪里的虛擬線程是通過(guò)這個(gè)配置生效的)
可以看到他被用在如下的地方:
- spring-webflux(區(qū)別于spring web的一個(gè)響應(yīng)式web開(kāi)發(fā)框架)的阻塞配置中(如果阻塞了使用什么類型的線程去進(jìn)行阻塞)
- 注解
ConditionalOnThreading的判斷條件OnThreadingCondition- Rabbit MQ——一個(gè)消息隊(duì)列,啟用虛擬線程則執(zhí)行
configurer.setTaskExecutor(new VirtualThreadTaskExecutor("rabbit-direct-"));和configurer.setTaskExecutor(new VirtualThreadTaskExecutor("rabbit-simple-")); - JedisConnection——一個(gè)redis客戶端,啟用虛擬線程則執(zhí)行
SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor("redis-"); executor.setVirtualThreads(true); factory.setExecutor(executor); - LettuceConnection——一個(gè)redis客戶端,啟用虛擬線程則執(zhí)行和Jedis類似的代碼,都是把Executor設(shè)置為一個(gè)啟用了虛擬線程的
new SimpleAsyncTaskExecutor("redis-"); - Kafka——一個(gè)消息隊(duì)列,啟用虛擬線程則執(zhí)行和Jedis類似的兩碼,把Executor設(shè)置為一個(gè)啟用了虛擬線程的
new SimpleAsyncTaskExecutor("kafka-"); - TaskExecutorConfigurations——spring boot中的任務(wù)調(diào)度器配置類,
@Async(異步任務(wù)注解)所注解的方法會(huì)根據(jù)配置決定是用平臺(tái)線程執(zhí)行還是虛擬線程執(zhí)行 - TaskSchedulingConfigurations——spring boot中定時(shí)任務(wù)配置類,
@Scheduled(定時(shí)任務(wù)注解)所注解的方法會(huì)根據(jù)配置決定是用平臺(tái)線程執(zhí)行還是虛擬線程執(zhí)行 - EmbeddedWebServerFactoryCustomizerAutoConfiguration——通常我們最關(guān)心的地方,這里定義了spring web的默認(rèn)容器tomcat的線程配置(Jetty的工作線程配置也在一起),如果開(kāi)啟了虛擬線程,則tomcat會(huì)使用虛擬線程作為執(zhí)行器(再也不用考慮tomcat默認(rèn)200線程的問(wèn)題了?。。。?/li>
- Rabbit MQ——一個(gè)消息隊(duì)列,啟用虛擬線程則執(zhí)行
- Pulsar:一個(gè)分布式消息流平臺(tái),啟用虛擬線程則執(zhí)行
containerProperties.setConsumerTaskExecutor(new VirtualThreadTaskExecutor("pulsar-consumer-"));和readerContainerProperties.setReaderTaskExecutor(new VirtualThreadTaskExecutor("pulsar-reader-"));
2.spring boot的方案
通過(guò)在spring boot的源碼搜索@ConditionalOnThreading(Threading.VIRTUAL),可以看到spring boot會(huì)根據(jù)虛擬線程的開(kāi)啟與否來(lái)選擇注入不同的bean,我們以spring-data-redis為例,其具體代碼如下:
@Bean
@ConditionalOnMissingBean(RedisConnectionFactory.class)
@ConditionalOnThreading(Threading.PLATFORM)
LettuceConnectionFactory redisConnectionFactory(
ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers,
ClientResources clientResources) {
return createConnectionFactory(builderCustomizers, clientResources);
}
@Bean
@ConditionalOnMissingBean(RedisConnectionFactory.class)
@ConditionalOnThreading(Threading.VIRTUAL)
LettuceConnectionFactory redisConnectionFactoryVirtualThreads(
ObjectProvider<LettuceClientConfigurationBuilderCustomizer> builderCustomizers,
ClientResources clientResources) {
LettuceConnectionFactory factory = createConnectionFactory(builderCustomizers, clientResources);
SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor("redis-");
executor.setVirtualThreads(true);
factory.setExecutor(executor);
return factory;
}通過(guò)代碼不難看出,spring boot 3.2通過(guò)@ConditionalOnThreading注解的方式,實(shí)現(xiàn)了虛擬線程和平臺(tái)線程的動(dòng)態(tài)配置。
如果我們自己需要開(kāi)發(fā)一個(gè)能夠同時(shí)支持平臺(tái)線程和虛擬線程的sdk,可以復(fù)用這個(gè)注解。
3.注意事項(xiàng)(施工中,歡迎補(bǔ)充)
- 使用虛擬線程本身要注意的5個(gè)點(diǎn):
- 大方使用“一個(gè)請(qǐng)求一個(gè)線程”的開(kāi)發(fā)方式
- 不需要對(duì)虛擬線程進(jìn)行池化
- 使用信號(hào)量控制并發(fā)
- 慎用ThreadLocal,使用ScopeValue(java21中還是預(yù)覽狀態(tài))代替
- 使用ReturnLock替代synchronized(這個(gè)問(wèn)題似乎在jdk23中會(huì)永久解決)
- java21默認(rèn)的垃圾回收器G1和其自身的JIT編譯器C2似乎有沖突,會(huì)導(dǎo)致jvm crash?(這里不能確定,似乎在高版本jdk 21.0.7中進(jìn)行了修復(fù),但是我比較了openjdk的源碼,并沒(méi)能找到具體的改動(dòng)指向這個(gè)問(wèn)題)
到此這篇關(guān)于Java21在spring boot中使用虛擬線程的方法的文章就介紹到這了,更多相關(guān)springboot使用虛擬線程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java實(shí)現(xiàn)優(yōu)雅日期處理的方案詳解
在我們的日常工作中,需要經(jīng)常處理各種格式,各種類似的的日期或者時(shí)間,下面我們就來(lái)看看如何使用java處理這樣的日期問(wèn)題吧,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-04-04
Java中使用ConcurrentHashMap實(shí)現(xiàn)線程安全的Map
在Java中,ConcurrentHashMap是一種線程安全的哈希表,可用于實(shí)現(xiàn)多線程環(huán)境下的Map操作。它支持高并發(fā)的讀寫(xiě)操作,通過(guò)分段鎖的方式實(shí)現(xiàn)線程安全,同時(shí)提供了一些高級(jí)功能,比如迭代器弱一致性和批量操作等。ConcurrentHashMap在高并發(fā)場(chǎng)景中具有重要的應(yīng)用價(jià)值2023-04-04
Mybatis結(jié)果集映射與生命周期詳細(xì)介紹
結(jié)果集映射指的是將數(shù)據(jù)表中的字段與實(shí)體類中的屬性關(guān)聯(lián)起來(lái),這樣 MyBatis 就可以根據(jù)查詢到的數(shù)據(jù)來(lái)填充實(shí)體對(duì)象的屬性,幫助我們完成賦值操作2022-10-10
詳解SpringBoot 快速整合MyBatis(去XML化)
本篇文章主要介紹了詳解SpringBoot 快速整合MyBatis(去XML化),非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-10-10
SpringCloud客戶端的負(fù)載均衡Ribbon的實(shí)現(xiàn)
微服務(wù)架構(gòu),不可避免的存在單個(gè)微服務(wù)有多個(gè)實(shí)例,這篇文章主要介紹了SpringCloud客戶端的負(fù)載均衡Ribbon的實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06
關(guān)于@CacheEvict無(wú)法解決分頁(yè)緩存清除的解決思路
這篇文章主要介紹了關(guān)于@CacheEvict無(wú)法解決分頁(yè)緩存清除的解決思路,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
SpringBoot整合Guava Cache實(shí)現(xiàn)全局緩存的示例代碼
這篇文章主要介紹了SpringBoot整合Guava Cache實(shí)現(xiàn)全局緩存,Guava Cache是Google Guava庫(kù)中的一個(gè)模塊,提供了基于內(nèi)存的本地緩存實(shí)現(xiàn),文中介紹了SpringBoot整合使用Guava Cache的具體步驟,需要的朋友可以參考下2024-03-03
Mybatis-plus 雙主鍵的實(shí)現(xiàn)示例
本文主要介紹了Mybatis-plus 雙主鍵的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-05-05

