【问题标题】:Thread.Interrupt() does not work and I don't really see reason whyThread.Interrupt() 不起作用,我真的不明白为什么
【发布时间】:2021-10-07 19:01:43
【问题描述】:

就像我很沮丧,因为我不明白为什么它不起作用。

这是我的代码的一部分:

if (!loadThread.isInterrupted()) {
    try {
        Thread.sleep(500);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

它给了我错误:

W/System.err: java.lang.InterruptedException
W/System.err:     at java.lang.Thread.sleep(Native Method)
    at java.lang.Thread.sleep(Thread.java:442)
    java.lang.Thread.sleep(Thread.java:358)
    at me.igor.comunicator.client.MainActivity$2.run(MainActivity.java:94)

第 94 行是Thread.sleep(500);。这很奇怪,因为如果它给我的错误是线程被中断,那么为什么if(!loadThread.isInterrupted()) { 会被执行为真?

【问题讨论】:

  • 所以你在睡觉前检查一下,是什么阻止了你在睡眠期间打断线程?
  • 是同一个线程还是两个不同的线程?请问minimal reproducible example?
  • 同一个@OleV.V.

标签: java multithreading java-threads


【解决方案1】:

您似乎不了解中断的作用或工作原理。

一个简短的教程:

  • 检查其他线程的中断标志的状态是非常奇怪的。 您可能想要Thread.interrupted() 而不是loadThread.isInterrupted()。
  • 在线程上设置中断标志时,不会立即发生任何事情。我们不会等待读取标志的东西在该线程中运行,此时会发生一些事情。与该标志只有 2 次交互:
    1. 正在呼叫Thread.interrupted。如果您在线程的中断标志被引发时调用该方法,那将返回 true,并将降低该标志。
    2. 正在调用与该标志具有特定交互的任何方法。 每个指定给throws InterruptedException 的方法,例如Thread.sleep,都保证与之交互:这些方法将抛出InterruptedException 并降低标志。如果在您调用该方法时标志处于上升状态,它们会通过降低标志并抛出异常来立即返回。没有指定抛出 InterruptedEx,但会“休眠”的方法,例如 fileInputStream.read(),可能会或可能不会与它交互:JVM 的选择。取决于您的操作系统。如果他们与它互动,他们会降低旗帜并抛出例如IOException。他们不会(也不能)抛出InterruptedException。

这对您的代码意味着几件事:

  1. 当然,您的 isInterrupted() 调用返回 false:它还没有中断YET,这发生在这 500 毫秒内。
  2. 一般来说,您根本不需要检查。 这里处理中断的唯一方法是捕获该异常。根本没有别的办法。这也将处理所有可能发生的情况,您不需要任何检查。这是您必须编写的代码,它涵盖了所有相关案例:
boolean wasInterrupted;
try {
    Thread.sleep(500);
    wasInterrupted = false;
} catch (InterruptedException e) {
    wasInterrupted = true;
}

if (wasInterrupted) {
   // do whatever you intended to do here
}

您根本不需要调用 Thread.interrupted 的原因是因为 Thread.sleep 会免费为您做这件事(性能或其他方面)。

请注意,线程永远不会被任何事情打断,除非您专门写 someThread.interupt()。例如用户按下 CTRL+C 或进入他们的任务管理器或活动监视器或诸如此类并结束您的进程,无论是否强制,不会导致中断。

【讨论】:

  • Thread.interrupted() 不推荐,因为它会取消设置中断标志。 Thread.currentThread().isInterrupted() 是应该使用的。 OP 对isInterrupted() 的使用是正确的。
  • 另外,还有很多其他地方会导致线程被中断而程序员没有直接调用somethread.interrupt()。 threadPool.shutdownNow() 浮现在脑海中。我理解你的意思,但可能会被误解。
  • @Gray 不,你错了:清除标志是重点的一部分。如何使用中断 API 的“流程”是围绕在您采取行动后清除该标志而设计的。
  • 是的,没有。通常不建议这样做。如果您清除该标志,那么调用者将不知道当前线程已被中断。这就是为什么我们在捕获 InterruptedException 时重新中断线程的原因。您通常希望在不清除的情况下测试中断状态,并且希望在捕获 InterruptedException 后重新中断。
  • 通常不推荐 - 上诉.. 什么?无论如何,这是一个逻辑谬误。或者,正如维基百科的人所说,[需要引用]。但是,嘿,如果上诉是公平的游戏:我只会说它通常是推荐的。与你不同,我什至会为这个声明提供一个来源,而不是我自己:API 本身的设计者,它没有添加“降低那个标志”来搞笑。他们认为 API 以这种方式工作得更好。
【解决方案2】:
if(!loadThread.isInterrupted()) {

所以答案取决于loadThread 是当前正在运行的线程还是在您的应用程序中运行的另一个线程。因为你在MainActivity,所以当前运行的线程可能是主线程,loadThread是当前线程正在检查状态的某个后台加载线程。

如果loadThread 是当前线程,那么测试中断标志确实没有任何意义。如果设置了标志,Thread.sleep() 将立即抛出。

W/System.err: java.lang.InterruptedException

这是说当前正在运行的线程已被中断。您可以通过堆栈跟踪看到线程在抛出时位于Thread.sleep(...)。这可能与loadThread 有任何关系,也可能没有任何关系。

为什么if(!loadThread.isInterrupted()) { 被执行为真。

所以如果loadThread是当前正在运行的线程,那么它很有可能测试它的中断状态然后调用Thread.sleep()。当它处于睡眠状态时是中断被传递的时候。我假设这段代码在某种测试循环中?代码在睡眠之外被中断的可能性实际上可能很小。这是典型的竞争条件,因此可以在isInterrupted() 之前或在睡眠期间之后传递中断——代码必须为任何一种可能性做好准备。

最后,在大多数情况下,建议您在捕获InterruptedException 时重新中断线程。原因是当InterruptedException被抛出时,线程的中断状态被清除。如果您退出例程,您希望调用代码也能够测试中断标志——您不想人为地清除它。有 3rd 方库可以捕获并且不会重新中断线程,这可能会导致线程应用程序出现重大问题。

try {
   Thread.sleep(500);
} catch (InterruptedException ie) {
   // immediately re-interrupt the thread so callers can test it too
   Thread.currentThread().interrupt();
   // deal with the interrupt which typically means exiting the the thread
   return;
}

【讨论】:

    【解决方案3】:

    你的线程在等待期间被中断(执行Thread.sleep指令) 在这种情况下,InterruptedException 会被抛出。

    在您的代码中,除了 Thread.sleep 之外别无其他。所以运行这段代码的线程在thread.sleep之后,if.isInteruppted之前被中断的可能性很小。

    您的程序不应失败 - 只需打印堆栈跟踪并继续执行(try 块之后的代码)。在这种情况下,当 InterruptedException 被捕获时,只使用 log.debug 是合适的(这不是错误)。

    详情请见https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#sleep(long)

    【讨论】:

    • 在大多数情况下,在捕获 InterruptedException 后继续操作被认为是错误的形式。您的线程正在被中断,您通常应该让它退出或返回。在某些情况下,应用程序使用中断标志来使线程停止睡眠,以便它可以检查某些内容并继续,但这种逻辑不太典型。
    猜你喜欢
    • 2014-04-20
    • 1970-01-01
    • 1970-01-01
    • 2021-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    相关资源
    最近更新 更多