How does Java Async work ? Async method does not seem to run asynchronously

Tom :

Using Java 8.

I have a Logger class that calls an API whenever it needs to log something. I realized that if the API is somehow badly configured, or the API just does not answer, my log action takes an awefull lot of time.

Example of synchronous logging:

public void debug(String message) {
    MDC.clear();
    MDC.put(SOME_KEY, "SOME_VALUE");
    super.debug(message);
    MDC.clear();
}

I was able to pinpoint that the problem is here because if I just comment everything and stop logging or doing anything, everything runs as fast as it should:

public void debug(String message) {
    //     MDC.clear();
    //     MDC.put(SOME_KEY, "SOME_VALUE");
    //     super.debug(message);
    //     MDC.clear();
}

So I thought to make this an asynchronous call, since I don't care if it's logged synchronously :

public void debug(String message) {
    CompletableFuture.runAsync(() -> {
        MDC.clear();
        MDC.put(SOME_KEY, "SOME_VALUE");
        super.debug(message);
        MDC.clear();
    });
}

But this asynchronous call is just as bad, performance wise for my main application, as the synchronous call. What am I missing ?

Konrad Höffner :

Your problem is that you don't provide an executor. This can cause Java to provide you with less threads than you have currently waiting debug calls, which means that you still get some blocking. On my Intel Core i7-4790 with 4 cores and hyperthreading on Java 8, I seem to get 7 threads running at the same time (number logical CPUs - 1 for the main thread). You can fix this by supplying an unlimited number of threads using a cached thread pool:

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class Test
{

    public static void main(String[] args) throws InterruptedException
    {
        Executor ex = Executors.newCachedThreadPool();
        for(int i=0;i<100;i++)
        {
            CompletableFuture.runAsync(() -> {          
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    throw new IllegalStateException(e);
                }
                System.out.println("completed");
            },ex);          
        }
        TimeUnit.SECONDS.sleep(2);
    }
}

See the example above, which prints "completed" 100 times. If you remove the ex parameter, it will print far less.

However the underlying cause of slow debug calls may still need to be fixed as this may fill your memory if it is a long running task.

See also: (https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html):

All async methods without an explicit Executor argument are performed using the ForkJoinPool.commonPool() (unless it does not support a parallelism level of at least two, in which case, a new Thread is created to run each task). [...]

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=76865&siteId=1
Recommended