Virtually
Virtually copied to clipboard
A Java library to make code more virtual thread friendly
Virtually - Make your code Java virtual threads friendly
Introduction
Virtually is a library that contains classes to ease the migration of code to be more virtual threads friendly. One of the goal is to do it with the less boilingplate code.
For workable full demo code of the API, go to Demo directory
This library provides many tools to migrate to a more virtual threads friendly code:
- Utility methods and annotations to replace the
synchronizedkeyword - Utility methods to convert list elements in parallel using virtual threads
- Classes to execute multiple tasks in virtual threads
Also note that this is early days for this library, so backward compatibility is not guaranteed.
Why virtual threads
| For Managers | For Developers |
|---|---|
| Less memory needed (save costs) | Easy to debug |
| Accept more requests per server | Readable stack trace |
| More memory for caching (faster response time) | Easier to develop with |
| Apply a bit of all of the above | Good pretext to migrate to Java 21 |
Maven
<dependency>
<groupId>com.japplis</groupId>
<artifactId>virtually</artifactId>
<version>0.1</version>
</dependency>
Synchronized
Synchronized code is pinning the virtual thead to the platform/carrier thread, so it should be avoided around I/O operation and replace with ReentrantLock for example.
import com.japplis.virtually.sync.BlockLock;
BlockLock blockLock = new BlockLock();
void main() {
// BlockLock is an AutoCloseable ReentrantLock
try (var sync = blockLock.lockBlock()) {
// Synchronized block with a ReentrantLock
}
}
import static com.japplis.virtually.sync.SyncUtils.*;
void main() {
String text = runSynchronized(() -> {
// Synchronized block on the calling class
return "test";
});
runSynchronized(this, () -> { // 'this' can be replaced with any object (also a ReentrantLock)
// Synchronized block with a ReentrantLock
});
callSynchronized(this, () -> { // will rethrow the Exception of the Callable lambda
// Synchronized block for Callable that may throw an exception
});
}
Collections
import static com.japplis.virtually.ListConverter.*;
import static com.japplis.virtually.MapUtils.*;
void main() throws Exception {
// convert a list to another one using one virtual thread per element
List<Double> prices = convertAll(products, priceService::retreivePrice);
// Get per product the price
Map<Product, Double> productPrice = convertToMap(products, priceService::retreivePrice);
// Get price for other products if not already in the map
computeIfAbsent(productPrice, newProduct, priceService::retreivePrice);
}
Task scopes
At the moment (JDK 21), the task scopes require --enable-preview JVM start-up parameter.
import static com.japplis.virtually.scope.ListTaskScope;
void main() throws Exception {
// A CallableFunction is a Function that can throw an exception
CallableFunction<Product, Double> productToPrice = (Product p) -> priceService.retreivePrice(p.id());
try (ListTaskScope<Product, Double> scope = new ListTaskScope(productToPrice)) {
// scope.setDefaultValue(0);
// scope.setFailOnException(true);
// scope.setMaxConcurrentTasks(10_000);
// scope.setMaxConsecutiveFails(50);
for (Product product : products) {
scope.convert(product);
}
// getting the result will call scope.join()
Map<Product, Double> productWithPrices = scope.getResultsAsMap();
}
}
Annotations
import com.japplis.virtually.sync.*;
@Synchronized // similar to synchronized keyword but with ReentrantLock, requires AspectJ library
void doSomethingSynchronized() {
// do stuff
}
@SynchronizedMethod // synchronized with ReentrantLock to avoid multiple threads to enter this method at the same time, requires AspectJ library
void doSomethingElseSynchronized() {
// do stuff
}
Libraries
Here is a list of frameworks and libraries that are virtual-threads friendly
| Name | Version | Remark |
|---|---|---|
| Spring Boot | 3.2.0 | spring.threads.virtual.enabled=true |
| Quarkus | 3.4.0 | @RunOnVirtualThread |
| Micronaut | 4.0.0 | @Executes(BLOCKING) |
| Tomcat | 11 | <Connector ... useVirtualThreads="true" /> |
| Jettty | 12 | Details |
| Helidon | 4.0.0 | Helidon Níma |
| pgjdbc (Postgres) | 42.6.0 | |
| Oracle driver | 21c | |
| MariaDB connector | 3.3.0 |
Sponsors
This open-source project is sponsored by Ant Commander Pro File Manager. A professional file manager for Windows, MacOS and Linux for developers and more.
You can also hire me to help you migrate to virtual threads.
