user2163603
user2163603

Reputation: 33

Spring @Async issues with multiple threads

Threads created by Async works for first time and the second time onwards they seems to be hanging. Here is how my code looks like -

Sprint Boot Rest service {
       -> invokes Class A @Async method {
                -> invokes Class B @Async method
       }
}

This rest service is processing a huge tree, resulting many threads.

Here is AsyncConfiguration looks like:

setCorePoolSize - 1000
setMaxPoolSize - 20000
setQueueCapacity - 5000
setThreadNamePrefix - "ABCService"

I am logging thread following thread number and right before first invocation everything looks clean . activeCount:0, poolSize:0, largestPoolSize:0, completedTaskCount:0, taskCount:0, remainingQueueCApacity:5000

While processing the first reuqest : activeCount:1000, poolSize:1000, largestPoolSize:1000, completedTaskCount:6, taskCount:1782, remainingQueueCApacity:4224

After processing first request: activeCount:0, poolSize:1000, largestPoolSize:1000, completedTaskCount:2595, taskCount:2595, remainingQueueCApacity:5000

After requesting my second request: activeCount:1000, poolSize:1000, largestPoolSize:1000, completedTaskCount:2595, taskCount:4915, remainingQueueCApacity:3680

I think threads are hanging because the threads seems to be not working. Also, I do not see any change in activeCount.

I have try/catch in Async methods to handle any exception.

Here are my Async method definitions looks like:

@Async
public void foo(String , String , list, String , boolean ){
    try {
            List<CompletableFuture<String>> completableFutureList
            for each item in list{
                CompletableFuture<String> response = ClassB.bar(String , String , item, String , boolean);
                completableFutureList.add(response);
            }

        CompletableFuture.allOf(completableFutureList.toArray(new CompletableFuture[completableFutureList.size()])).join();

        .......
        ......
    } catch (Throwable e) {
        logger.error("Exception .... " );
    }
}


class B method

@Async
public CompletableFuture<String> bar(String , String , item, String , boolean)){
    try{
        .....
        ......
        }
    catch(......) {
    }
}   

Any help will be appreciated. Thanks.

update :

When I do thread dump, I see that all threads WAITING (parking) as shown below.

"ABCService-26" #83 prio=5 os_prio=0 tid=0x00007f2ab829b800 nid=0x716d waiting on condition [0x00007f272ffc7000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x0000000745cf3198> (a java.util.concurrent.CompletableFuture$Signaller) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at java.util.concurrent.CompletableFuture$Signaller.block(CompletableFuture.java:1693) at java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3323) at java.util.concurrent.CompletableFuture.waitingGet(CompletableFuture.java:1729) at java.util.concurrent.CompletableFuture.join(CompletableFuture.java:1934) at com.abc.command.util.ClassA.foo(ClassA.java:106) at com.abc.command.util.ClassA.bar(ClassA.java:54) at com.abc.command.util.ClassA$$FastClassBySpringCGLIB$$b0eafa9.invoke() at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:115) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745)

Upvotes: 2

Views: 2986

Answers (1)

user2163603
user2163603

Reputation: 33

Issue seems to be JDK bug with CompletableFuture<String>. The workaround is using get(timeout) instead of join():

CompletableFuture<Void> future = CompletableFuture.allOf(completableFutureList.toArray(new CompletableFuture[completableFutureList.size()]));

future.get(executionTime, TimeUnit.MILLISECONDS);

here are more details on the issue...

https://bugs.openjdk.java.net/browse/JDK-8201576 https://crondev.wordpress.com/2017/01/23/timeouts-with-java-8-completablefuture-youre-probably-doing-it-wrong/

Upvotes: 1

Related Questions