Skip to content

Commit

Permalink
Blog: Improve performance of your spring boot application with Virtua…
Browse files Browse the repository at this point in the history
…l Threads
  • Loading branch information
akashchandwani committed Feb 12, 2024
1 parent 47df5da commit df292be
Show file tree
Hide file tree
Showing 3 changed files with 195 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
---
title: "Improving Performance of Your Spring Boot Application With Virtual Threads"
date: 2024-02-12T15:14:28+05:30
draft: false
tags: ["virtual-threads", "spring-boot", "throughput", "performance"]
---


Do you know you can significantly improve the performance of your Spring Boot application in less than just two minutes? Yes, you heard it right! You can simply improve performance of your application by adding two configurations in your app. These configuration will enforce the use of **Virtual Threads** (in contrast to the default **Platform Threads**) on your Spring Boot application running on Tomcat Server. These changes will significantly improve the **throughput** of your Spring Boot application (and yes, I am not kidding!).

If you have already enabled Virtual Threads in your application, and you know what it does behind the scenes, feel free to skip this article. However, if you curious about changes that can increase the throughput of your application, learn about Virtual Threads, and understand what's going on under the hood of these changes, you are at the right place.

Okay, let's just cut to the chase and talk about the changes that can improve the throughput of your Spring Boot application. It's nothing but enabling the use of Virtual threads in Spring boot application.

# Using Virtual Threads in a Spring Boot application

If you are using Spring Boot version 3.2 or above and Java version 21+, you can simply add these two configuration in your app to enforce the use **Virtual Threads**

```java
@Bean(TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME)
public AsyncTaskExecutor asyncTaskExecutor() {
return new TaskExecutorAdapter(Executors.newVirtualThreadPerTaskExecutor());
}

@Bean
public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() {
return protocolHandler -> {
protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
};
}
```

If you just wanted to improve throughput of your application and don't want to deep dive into the theory, you are all good till here and can skip the rest of the article.

If case you are still here, let's just buckle up and deep dive into some theory...

# What are Virtual Threads?

Before we deep dive into Virtual Threads it is important to understand what a platform thread is.

## Platform Threads

A Platform Thread is a thread that runs Java code on its underlying operating system (OS) thread. It is implemented as a thin wrapper around an OS thread and captures its OS thread for the platform thread's entire lifetime. Platform threads are suitable for running all types of tasks but are a limited resource due to the large runtime stack size. The diagram below shows 1-to-1 mapping of Platform threads with the OS Threads

```mermaid
---
config:
sankey:
showValues: false
---
sankey-beta
Platform-Thread-1,OS-Thread-1,1
Platform-Thread-2,OS-Thread-2,1
Platform-Thread-3,OS-Thread-3,1
Platform-Thread-4,OS-Thread-4,1
Platform-Thread-5,OS-Thread-5,1
Platform-Thread-6,OS-Thread-6,1
Platform-Thread-7,OS-Thread-7,1
Platform-Thread-8,OS-Thread-8,1
```
## Virtual Threads

Virtual Threads, on the other hand, are user made threads scheduled by the Java Virtual Machine (JVM) rather than the underlying OS. Virtual threads introduce an abstraction layer between operating-system processes and application-level concurrency, allowing the JVM to mediate between the operating system and the program. This allows the JVM to manage more threads than the ones available on the underlying OS.

Virtual Threads are suitable for executing tasks that spend most of the time blocked, often waiting for the I/O operation to complete. Virtual Threads are not intended for long running CPU intensive operation.

The diagram below shows how virtual threads are mapped to OS threads via JVM orchestration.

```mermaid
---
config:
sankey:
showValues: false
---
sankey-beta
Virtual-Thread-1,JVM-Orchestration,1
Virtual-Thread-2,JVM-Orchestration,1
Virtual-Thread-3,JVM-Orchestration,1
Virtual-Thread-4,JVM-Orchestration,1
Virtual-Thread-5,JVM-Orchestration,1
Virtual-Thread-6,JVM-Orchestration,1
Virtual-Thread-7,JVM-Orchestration,1
Virtual-Thread-8,JVM-Orchestration,1
JVM-Orchestration,OS-Thread-1,1
JVM-Orchestration,OS-Thread-2,1
JVM-Orchestration,OS-Thread-3,1
JVM-Orchestration,OS-Thread-4,1
JVM-Orchestration,OS-Thread-5,1
JVM-Orchestration,OS-Thread-6,1
JVM-Orchestration,OS-Thread-7,1
JVM-Orchestration,OS-Thread-8,1
```

