Java - 线程问题

4
我的问题与所有那些会抛出InterruptedException异常的方法有关(包括Thread.sleep(...))。
我在Sun的教程中找到了一句话,它说:“当另一个线程在sleep处于活动状态时中断当前线程时,sleep会抛出InterruptedException异常。”
这是否意味着如果在中断发生时sleep不处于活动状态,那么中断将被忽略?
假设我有两个线程:threadOne和threadTwo。threadOne创建并启动threadTwo。threadTwo执行一个runnable,其run方法类似于:
public void run() {
    :
    :
    try {
        Thread.sleep(10 * 1000);
    } catch (InterruptedException e) {
        return;
    }
    :
    :
    : // In the middle of two sleep invocations
    :
    :
    try {
        Thread.sleep(10 * 1000);
    } catch (InterruptedException e) {
        return;
    }
    :
    :
}

创建线程后,threadOne 中断了 threadTwo。假设在中断时(没有活动的睡眠方法),threadTwo 正处于两个睡眠调用之间,那么第二个睡眠方法会立即抛出 InterrupteException 吗?
如果不是,那么这个中断会永远被忽略吗?
如何确保 threadTwo 总是知道中断(无论其一个睡眠方法是否活动)?
4个回答

3
从javadoc中得知:
如果该线程在Object类的wait()、wait(long)或wait(long, int)方法,或者在该类的join()、join(long)、join(long, int)、sleep(long)或sleep(long, int)方法的调用中被阻塞,那么它的中断状态将被清除,并且它将接收到InterruptedException异常。
如果该线程在可中断通道上的I/O操作中被阻塞,则该通道将被关闭,线程的中断状态将被设置,并且该线程将接收ClosedByInterruptException异常。
如果该线程在选择器(Selector)中被阻塞,则该线程的中断状态将被设置,并且它将立即从选择操作返回,可能会带有非零值,就像调用选择器的wakeup方法一样。
如果没有满足上述条件,则该线程的中断状态将被设置。
这意味着您必须检查中断状态以确保您的线程知道中断。这可以通过两种方法完成:isInterrupted()和interrupted()。最后一个方法会清除中断状态。
类似于以下内容:
while(!Thread.interrupted()) {
  ...
  try {
    Thread.sleep(10 * 1000);
  } catch (InterruptedException e) {
    return;
  }
}

很好,我刚学到了新东西。我一直在想如何获取中断状态。 - user132014
@Andrea 为什么你使用了 isInterrupted() 而不是 interrupted()? 我认为当线程知道它已被中断时,中断状态应该被清除。 - Amit
Thread.currentThread().interrupted() 更改为 Thread.interrupted(),因为它是一个静态方法。 - Amit

2
在Sun的Windows JDK中,当线程进入sleep()时,实际上会抛出InterruptedException异常:
public static final void main(String args[]) throws Exception {
    final Thread main = Thread.currentThread();
    Thread t = new Thread() {
        @Override
        public void run() {
            main.interrupt();
        }
    };
    t.start();
    t.join();
    Thread.sleep(1000);
    System.out.println("Not interrupted!");
}
sleep()的API文档可以理解为这是强制性行为:

如果任何线程中断了当前线程,则抛出InterruptedException。当抛出此异常时,清除当前线程的中断状态。

但这并不太清楚,所以我不会依赖它,而是手动检查isInterrupted()

@Michael,您对@zerocrates的答案有何看法?如果线程已被中断,sleep()方法是否总是会抛出InterruptedException(无论线程的睡眠方法是否处于活动状态)?......您是在说sleep()方法的这种行为不清楚吗?......如果是这样,那么我将不得不在两个地方提供代码,在sleep方法的catch子句中以及在ifif(Thread.interrupted())中,因为如果sleep方法引发异常,则会清除中断... - Amit
...状态,随后的if (Thread.interrupted())块将返回false。 - Amit
1
@Yatandra:正如我所写的那样:由于API文档中没有明确说明行为,因此我不会依赖它。将应在中断时执行的代码放入单独的方法中,并从两个位置调用它。 - Michael Borgwardt

2
Java文档有些误导性。如果线程的中断状态被设置,在该线程上调用sleep()将立即抛出InterruptException,即使在调用sleep()之前该线程已被中断也是如此。但是,如上所述,您还可以使用Thread.isInterrupted()来检查是否要自行处理中断。请注意保留HTML标记。

-1

InterruptionException 只在线程休眠期间才具有兴趣。如果线程在之前的任何地方被中断,后续的 sleep() 调用不会引发异常。只有在 sleep() 调用时进行中断才是重要的,因为它恰好打破了该 sleep() 调用。


为什么InterruptedException只在sleep方法期间才有意义?即使线程没有睡眠,我也对该异常感兴趣,因为我想在被中断时停止该线程。 - Amit
1
这实际上是不正确的,至少在Sun的Windows JDK上是这样的。 - Michael Borgwardt
那我就是不太清晰的文档的受害者了...很抱歉我之前的回复。 - Daniel Bleisteiner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接