使用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();
});
}
但是,对于我的主应用程序而言,异步调用与同步调用一样糟糕,在性能方面也是明智的。我想念什么?
答案 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()执行(除非它不会 支持至少两个并行度,在这种情况下, 创建线程以运行每个任务)。 [...]