用它的方法中断 Runnable 实例

Interrupting Runnable instance with its method

假设我有 类 像那些: Foo.java:

public class Foo implements Runnable{
  public void run(){
    try{
      sleep(3000);
      System.out.println("Slept for 3s");
    }catch(InterruptedException e){
      Thread.currentThread().interrupt();
      System.out.println("Exception handled from Foo");
    }
  }

  public void terminate(){
    Thread.currentThread().interrupt();
  }
}

Bar.java:

public class Bar implements Runnable{
  private Foo f;

  public Bar(Foo f){
    this.f = f;
  }

  public void run(){
    System.out.println("Interrupting Foo");
    f.terminate();
    System.out.println("Interrupted Foo");
    try{
      sleep(4000);
      System.out.println("Slept for 4s");
    }catch(InterruptedException e){
      Thread.currentThread().interrupt();
      System.out.println("Exception handled from Bar");
    }
  }
}

Test.java:

public class Test{
  public static void main(String[] args){
    Foo f = new Foo();
    Bar b = new Bar(f);
    new Thread(f).start();
    new Thread(b).start();
    System.out.println("Test end");
  }
}

当我编写这段代码时,我希望输出如下:

Test end
Interrupting Foo
Exception from Foo handled
Interrupted
Slept for 4s

但我得到的不是上面的:

Test end
Interrupting Foo
Interrupted
Exception from Bar handled
Slept for 3s

这段代码背后的故事是,在我的应用程序中,我需要一个 Thread/Runnable 来中断另一个匿名线程 运行 我有权访问的另一个 Runnable 实例。知道我可以使用 Thread.currentThread.interrupt() 从 Runnable 内部中断线程(从互联网上学到)我认为在我想停止的 Runnable 方法中调用它,然后在另一个 Thread 的实例上调用这个方法会打断它。但是如上面的示例所示,它正在中断调用该方法的线程,而不是运行定义此方法的 Runnable 的线程。我知道我对 Thread.currentThread.interrupt() 的工作方式一无所知,而且它没有像我预期的那样工作,我有几个问题:
1. 从这个例子的工作原理来看,我假设 Thread.currentThread.interrupt() 中断正在执行调用它的函数的线程,而不是 运行 调用函数的实例的线程。那正确吗?如果不是,它是如何工作的?
2.(最重要的)有没有办法通过从另一个线程调用其 Runnable 的方法来中断线程?如果是 - 它是如何完成的?如果不是 - 我是否必须有权访问 Thread 实例才能中断它,或者如果 Foo 只是扩展 Thread 而不是实现 Runnable 会更好吗?
3.为什么在sleep之前调用中断会捕获到Bar的异常?

尝试完整回答您的问题:

  1. 你是对的。正如您在此处看到的 https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html Thread.currentThread() returns 对当前正在执行的线程的引用。

  2. 是的,有。 Android: How do I stop Runnable?

  3. 因为正如您在 1 中所建议的那样,您正在中断当前正在执行的线程,这是 Bar 上下文所在的线程。Bar 导致它自己的 InterruptedException.

Thread.currentThread() return 当前 运行 线程。您似乎期望有一个线程与 Foo 的实例相关联,因为它的 run() 方法几乎占据了整个 class,并且它的 terminate() 方法将然后使用那个线程,但是 Foo 只是一个普通的 class。它的 run() 方法可以被另一个以它的实例启动的线程调用,也可以直接调用。在任何情况下,当在某个线程上直接调用 terminate() 方法时,Thread.currentThread() 将 return 该线程。

thread.interrupt() 方法不一定会引发 InterruptedException。如果线程正在休眠、等待或调用某些阻塞操作,则会发生这种情况,但文档说:

If none of the previous conditions hold then this thread's interrupt status will be set.

中断状态只是一个标志,表示线程已被中断。下次调用睡眠、等待或阻塞操作时,将立即抛出 InterruptedException

如果您想中断特定线程,而不是当前线程,特别是对于您已启动的线程,有一个简单的解决方案:在启动时存储对该线程的引用。

Thread fthread = new Thread(f).start();
Bar b = new Bar(f, fthread);

然后在 Bar 中调用 fthread.interrupt(),而不是调用 f.terminate()