I developed a microservice using Spring Boot. I was performance testing the service by stubbing the backend calls. When I looked at the thread count , I see that the maximum number of threads that created to the service is 20 at any point in time even though the number of calls made is much higher. Are there any limitations with respect to number of calls that can be made to a microservice developed using Spring Boot. Please can you guide in what steps I need to follow to troubleshoot / increase the number of connections accepted by the service?
-
2which container are you using ? Jetty, tomcat, nginx, undertow... ? – alexbt Aug 17 '16 at 17:05
-
1correct answer is `server.tomcat.threads.max` as @Couper comment below – duyetpt Sep 18 '22 at 08:35
5 Answers
This setting is derived from the embedded container (tomcat, jetty...).
Tomcat's number of threads
You may specify this property in your application.properties
server.tomcat.threads.max=400
You say you counted 20 threads, however according to this other stackoverflow question/answer, the default number of thread should be 200 with tomcat, since server.tomcat.max-threads's default value is 0. See tomcat's documentation:
The maximum number of request processing threads to be created by this Connector, which therefore determines the maximum number of simultaneous requests that can be handled. If not specified, this attribute is set to 200. If an executor is associated with this connector, this attribute is ignored as the connector will execute tasks using the executor rather than an internal thread pool.
Also, the property for:
undertow:
server.undertow.worker-threads
jetty:
server.jetty.acceptors
You'll find the list of properties in Spring's documentation
-
-
-
Not that I know of. I mean, server.tomcat.max-threads's default value is definitely 0, so it comes down to tomcat's value. What I would do If I were you is to try with a really big value (server.tomcat.max-threads=1000) and see if it makes a difference. – alexbt Aug 17 '16 at 17:33
-
@PunterVicky why do you need print it? Add application.properties to your resources dir and set there amout of thread. – eL_ Nov 02 '18 at 09:07
-
2You can inject `@Autowired private ServerProperties serverProperties;`, then see `serverProperties.tomcat.maxThreads`. But if you don't set it, the default value is 0 (`private int maxThreads = 0;`) – alexbt Dec 07 '18 at 17:11
-
3You can add spring boot actuator dependency to your project. Its a great tool that gives you a lot of environment information. The endpoint /env will provide you environment properties. – bram000 Feb 28 '19 at 10:38
-
Thank you very much! My application was spamming the MySQL server with useless sleeping threads. Now, I am able the control the threads. – madaimartin Oct 20 '20 at 11:43
-
14Since Spring Boot 2.3 the correct property is `server.tomcat.threads.max`. – Couper Aug 27 '21 at 18:16
-
can someone please update the answer based on @Couper's comment above – jathin sanghvi Jun 14 '22 at 20:42
Maybe, you can have a look at the springboot's config
server.tomcat.accept-count=100 # Maximum queue length for incoming connection requests when all possible request processing threads are in use.
server.tomcat.additional-tld-skip-patterns= # Comma-separated list of additional patterns that match jars to ignore for TLD scanning.
server.tomcat.background-processor-delay=10s # Delay between the invocation of backgroundProcess methods. If a duration suffix is not specified, seconds will be used.
server.tomcat.basedir= # Tomcat base directory. If not specified, a temporary directory is used.
server.tomcat.max-connections=10000 # Maximum number of connections that the server accepts and processes at any given time.
server.tomcat.max-http-header-size=0 # Maximum size in bytes of the HTTP message header.
server.tomcat.max-http-post-size=2097152 # Maximum size in bytes of the HTTP post content.
server.tomcat.max-threads=200 # Maximum amount of worker threads.
server.tomcat.min-spare-threads=10 # Minimum amount of worker threads.
server.tomcat.port-header=X-Forwarded-Port # Name of the HTTP header used to override the original port value.
server.tomcat.protocol-header= # Header that holds the incoming protocol, usually named "X-Forwarded-Proto".
server.tomcat.protocol-header-https-value=https # Value of the protocol header indicating whether the incoming request uses SSL.
server.tomcat.redirect-context-root=true # Whether requests to the context root should be redirected by appending a / to the path.
server.tomcat.remote-ip-header= # Name of the HTTP header from which the remote IP is extracted. For instance, `X-FORWARDED-FOR`.
server.tomcat.resource.cache-ttl= # Time-to-live of the static resource cache.
server.tomcat.uri-encoding=UTF-8 # Character encoding to use to decode the URI.
server.tomcat.use-relative-redirects= # Whether HTTP 1.1 and later location headers generated by a call to sendRedirect will use relative or absolute redirects.

