使用Thread
查看示例代码,我经常会遇到此重试模式。
boolean retry = true;
while (retry) {
try {
myThread.join();
retry = false;
} catch (InterruptedException e) {
// Nothing ...
}
}
join()
应该永远等待。
如果当前线程在join
之前或期间被中断并因此收到InterruptedException
,myThread
实际加入了吗?
这是一些切割残留物变成了一种模式吗?
答案 0 :(得分:2)
如果Thread
,则join()
Thread
InterruptedException
join()
Thread
。 interrupt()
应该永远等待或直到调用InterruptedException
为InterruptedException
- ed 。
首先,您需要考虑InterruptedException
是否真的可以发生。如何处理它有几种可能性。你可以:
Thread
时才会这样做。 (你确定吗?真的吗?)run()
感兴趣的东西。InterruptedException
只是想在收到InterruptedException
后停止(通过完成InterruptedException
方法)。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
s的情况),那么您只需将好的阻塞代码转换为忙碌等待的垃圾,因为{{1 flag永远不会被正确清除。虽然这个解决方案在许多博客文章中被宣传为最佳或真正的解决方案,但只要没有任何代码知道如何处理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;
}
}
并且实际上保持标志清除而不是重置它,这是无稽之谈。 / p>
如果方法本身不知道如何处理它,这是最好的解决方案,但调用者可能知道。
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
,将异常转换为{{ 1}}是要走的路。
有两种可能性。
// 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
被提升到受影响的UncaughtExceptionHandler
的{{1}}而将被删除的线程。< / p>
答案 1 :(得分:1)
如果myThread.join()
调用中断,则线程未加入。 myThread
将继续运行,不知道调用join的线程已被中断。
我自己并没有看到这种模式,我说这是一种可怕的模式。你永远不应该忽略InterruptedException
这种方式。有关如何正确处理InterruptedExceptions
的说明,请参阅this post。