gpt4 book ai didi

java - 带有 “retry”模式的Thread.join

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:24:25 34 4
gpt4 key购买 nike

使用Thread查看示例代码,我经常遇到这种重试模式。

boolean retry = true;
while (retry) {
try {
myThread.join();
retry = false;
} catch (InterruptedException e) {
// Nothing ...
}
}

join() 应该永远等待。

如果当前线程在 join之前或期间被中断并因此收到 InterruptedException,那么 myThread是否真的加入了?

这是一些剪切粘贴的残留物变成了图案吗?

最佳答案

如果是Thread,则另一个join()不会对您的Thread进行InterruptedExceptionjoin()应该永远等待,或者直到调用Threadinterrupt() -ed为止。

首先,您需要考虑InterruptedException是否可以实际发生。如何处理它有几种可能性。你可以:

  • 吞下它。警告仅当您确定InterruptedException永远不会发生时才这样做。 (您确定吗?是吗?)
  • 再次设置中断标志。如果您的代码不知道如何处理它,但是线程也在做其他可能对InterruptedException感兴趣的事情,那么您将执行此操作。
  • 传播它。如果您当前的方法不知道该如何处理,但调用者可能知道,则这是最佳解决方案。
  • 处理它。也许当您收到Thread时,您当前的run()只是想停止(通过完成其InterruptedException方法)。
  • 将它包装在另一个异常中。有两种变体。
  • 如果InterruptedException最初不应该发生,并且显然是错误的,则可能需要将其包装在Assertion中。
  • 如果您的方法绑定(bind)到不允许InterruptedException的特定契约(Contract),则可能需要将其包装在另一个异常中。

  • 无论如何,我强烈建议您以某种方式对 log()进行 InterruptedException。如果您没有记录它,并且它确实发生了,那么如果没有有关 InterruptedException的记录信息,程序的行为可能很难理解。

    吞下它

    警告仅在完全确定可以这样做时才将其吞下。你被警告了。
    public static void joinThread(final Thread thread) {
    while (true)
    try {
    thread.join();
    return;
    } catch (final InterruptedException e) {
    Logger.getGlobal().log(Level.ERROR, "Unexpected InterruptedException", e);
    }
    }

    作为此方法的一种变体,您可以简单地忽略它而无需重试。
    public static void joinThread(final Thread thread) {
    try {
    thread.join();
    } catch (final InterruptedException e) {
    Logger.getGlobal().log(Level.ERROR, "Unexpected InterruptedException", e);
    }
    }

    再次设置 interrupted标志。

    如果 Thread也正在做其他事情,这就是您要执行的操作,您的代码不知道如何处理 InterruptedException,而其他代码则可以。
    public static void joinThread(final Thread thread) {
    try {
    thread.join();
    } catch (final InterruptedException e) {
    Logger.getGlobal().log(Level.INFO, "Unexpected InterruptedException, resetting flag", e);
    Thread.currentThread().interrupt();
    }
    }

    但是要警告!如果其他代码确实知道该怎么做,那么这才是一个好主意。如果其他代码执行相同的操作,并且这些内容处于循环状态(对于 Thread常常是这种情况),则您刚刚将漂亮的阻塞代码变成了等待繁忙的垃圾,因为 interrupted标志从未正确清除。尽管此解决方案在许多博客文章中都被宣传为最佳或真实的解决方案,但它是无稽之谈,只要没有任何代码知道如何处理 InterruptedException并实际上保持清除该标志而不是对其进行重置即可。

    传播它

    如果方法本身不知道如何处理它,但调用者可能知道,则这是最佳解决方案。
    public static void joinThread(final Thread thread) throws InterruptedException {
    try {
    thread.join();
    } catch (final InterruptedException e) {
    Logger.getGlobal().log(Level.FINE, "Got InterruptedException, propagating it to the caller", e);
    throw e;
    }
    }

    如果调用者做得不错,可以删除不必要的部分,例如日志记录和重新抛出。

    处理它。

    如果方法本身知道在被中断时必须执行某些操作,则它可以简单地捕获异常并执行预期的操作。
    public static void joinThread(final Thread thread) {
    try {
    thread.join();
    } catch (final InterruptedException e) {
    Logger.getGlobal().log(Level.FINE, "Got InterruptedException, handling it", e);
    // ...whatever...
    }
    }

    包装。

    如果不应该发生异常,因为应用程序不支持中断,并且首先不应该调用 Thread.interrupt()ThreadGroup.interrupt(),则将异常转化为 AssertionError是解决方法。
    这样做有两种可能性。
    // Only throws AssertionError if assertions are enabled.
    public static void joinThread(final Thread thread) {
    try {
    thread.join();
    } catch (final InterruptedException e) {
    Logger.getGlobal().log(Level.ERROR, "Unexpected InterruptedException", e);
    assert false : e;
    }
    }

    // Always throws AssertionError.
    public static void joinThread(final Thread thread) {
    try {
    thread.join();
    } catch (final InterruptedException e) {
    Logger.getGlobal().log(Level.FATAL, "Unexpected InterruptedException", e);
    throw new AssertionError(e, "Unexpected Thread interruption.");
    }
    }

    如果要传播 InterruptedException,但调用者不支持该异常且无法更改,则可以将其包装为受支持的异常。这是否可行,是否是一个好主意,实际上很大程度上取决于调用方。
    public static void joinThread(final Thread thread) {
    try {
    thread.join();
    } catch (final InterruptedException e) {
    Logger.getGlobal().log(Level.ERROR, "Unexpected InterruptedException", e);
    throw new SomeException(e, "Unexpected Thread interruption.");
    }
    }

    最后的笔记

    有人讨论吞咽总是不好的。这不是真的。如果您有100行代码,并且出于某些充分理由在某处执行 Thread.sleep(),则吞咽通常会很好。与往常一样,这取决于。最后, Thread.interrupt()的语义与 SIGHUP并没有太大不同,并且 SIGHUP通常被忽略。

    还进行了一些讨论,将其转换为 AssertionError是否是一个好主意。 AssertionError是未经检查的 Throwable,甚至不是 Exception,这意味着编译器不会强制代码对其进行处理,并且大多数代码并未编写来对其进行处理-这是有意的,因为使用 AssertionError时,我们说这是一个错误太出乎意料了,以至于代码不知道如何处理它,因此想停止。 AssertionError是否终止VM取决于要删除哪个线程,因为 AssertionError被抛出到受影响的 UncaughtExceptionHandlerThread上。

    关于java - 带有 “retry”模式的Thread.join,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27357495/

    34 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com