I am currently using Executors.newFixedThreadPool to run a large number of tasks in parallel.
try(ExecutorService executorService = Executors.newFixedThreadPool(10)) {
List<Future<Integer>> resultFutures = executorService.invokeAll(tasks);
for (Future<Integer> rf: resultFutures ) {
....
}
executorService.shutdown();
}
Each task opens a DB connection.
I want to use virtual threads for same(Executors.newVirtualThreadPerTaskExecutor()).
But it may lead to large number of DB connections.
I searched, but couldn't find a way to limit number of virtual threads.
What is a better way of dealing with this situation?
static final mySemaphore = new Semaphore ( … ) ;
try
{
mySemaphore() ; // Blocks until a permit becomes available from the semaphore.
… do your work …
}
finally
{
mySemaphore.release() ; // Return permit to the semaphore’s pool of permits.
}
Virtual threads should not be pooled.
So we need to directly throttle our use of expensive resources.
By the way, be aware that enterprise-oriented database servers such as Postgres offer various ways of limiting connections. These have the advantage of being managed by the DBA/SysAdmin rather than the Java programmer. But here I focus on your Question asking about limiting Java virtual threads.
java.util.concurrent.Semaphore
Semaphore
is a common way to limit the number of objects simultaneously accessing a resource.
Instantiate a Semaphore
, specifying a limited number of permits. You likely want to mark the object reference static
and final
.
static final databaseConnectionLimitSemaphore = new Semaphore ( 42 ) ;
Your code grabs one of the permits by calling acquire
. If no permit is available, the acquire
call blocks until one becomes available. Blocked virtual threads are very efficient, being set aside (“parked”) to allow other virtual threads to execute.
When done using that resource, return the permit by calling release
. Be sure to use try-finally
syntax to ensure no permit is lost.
try
{
databaseConnectionLimitSemaphore.acquire() ; // Blocks until a permit becomes available.
… get your database connection …
… do your database work …
}
finally
{
databaseConnectionLimitSemaphore.release() ; // Return permit to the semaphore.
}