如果我的机器只有 10 个物理线程并且 JVM 线程映射到操作系统线程,我无法理解 JVM 如何在我的机器上运行 100 个线程。好吧,我认为的唯一答案是时间切片。但事实并非如此。我创建了一个简单的 Spring Boot 应用程序,它从另一台服务器获取响应,产生 3 秒的延迟。我在 application.properties 中使用 server.tomcat.threads.max=10 运行代码,而没有使用它。区别就是白天和黑夜。
server.tomcat.threads.max=10 -
>ab -n 1000 -c 100 http://localhost:8080/block
This is ApacheBench, Version 2.3 <$Revision: 1913912 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests
Server Software:
Server Hostname: localhost
Server Port: 8080
Document Path: /block
Document Length: 39 bytes
Concurrency Level: 100
Time taken for tests: 304.367 seconds
Complete requests: 1000
Failed requests: 100
(Connect: 0, Receive: 0, Length: 100, Exceptions: 0)
Total transferred: 172100 bytes
HTML transferred: 39100 bytes
Requests per second: 3.29 [#/sec] (mean)
Time per request: 30436.732 [ms] (mean)
Time per request: 304.367 [ms] (mean, across all concurrent requests)
Transfer rate: 0.55 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.7 0 7
Processing: 3031 28738 4956.5 30102 30238
Waiting: 3028 28738 4956.8 30101 30238
Total: 3034 28739 4955.9 30102 30239
Percentage of the requests served within a certain time (ms)
50% 30102
66% 30112
75% 30120
80% 30134
90% 30174
95% 30205
98% 30223
99% 30230
100% 30239 (longest request)
没有 server.tomcat.threads.max=10 -
ab -n 1000 -c 100 http://localhost:8080/block
This is ApacheBench, Version 2.3 <$Revision: 1913912 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking localhost (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests
Server Software:
Server Hostname: localhost
Server Port: 8080
Document Path: /block
Document Length: 39 bytes
Concurrency Level: 100
Time taken for tests: 33.435 seconds
Complete requests: 1000
Failed requests: 909
(Connect: 0, Receive: 0, Length: 909, Exceptions: 0)
Total transferred: 173415 bytes
HTML transferred: 40415 bytes
Requests per second: 29.91 [#/sec] (mean)
Time per request: 3343.475 [ms] (mean)
Time per request: 33.435 [ms] (mean, across all concurrent requests)
Transfer rate: 5.07 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 1.0 0 11
Processing: 3002 3023 15.7 3021 3172
Waiting: 3002 3023 15.6 3020 3168
Total: 3002 3024 16.3 3021 3172
Percentage of the requests served within a certain time (ms)
50% 3021
66% 3026
75% 3029
80% 3031
90% 3041
95% 3063
98% 3075
99% 3078
100% 3172 (longest request)
那么如果 JVM 线程不是平台线程,那么 Java 虚拟线程从何而来呢?当我在启用虚拟线程的情况下进行测试时,它给出了与平台线程相同的结果。
-编辑: 我知道应用程序正在创建数百个线程,因为我正在记录线程。我还了解到 server.tomcat.threads.max 默认值为 200。但话又说回来,如果我的机器只有 10 个物理线程,这 200 个线程的运行速度如何显着加快?
这并没有什么魔力;它实际上是基于时间切片的。你的物理机只有 10 个物理线程,但当你的 JVM 线程超过 10 个时,你会看到响应时间显着改善,这是因为你的服务负载是 I/O 密集型的——它是一个 I/O 密集型程序。 I/O 不会消耗 CPU 时间片,因为现代操作系统异步处理 I/O(这与您使用的编程语言无关;在较低级别,它是由中断触发的,而不是由 CPU 在繁忙循环中等待) .
您可以考虑将服务负载更改为类似 for 循环的内容,例如运行 10^9 次迭代。在这种情况下,当并发请求数超过物理线程数时,您会发现将 JVM 线程数增加到超过物理线程数并不能缩短响应时间。事实上,随着线程数的增加,响应时间可能会逐渐增加,因为物理线程的数量并没有增加,而添加虚拟线程又引入了上下文切换的开销。