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

4

使用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个回答

6
你的问题在于没有提供执行器。这可能会导致Java提供给你比当前等待调试调用更少的线程,这意味着你仍然会遇到一些阻塞。在我的Intel Core i7-4790(4核心,支持超线程),使用Java 8时,似乎可以同时运行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);
    }
}

看上面的示例,它会打印“completed”100次。如果您删除ex参数,则会打印较少的次数。

然而,如果调试调用缓慢的根本原因仍需修复,因为这可能会在长时间运行的任务中填满内存。

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

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


我会尝试解决这个问题,同时也会修复根本原因,但我想先解决这个问题,因为如果远程日志API在几秒钟内出现故障,我不希望用户受到影响 :) - Tom
它起作用了,非常感谢,我可能会在这个问题上寻找很长时间。 - Tom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接