I am migrating my Spring Boot application to virtual threads from the platform ones.
Generally it works fine, no pinning happens. But for some request there could be an operation that leads to the pinning (due to a blocking operation inside of a synchronized block) and I want to avoid that. If I don’t, I could not end up in a situation in which all the carriers are pinned and there’s no platform thread to serve a request left.
The operation that leads to the pinning is a part of a 3rd-party library. While waiting for the fix that would allow to execute the library’s code without pinning, I am planning to use the following approach:
Submit the code that pins the virtual thread’s carrier to an executor service and immediately call .get()
(from a virtual thread) on the CompletableFuture
I would receive from the executor.
So, the following code:
// Some other operations on a virtual thread
return obj.thisLeadsToPinning();
Would be rewritten as:
// Some other operations on a virtual thread
return service.submit(() -> obj.thisLeadsToPinning()).get();
As I understand this, the operation now could wait to enter the synchronized block on the executor’s pool thread, but since the .get()
method is called from a virtual thread, their carrier would be free once the operation is done. Now it seems that I’m limiting my parallelism to the size of the thread pool the executor uses, but only for the (rare) requests that requires the operation to run.
For me it seems like it wouldn’t be bad for the application performance.Are my assumptions correct, or am I missing something?