- 1,718
- 20
- 15
-
2What is the difference between `accept-count` and `max-connections`? Shouldn't the `accept-count` be greater than `max-connections`? – Chloe Oct 24 '19 at 23:36
-
6`accept-count` is the connection request in the queue that waiting for process, this is the queue size.`max-connections` means the max connection count that can process at the same time, this is max connection size. Normally, `max-connections` should be greater than `accept-count`. – Bruce Oct 26 '19 at 04:23
-
1@Bruce server.tomcat.max-threads=200 if Maximum amount of worker threads is 200 then it can concurrently process 200 req at any time then how? – Swapan Shaw Mar 12 '21 at 13:10
While the accepted answer is very useful, I recently experienced what I believe to be the same problem as the original poster. This is the only search result I could find that directly correlated with my experience, so I thought I'd add my solution in case it helps someone.
In my case, the observed concurrency limit of 20 was imposed by the default setting of 20 for themaxConcurrentStreamExecution
property in org.apache.coyote.http2.Http2Protocol
.
If you're experiencing this problem and you're using HTTP/2, there's a good chance that increasing maxConcurrentStreamExecution
will help.
You can find more info in the Tomcat Configuration Reference, which actually states that this should be set to 200 by default (not 20). You can definitely see the default setting of 20 in org.apache.coyote.http2.Http2Protocol
, though, so I'm not sure if this is a typo or just something that presents itself differently in the embedded version of Tomcat.

- 749
- 1
- 7
- 19
-
1The documentation changed in the meantime and now states "20". So the observed behavior matches the documentation. – Mirko Jahn Mar 28 '19 at 23:53
-
I was going to ask how to use it, but looks like there is flag in spring boot server.http2.enabled=true – Kalpesh Soni Aug 08 '19 at 18:23
-
2It's important to notice that "maxConcurrentStreamExecution" refers to concurrent streams of a single connection over the HTTP 2 protocol, not the maximum connections that the container can accept. – Shlomi Uziel Jan 09 '21 at 22:06
If you have actuator you can see the metrics
/actuator/metrics/tomcat.threads.config.max
{
"name": "tomcat.threads.config.max",
"description": null,
"baseUnit": null,
"measurements": [{
"statistic": "VALUE",
"value": 200.0
}],
"availableTags": [{
"tag": "name",
"values": ["http-nio-8080"]
}]
}
The actual value tomcat decided to create? /actuator/metrics/tomcat.threads.current
you may see 10 there depending on the load
spring boot never seems to fully use max-threads you can however start with more
server:
tomcat:
min-spare-threads: 40

- 6,879
- 2
- 56
- 59
Increase maxConcurrentStreamExecution
(set 200) for HTTP/2 in Spring Boot 2:
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> containerCustomizer() {
return new WebServerFactoryCustomizer<TomcatServletWebServerFactory>() {
@Override
public void customize(TomcatServletWebServerFactory factory) {
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
@Override
public void customize(Connector connector) {
Arrays.stream(connector.getProtocolHandler().findUpgradeProtocols())
.filter(upgradeProtocol -> upgradeProtocol instanceof Http2Protocol)
.map(upgradeProtocol -> (Http2Protocol) upgradeProtocol)
.forEach(http2Protocol -> http2Protocol.setMaxConcurrentStreamExecution(200));
}
});
}
};
}

- 23
- 5