Java Async如何工作?异步方法似乎并不异步运行

时间:2019-05-10 14:20:25

标签: java performance asynchronous

使用Java 8。

我有一个Logger类,该类在需要记录某些内容时会调用API。我意识到,如果API配置不正确,或者API无法解决问题,我的日志操作将花费大量时间。

同步记录示例:

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

我能够指出问题出在这里,因为如果我仅评论所有内容并停止记录或执行任何操作,则所有内容的运行速度都应达到其应有的速度:

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

所以我想将其设为异步调用,因为我不在乎它是否同步记录:

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

但是,对于我的主应用程序而言,异步调用与同步调用一样糟糕,在性能方面也是明智的。我想念什么?

1 个答案:

答案 0 :(得分:5)

您的问题是您不提供执行者。与当前等待的调试调用相比,这可能导致Java为您提供的线程更少,这意味着您仍然会遇到一些阻塞。在具有4个内核和Java 8上的超线程的Intel Core i7-4790上,我似乎使7个线程同时运行(逻辑CPU数-主线程1个)。您可以通过使用缓存的线程池提供无限数量的线程来解决此问题:

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);
    }
}

请参见上面的示例,该示例将“完成”打印100次。如果您删除ex参数,它将打印的内容少得多。

但是,仍然可能需要修复调试调用缓慢的根本原因,因为这是一项长期运行的任务,可能会占用您的内存。

另请参阅:(https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html):

  

所有没有显式Executor参数的异步方法都是   使用ForkJoinPool.commonPool()执行(除非它不会   支持至少两个并行度,在这种情况下,   创建线程以运行每个任务)。 [...]