如何创建异步堆栈跟踪?

如何创建异步堆栈跟踪?,第1张

如何创建异步堆栈跟踪

鉴于这个问题将近一个月没有收到任何答案,我将发布迄今为止找到的最佳解决方案:

DebugCompletableFuture.java

public final class DebugCompletableFuture<T> extends CompletableFuture<T>{    private static RunMode RUN_MODE = RunMode.DEBUG;    private static final Set<String> CLASS_PREFIXES_TO_REMOVE = ImmutableSet.of(DebugCompletableFuture.class.getName(),        CompletableFuture.class.getName(), ThreadPoolExecutor.class.getName());    private static final Set<Class<? extends Throwable>> EXCEPTIONS_TO_UNWRAP = ImmutableSet.of(AsynchronousException.class,        CompletionException.class, ExecutionException.class);    private final CompletableFuture<T> delegate;    private final AsynchronousException asyncStacktrace;        private DebugCompletableFuture(CompletableFuture<T> delegate)    {        requireThat("delegate", delegate).isNotNull();        this.delegate = delegate;        this.asyncStacktrace = new AsynchronousException();        delegate.whenComplete((value, exception) ->        { if (exception == null) {     super.complete(value);     return; } exception = Exceptions.unwrap(exception, EXCEPTIONS_TO_UNWRAP); asyncStacktrace.initCause(exception); filterStacktrace(asyncStacktrace, element -> {     String className = element.getClassName();     for (String prefix : CLASS_PREFIXES_TO_REMOVE)         if (className.startsWith(prefix))  return true;     return false; }); Set<String> newMethods = getMethodsInStacktrace(asyncStacktrace); if (!newMethods.isEmpty()) {     Set<String> oldMethods = getMethodsInStacktrace(exception);     newMethods.removeAll(oldMethods);     if (!newMethods.isEmpty())     {         // The async stacktrace introduces something new         super.completeExceptionally(asyncStacktrace);         return;     } } super.completeExceptionally(exception);        });    }        private Set<String> getMethodsInStacktrace(Throwable exception)    {        requireThat("exception", exception).isNotNull();        Set<String> result = new HashSet<>();        for (StackTraceElement element : exception.getStackTrace()) result.add(element.getClassName() + "." + element.getMethodName());        for (Throwable suppressed : exception.getSuppressed()) result.addAll(getMethodsInStacktrace(suppressed));        return result;    }        public static <T2> CompletableFuture<T2> wrap(CompletableFuture<T2> delegate)    {        if (RUN_MODE != RunMode.DEBUG) return delegate;        return new DebugCompletableFuture<>(delegate);    }        private void filterStacktrace(Throwable exception, Predicate<StackTraceElement> elementFilter)    {        Throwable cause = exception.getCause();        if (cause != null) filterStacktrace(cause, elementFilter);        for (Throwable suppressed : exception.getSuppressed()) filterStacktrace(suppressed, elementFilter);        StackTraceElement[] elements = exception.getStackTrace();        List<StackTraceElement> keep = new ArrayList<>(elements.length);        for (StackTraceElement element : elements)        { if (!elementFilter.test(element))     keep.add(element);        }        exception.setStackTrace(keep.toArray(new StackTraceElement[0]));    }    @Override    public <U> CompletableFuture<U> thenApply(Function<? super T, ? extends U> fn)    {        return wrap(super.thenApply(fn));    }    @Override    public <U> CompletableFuture<U> thenApplyAsync(Function<? super T, ? extends U> fn)    {        return wrap(super.thenApplyAsync(fn));    }    @Override    public <U> CompletableFuture<U> thenApplyAsync(Function<? super T, ? extends U> fn, Executor executor)    {        return wrap(super.thenApplyAsync(fn, executor));    }    @Override    public CompletableFuture<Void> thenAccept(Consumer<? super T> action)    {        return wrap(super.thenAccept(action));    }    @Override    public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action)    {        return wrap(super.thenAcceptAsync(action));    }    @Override    public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor)    {        return wrap(super.thenAcceptAsync(action, executor));    }    @Override    public CompletableFuture<Void> thenRun(Runnable action)    {        return wrap(super.thenRun(action));    }    @Override    public CompletableFuture<Void> thenRunAsync(Runnable action)    {        return wrap(super.thenRunAsync(action));    }    @Override    public CompletableFuture<Void> thenRunAsync(Runnable action, Executor executor)    {        return wrap(super.thenRunAsync(action, executor));    }    @Override    public <U, V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other,       BiFunction<? super T, ? super U, ? extends V> fn)    {        return wrap(super.thenCombine(other, fn));    }    @Override    public <U, V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T, ? super U, ? extends V> fn)    {        return wrap(super.thenCombineAsync(other, fn));    }    @Override    public <U, V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T, ? super U, ? extends V> fn, Executor executor)    {        return wrap(super.thenCombineAsync(other, fn, executor));    }    @Override    public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other,          BiConsumer<? super T, ? super U> action)    {        return wrap(super.thenAcceptBoth(other, action));    }    @Override    public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,    BiConsumer<? super T, ? super U> action)    {        return wrap(super.thenAcceptBothAsync(other, action));    }    @Override    public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,    BiConsumer<? super T, ? super U> action,    Executor executor)    {        return wrap(super.thenAcceptBothAsync(other, action, executor));    }    @Override    public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other, Runnable action)    {        return wrap(super.runAfterBoth(other, action));    }    @Override    public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other, Runnable action)    {        return wrap(super.runAfterBothAsync(other, action));    }    @Override    public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other, Runnable action, Executor executor)    {        return wrap(super.runAfterBothAsync(other, action, executor));    }    @Override    public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn)    {        return wrap(super.applyToEither(other, fn));    }    @Override    public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn)    {        return wrap(super.applyToEitherAsync(other, fn));    }    @Override    public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T, U> fn,Executor executor)    {        return wrap(super.applyToEitherAsync(other, fn, executor));    }    @Override    public CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action)    {        return wrap(super.acceptEither(other, action));    }    @Override    public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action)    {        return wrap(super.acceptEitherAsync(other, action));    }    @Override    public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action,         Executor executor)    {        return wrap(super.acceptEitherAsync(other, action, executor));    }    @Override    public CompletableFuture<Void> runAfterEither(CompletionStage<?> other, Runnable action)    {        return wrap(super.runAfterEither(other, action));    }    @Override    public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other, Runnable action)    {        return wrap(super.runAfterEitherAsync(other, action));    }    @Override    public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other, Runnable action, Executor executor)    {        return wrap(super.runAfterEitherAsync(other, action, executor));    }    @Override    public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn)    {        return wrap(super.thenCompose(fn));    }    @Override    public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn)    {        return wrap(super.thenComposeAsync(fn));    }    @Override    public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn,         Executor executor)    {        return wrap(super.thenComposeAsync(fn, executor));    }    @Override    public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn)    {        return wrap(super.exceptionally(fn));    }    @Override    public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action)    {        return wrap(super.whenComplete(action));    }    @Override    public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action)    {        return wrap(super.whenCompleteAsync(action));    }    @Override    public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action,      Executor executor)    {        return wrap(super.whenCompleteAsync(action, executor));    }    @Override    public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn)    {        return wrap(super.handle(fn));    }    @Override    public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn)    {        return wrap(super.handleAsync(fn));    }    @Override    public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn,    Executor executor)    {        return wrap(super.handleAsync(fn, executor));    }    @Override    public boolean complete(T value)    {        return delegate.complete(value);    }    @Override    public boolean completeExceptionally(Throwable ex)    {        return delegate.completeExceptionally(ex);    }}

RunMode.java

public enum RunMode{        DEBUG,        RELEASE}

AsynchronousException.java

public final class AsynchronousException extends RuntimeException{    private static final long serialVersionUID = 0L;    public AsynchronousException()    {    }}

用法:

DebugCompletableFuture.wrap(CompletableFuture.supplyAsync(this::expensiveOperation));

好处:您将获得相对干净的异步堆栈跟踪

缺点:

AsynchronousException
每创造一个未来就建造一个新产品是非常昂贵的。具体来说,如果您生成大量的期货,这会在堆上生成大量垃圾,并且GC开销会变得明显。

我仍然希望有人会提出更好的方法。



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5501175.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-12
下一篇 2022-12-12

发表评论

登录后才能评论

评论列表(0条)

保存