## Benefit of using Virtual Threads

The main advantage of using Virtual Thread is that your application would now be able to **use greater number of threads** than they were able to use before. This is because the Java Virtual Machine (JVM) would assume responsibility of coordinating requests to and from the Operating System, managing them efficiently. As a result, numerous Virtual threads can bypass the waiting period associated with I/O operations and the Operating System, making them accessible to the next task.

# So why is our application faster now?

The configuration we added earlier, simply update the executors of Tomcat to use **Virtual Threads** rather than the default Platform Threads. By default, Tomcat associates one HTTP request with one Platform thread. However, with the Virtual Threads configuration, Tomcat can efficiently manage multiple concurrent requests per underlying Thread within each worker pool, enabling more effective handling of background tasks.

# References

1. [Embracing Virtual Threads](https://spring.io/blog/2022/10/11/embracing-virtual-threads)
2. [Platform Threads and Virtual Threads](https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html)

4 changes: 4 additions & 0 deletions layouts/_default/_markup/render-codeblock-mermaid.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<pre class="mermaid">
{{- .Inner | safeHTML }}
</pre>
{{ .Page.Store.Set "hasMermaid" true }}
82 changes: 82 additions & 0 deletions layouts/_default/single.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{{- define "main" }}

<article class="post-single">
<header class="post-header">
{{ partial "breadcrumbs.html" . }}
<h1 class="post-title entry-hint-parent">
{{ .Title }}
{{- if .Draft }}
<span class="entry-hint" title="Draft">
<svg xmlns="http://www.w3.org/2000/svg" height="35" viewBox="0 -960 960 960" fill="currentColor">
<path
d="M160-410v-60h300v60H160Zm0-165v-60h470v60H160Zm0-165v-60h470v60H160Zm360 580v-123l221-220q9-9 20-13t22-4q12 0 23 4.5t20 13.5l37 37q9 9 13 20t4 22q0 11-4.5 22.5T862.09-380L643-160H520Zm300-263-37-37 37 37ZM580-220h38l121-122-18-19-19-18-122 121v38Zm141-141-19-18 37 37-18-19Z" />
</svg>
</span>
{{- end }}
</h1>
{{- if .Description }}
<div class="post-description">
{{ .Description }}
</div>
{{- end }}
{{- if not (.Param "hideMeta") }}
<div class="post-meta">
{{- partial "post_meta.html" . -}}
{{- partial "translation_list.html" . -}}
{{- partial "edit_post.html" . -}}
{{- partial "post_canonical.html" . -}}
</div>
{{- end }}
</header>
{{- $isHidden := (.Param "cover.hiddenInSingle") | default (.Param "cover.hidden") | default false }}
{{- partial "cover.html" (dict "cxt" . "IsSingle" true "isHidden" $isHidden) }}
{{- if (.Param "ShowToc") }}
{{- partial "toc.html" . }}
{{- end }}

{{- if .Content }}
<div class="post-content">
{{- if not (.Param "disableAnchoredHeadings") }}
{{- partial "anchored_headings.html" .Content -}}
{{- else }}{{ .Content }}{{ end }}
</div>
{{- end }}
{{ if .Page.Store.Get "hasMermaid" }}
<script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.mjs';
const config = {
startOnLoad: true,
securityLevel: 'loose',
sankey: {
width: 800,
height: 400,
linkColor: 'gradient',
nodeAlignment: 'center',
},
};
mermaid.initialize(config);
</script>
{{ end }}


<footer class="post-footer">
{{- $tags := .Language.Params.Taxonomies.tag | default "tags" }}
<ul class="post-tags">
{{- range ($.GetTerms $tags) }}
<li><a href="{{ .Permalink }}">{{ .LinkTitle }}</a></li>
{{- end }}
</ul>
{{- if (.Param "ShowPostNavLinks") }}
{{- partial "post_nav_links.html" . }}
{{- end }}
{{- if (and site.Params.ShowShareButtons (ne .Params.disableShare true)) }}
{{- partial "share_icons.html" . -}}
{{- end }}
</footer>

{{- if (.Param "comments") }}
{{- partial "comments.html" . }}
{{- end }}
</article>

{{- end }}{{/* end main */}}

0 comments on commit df292be

Please sign in to comment.