Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In java How to migrate from Executors.newFixedThreadPool(MAX_THREAD_COUNT()) to Virtual Thread

Motivation: Trying to migrate Virtual Threads.

Problem: Even though Virtual Threads are cheap, OS may find it suspicious for some processes to be stacked up at the same time, like searching for IP or ports on the network.

I am using the below code to limit the creation of threads. TS_NetworkIPUtils TS_NetworkPortUtils

var executor = useVirtualThread
                    ? Executors.newVirtualThreadPerTaskExecutor()
                    : Executors.newFixedThreadPool(MAX_THREAD_COUNT());

Is it possible to create an executor service for creating virtual threads and having a limiting feature at the same time?

like image 211
Tugalsan Karabacak Avatar asked Jul 20 '26 05:07

Tugalsan Karabacak


1 Answers

While the best way to limit a number of virtual threads concurrently accessing a limited resource is a Semaphore, recommended in a part Use Semaphores to Limit Concurrency of Virtual Threads manual, yet another solution, a drop-in replacement of

Executors.newFixedThreadPool(MAX_THREAD_COUNT());

construct, when migrating to virtual threads, is perfectly legal:

Executors.newFixedThreadPool(MAX_THREAD_COUNT(), Thread.ofVirtual().factory());

Although, a part Represent Every Concurrent Task as a Virtual Thread; Never Pool Virtual Threads of this manual indeed advises against pooling of virtual threads, main reason behind it is the fact that virtual threads are inexpensive, therefore their pooling makes no sense, at the same time incurring additional expenses on synchronization like organizing a queue etc. Moreover, the part Use Semaphores to Limit Concurrency, comparing Semaphore and thread pool methods, reads:

Submitting tasks to a thread pool queues them up for later execution, but the semaphore internally (or any other blocking synchronization construct for that matter) creates a queue of threads that are blocked on it that mirrors the queue of tasks waiting for a pooled thread to execute them. Because virtual threads are tasks, the resulting structure is equivalent.

In other words, synchronization expenses in Semaphore and thread pool solutions are approximately the same.

The other question that may arise about virtual threads pooling is their reusability. Indeed, if a virtual thread that ran one Runnable/Callable task, cannot correctly run next one, because of, for example, some leftover state or due to performance losses associated with re-tasking, then a pool of virtual threads is downright harmful. However, no any virtual threads' documentation, JEP, or manual says that virtual threads cannot be reused. Instead, they insist that virtual threads are just Java threads, only they are so cheap that their reusing makes no sense.

Having said that 1) synchronization expenses are not greater in a thread pool than with Semaphore and 2) reusing virtual threads is not prohibited, we could conclude that a fixed pool of virtual threads can be a viable alternative to a Semaphore-based solution in a case of an access to limited resources. Obviously, a thread state, ThreadLocals, should be cleaned up after the virtual thread usage exactly as it is done for the platform threads, borrowed from a pool.

It is worth to note that pooling of virtual threads in facts restricts an application of Structured Concurrency, for example, Scoped Values, because their binding to a virtual thread should be done at the time of its initiating/starting, which is impossible with pre-created pool-managed threads. Therefore, Semaphore or equivalent method remains more advisable as it allows to engage a full power of virtual threads and Structural Concurrency.

like image 64
igor.zh Avatar answered Jul 22 '26 18:07

igor.zh