我正try 在SpringBoot3.2和RestClient上使用虚拟线程并行调用两个外部服务,但我不确定简单地按顺序调用它们或使用future 是否正确.我的应用程序.properties已经包含:spring.threads.Viral.Enabled=True

简单地做是正确的吗:

String response1 = performGetRequest(uri1);  //RestClient get request
String response2 = performGetRequest(uri2);

return response1 + response2;

或者我需要做的是:

Future<String> response1 = performGetRequest(uri1);
Future<String> response2 = performGetRequest(uri2);

return response1.get() + response2.get();

另外,是否有必要将代码块包装在Try-With-Resources块中,或者没有必要,因为Spring已经 for each 任务使用了虚拟线程,因为在Application.Properties中启用了它?因此:

try (ExecutorService service = Executors.newVirtualThreadPerTaskExecutor();)

推荐答案

如果您可以在应用程序中使用虚拟线程,则更喜欢使用后一种方法,即invoke both the REST API calls using 101.在第#Represent Every Concurrent Task as a Virtual Thread; Never Pool Virtual Threads节下的虚拟线程文档中甚至提出了扇出场景的类似用例.

第一种方法

Spring本身将利用虚拟线程来处理向服务器发起的请求.这主要意味着每个请求都将被分配给一个由Tomcat处理的新虚拟线程,并且这些线程可以根据每个请求中执行的I/O切换到接受更高的吞吐量和并发性的其他请求.

但是,一旦为线程分配了请求(考虑跟踪request-id),它将执行所有后续同步步骤,直到它在同一线程内响应.如果日志(log)可以帮助您进行关联,则会产生如下输出:

GreetingsController       : 34ace5cc-2b6b-4226-a088-b5888fc30f99 : VirtualThread[#568,tomcat-handler-51]/runnable@ForkJoinPool-1-worker-10
WebPageService            : 34ace5cc-2b6b-4226-a088-b5888fc30f99 : tomcat-handler-51 : /uri1
WebPageService            : 34ace5cc-2b6b-4226-a088-b5888fc30f99 : tomcat-handler-51 : /uri2

二方法

通过使用newVirtualThreadPerTaskExecutor的方法,您可以将所有的服务调用作为一个任务并发地分配给一个新的虚拟线程.在这种情况下,应用程序会进一步为您提交的每个服务调用从common ForkJoinPool生成新的虚拟线程.以下是该 case 的日志(log)供参考:

GreetingsController       : ad39b86e-073c-479e-a5d8-ec35bbb34dac : VirtualThread[#575,tomcat-handler-54]/runnable@ForkJoinPool-1-worker-12
WebPageService            : ad39b86e-073c-479e-a5d8-ec35bbb34dac : VirtualThread[#576]/runnable@ForkJoinPool-1-worker-12: /uri1
WebPageService            : ad39b86e-073c-479e-a5d8-ec35bbb34dac : VirtualThread[#580]/runnable@ForkJoinPool-1-worker-12 : /uri2

Side Note -上述日志(log)中的线程名是在调试器的帮助下添加的.


此外,对于您有关试用资源的用法的问题,请引用引用的链接,总结新引入的ExecutorService.close:

close方法,在try 结束时隐式调用 块将自动等待提交给 ExecutorService-即由 ExecutorService-终止.

这肯定有助于释放其他线程使用的资源,并减少应用程序中任何可能的泄漏.

Java相关问答推荐

无法在Java中将hhmmss格式的时间解析为LocalTime

如果一个子类没有构造函数,超类也没有构造函数,那么为什么我可以构造子类的实例呢?

流迭代列表<;对象>;上的NoSuchElementException

Java 21虚拟线程执行器的性能比池化操作系统线程的执行器差?

更新GWT 2.5.1到2.11.0和sencha GXT 3.1.1到4.1时出现错误

具有阻塞方法的开源库是否应该为执行提供异步选项?

Oj算法 MatrixR032从字符串、归一化和余弦相似度计算创建

X=x*0.90;产生有损转换误差.X*=0.90;不是.为什么?

项目react 堆中doOnComplete()和Subscribe()的第三个参数之间的差异

如何在ImageIO或十二只猴子中旋转TIFF CMYK图像?

在应用程序运行时更改LookAndFeel

Java集合:NPE,即使没有添加空值

使用MediaPlayer类在一段时间后停止播放音乐

用于Java的Visual Studio代码完成不起作用

Java KeyListener不工作或被添加

根据应用程序 Select 的语言检索数据

如何正确使用java.time类?

Maven创建带有特定类的Spring Boot jar和普通jar

java构造函数中的冻结操作何时发生?

java.util.LinkedList()是如何成为MutableList的实例的?