What are virtual threads
Virtual threading is a feature that was added at the beginning of Java 19 and is similar to theGolang(used form a nominal expression)Ctrip (Chinese company)Similarly, other languages have long been provided, and so practical and useful features, as a Java developer, has long been looking forward to.
Difference between virtual and normal threads
"Virtual" threads, literally, it is "fake", it is not directly scheduling the operating system threads, but by the JVM to provide a layer of thread interface abstraction, by the ordinary thread scheduling, that is, a common operating system thread can be scheduled thousands of virtual threads. Virtual threads consume much, much less than normal threads, and with enough memory, we can even create millions of virtual threads, which was not possible before (before Java19).
In fact, if you have used akka friends will find that, in fact, the two are very similar, except that the use of akka is the application to deal with, and the virtual thread is the JVM to deal with, the use of more concise and convenient.
SpringBoot using virtual threads
The following we will use virtual threads in SpringBoot, the default asynchronous thread pool and http processing thread pool to replace the virtual thread, and then compare the performance difference between virtual threads and ordinary threads, you will find that the difference is like a horse-drawn carriage for a high-speed train, not an era of things.
configure
First of all the version of Java we are using isjava-20.0.2-oracle
The SpringBoot version is3.1.2
。
To use virtual threads in SpringBoot is simple, add the following configuration:
-
java copy code/**
-
* Configuration is for later testing, -thread=true is to use virtual threads, false is to use the default normal threads
-
*/
-
@Configuration
-
@ConditionalOnProperty(prefix = "spring", name = "virtual-thread", havingValue = "true")
-
public class ThreadConfig {
-
-
@Bean
-
public AsyncTaskExecutor applicationTaskExecutor() {
-
return new TaskExecutorAdapter(Executors.newVirtualThreadPerTaskExecutor());
-
}
-
-
@Bean
-
public TomcatProtocolHandlerCustomizer<?> protocolHandlerCustomizer() {
-
return protocolHandler -> {
-
protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor());
-
};
-
}
-
}
@Async Performance Comparison
Let's write an asynchronous service that sleeps for 50ms inside, simulating MySQL orRedisand other IO operations:
-
java copy code@Service
-
public class AsyncService {
-
-
/**
-
*
-
* @param countDownLatch for testing
-
*/
-
@Async
-
public void doSomething(CountDownLatch countDownLatch) throws InterruptedException {
-
(50);
-
();
-
}
-
}
The final test class, quite simply, is to loop through the method 100,000 times and calculate the time consumed for all the methods to complete execution:
-
java copy code @Test
-
public void testAsync() throws InterruptedException {
-
long start = ();
-
int n = 100000;
-
CountDownLatch countDownLatch = new CountDownLatch(n);
-
for (int i = 0; i < n; i++) {
-
(countDownLatch);
-
}
-
();
-
long end = ();
-
("Time consuming:" + (end - start) + "ms");
-
}
Common threads take time: 678 seconds or so. That's over 10 minutes.
Virtual threads are time consuming: 3.9 seconds!!!
Friends, approaching200 times
The performance gap!
HTTP Request Performance Comparison
Let's look at the comparison of http requests again, simply write a get request that does nothing in it and sleeps the same 50ms to simulate an IO operation:
-
java copy code@RequestMapping("/get")
-
public Object get() throws Exception {
-
(50);
-
return "ok";
-
}
Then we use thejmeterrequest interface.500
Concurrent threads that run10,000 times.
And see how that works out:
General thread:
You can see that the minimum elapsed time50ms
, there's nothing wrong with this, the interface sleeps for 50ms inside, but whether it's the median or the90/95/99 lines
both are larger than150ms
This is because system threads are an expensive resource and SpringBoot'stomcatThe default maximum number of connections should be 200, after the threads in the connection pool are exhausted, these 200 threads are there waiting for 50ms to end, and the rest of the requests can only wait, unable to do anything else. Here's how the virtual thread behaves:
Virtual threads are time consuming:
It can be seen that even the maximum elapsed time stays below 100ms, i.e., the thread waiting time is significantly reduced and the virtual threads make better use of the system resources.
summarize
The performance comparison above shows that virtual threads have a clear advantage in terms of performance, but note that all of our tests above had the threads waiting for 50ms, what scenario is this simulating? That's right.IO-intensive
scenario, i.e., the thread spends most of its time waiting for IO so that the virtual thread can take advantage of it, if theCPU-intensive
scenarios, then it may not be very effective. However, most of our current applications are more IO-intensive applications, such as the typicalWEB application
A lot of time on hold.Network IO
(DB, caching, HTTP, etc.), the use of virtual threads is still very effective.
Finally: most companies are probably still using Java 8, but I'd say it's time to upgrade and get with the times, folks!