Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/331.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何调试CompletableStage死锁?_Java_Debugging_Asynchronous_Completable Future - Fatal编程技术网

Java 如何调试CompletableStage死锁?

Java 如何调试CompletableStage死锁?,java,debugging,asynchronous,completable-future,Java,Debugging,Asynchronous,Completable Future,我最近遇到的最困难的调试问题是异步操作之间的死锁。例如,给定两个CompletionStage链,其中第一个链调用依赖于第二个链完成的方法,第二个链调用依赖于第一个链完成的方法。这在现实生活中并不明显,因为依赖关系往往是隐藏的,有时死锁涉及三方以上 问题的一部分在于无法找出CompletableStage在等待什么。这是因为操作引用的是CompletableStage,而不是相反 现在大多数调试器都提供某种程度的死锁检测,但这只适用于线程如何调试CompletableStage链之间的死锁?我最

我最近遇到的最困难的调试问题是异步操作之间的死锁。例如,给定两个
CompletionStage
链,其中第一个链调用依赖于第二个链完成的方法,第二个链调用依赖于第一个链完成的方法。这在现实生活中并不明显,因为依赖关系往往是隐藏的,有时死锁涉及三方以上

问题的一部分在于无法找出
CompletableStage
在等待什么。这是因为操作引用的是
CompletableStage
,而不是相反


现在大多数调试器都提供某种程度的死锁检测,但这只适用于线程如何调试CompletableStage链之间的死锁?

我最后做了以下工作:

  • 在每个
    CompletionStage
    链的末尾,安排一个将在超时后触发的事件:

    Set<Object> knownDeadlocks = ConcurrentHashMap.newKeySet();
    // ...
    Future<?> deadlockListener = scope.getScheduler().schedule(() ->
    {
        if (knownDeadlocks.add(Throwables.getStackTraceAsString(context)))
            log.warn("Possible deadlock", context);
    }, DEADLOCK_DURATION.toMillis(), TimeUnit.MILLISECONDS);
    
  • 为完整起见,您还需要:

    /**
     * Rethrows a {@code Throwable}, wrapping it in {@code CompletionException} if it isn't already wrapped.
     *
     * @param <T>       the return type expected by the caller
     * @param throwable a Throwable
     * @return an undefined value (the method always throws an exception)
     * @throws CompletionException wraps {@code throwable}
     */
    public <T> T rethrowException(Throwable throwable)
    {
        if (throwable instanceof CompletionException)
            throw (CompletionException) throwable;
        if (throwable == null)
            throwable = new NullPointerException("throwable may not be null");
        // According to https://stackoverflow.com/a/49261367/14731 some methods do not wrap exceptions
        throw new CompletionException(throwable);
    }
    
    /**
    *返回一个{@code Throwable},如果它还没有被包装,则将其包装在{@code CompletionException}中。
    *
    *@param调用方所需的返回类型
    *@param throwable一个throwable
    *@返回未定义的值(该方法始终引发异常)
    *@throws CompletionException包装{@code throwable}
    */
    公共T rethrowException(可丢弃可丢弃)
    {
    if(可丢弃的CompletionException实例)
    throw(CompletionException)可丢弃;
    if(throwable==null)
    throwable=新的NullPointerException(“throwable可能不是null”);
    //据https://stackoverflow.com/a/49261367/14731 有些方法不包装异常
    抛出新的CompletionException(可丢弃);
    }
    

您能举一个这种情况发生的例子吗?我认为有两种可能的情况,但我可能会错过一些:使用
new
/
complete()
手动管理
CompletableFuture
时,以及链中的一个任务在子级上调用
get()
/
join()
时。第一种情况似乎很难检测(可能需要代码分析),第二种情况似乎有点做作。这是现实生活中经常发生的事情吗?似乎更可能出现涉及其他机制的死锁(
同步的
、数据库事务等)。
/**
 * Rethrows a {@code Throwable}, wrapping it in {@code CompletionException} if it isn't already wrapped.
 *
 * @param <T>       the return type expected by the caller
 * @param throwable a Throwable
 * @return an undefined value (the method always throws an exception)
 * @throws CompletionException wraps {@code throwable}
 */
public <T> T rethrowException(Throwable throwable)
{
    if (throwable instanceof CompletionException)
        throw (CompletionException) throwable;
    if (throwable == null)
        throwable = new NullPointerException("throwable may not be null");
    // According to https://stackoverflow.com/a/49261367/14731 some methods do not wrap exceptions
    throw new CompletionException(throwable);
}