当请求 url 相同并使用 CompletableFuture 处理时,为什么 Tomcat 使用不同的线程?

Why Tomcat is using different threads when request url is same and handled with CompletableFuture?

我使用 CompletableFuture 在 github 中使用了 this sample

我同时在浏览器 (chrome) 的多个选项卡中尝试了 运行 /asyncCompletable 端点。 关键是 Tomcat 是 Servlet 容器,它有自己的 Servlet 线程池,因此从浏览器的不同选项卡访问相同的端点 url 不一定使用相同的主线程。在下面查看我的控制台日志:

8:07:07.334 [http-nio-9191-exec-8] Request received
18:07:07.335 [http-nio-9191-exec-8] Servlet thread released
18:07:07.335 [ForkJoinPool.commonPool-worker-3] Start processing request
18:07:08.262 [http-nio-9191-exec-7] Request received
18:07:08.262 [http-nio-9191-exec-7] Servlet thread released
18:07:08.262 [ForkJoinPool.commonPool-worker-4] Start processing request
18:07:08.860 [http-nio-9191-exec-9] Request received
18:07:08.861 [http-nio-9191-exec-9] Servlet thread released
18:07:08.861 [ForkJoinPool.commonPool-worker-5] Start processing request
18:07:09.376 [http-nio-9191-exec-10] Request received
18:07:09.377 [http-nio-9191-exec-10] Servlet thread released

如您所见,它为同一 URL 的每个浏览器选项卡使用不同的线程,而不是将已释放的线程重新用于进一步的调用。 我的意思是它不会为下一个传入请求重用已释放的线程(例如 http-nio-9191-exec-7)。 这是为什么?

线程池就是它所说的 - 一个池。因此,不能保证池中 re-address 同一线程与任务相同,也没有任何帮助。该池只是 return 池中的下一个可用线程。但是“下一个”是什么意思?这取决于池的实现——这应该从用户那里抽象出来。仅仅因为它没有直接重新分配下一个请求并不意味着它永远不会被重用。池决定如何执行此操作。这取决于池的策略。因此,Servlet 池中可能存在一些时间余量或阈值或一些队列。

当您重新配置 Tomcat 以进行评估时,如果行为发生变化,您可以尝试:

<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="150" minSpareThreads="0"/>

但这对性能没有帮助,不建议这样做。除非有充分的理由,否则我不会弄乱 Servlet 线程池机制。池是出于充分的理由移交该控制权。