Прерывание Runnable экземпляра его методом - PullRequest
0 голосов
/ 25 сентября 2019

Допустим, у меня есть такие классы: 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

За этим кодом стоит история о том, что в моем приложении мне нужен одинПоток / Runnable для прерывания другого анонимного потока, выполняющего другой экземпляр Runnable, к которому у меня есть доступ.Зная, что я могу прервать поток из Runnable изнутри с помощью Thread.currentThread.interrupt () (узнал из Интернета), я подумал, что, вызывая это в методе Runnable, я хочу остановить его, а затем вызывая этот метод в его экземпляре в другом потоке.прервет это.Но, как показано в приведенном выше примере, он прерывает поток, который вызвал метод, а не поток, который выполняет Runnable, в котором определен этот метод.Зная, что я ничего не знаю о том, как Thread.currentThread.interrupt () работает и что он не работает, как я ожидал, у меня есть несколько вопросов:1. Из того, как работает этот пример, я предполагаю, что Thread.currentThread.interrupt () прерывает поток, выполняющий функцию, в которой он вызывается, а не тот, который выполняет экземпляр, в котором была вызвана функция.Это правильно?Если нет, то как это работает?2. (самое главное) Есть ли способ прервать поток, вызвав метод его Runnable из другого потока?Если да - как это сделать?Если нет - должен ли я иметь доступ к экземпляру Thread, чтобы прервать его, или было бы лучше, если бы Foo просто расширил Thread вместо реализации Runnable?3. Почему ловится исключение из Bar, если прерывание вызывается перед сном?

Ответы [ 2 ]

0 голосов
/ 25 сентября 2019

Thread.currentThread() возвращает текущий запущенный поток.Вы, кажется, ожидаете, что с экземпляром Foo связан поток, поскольку его метод run() занимает почти весь класс, и его метод terminate() будет использовать этот поток, но Fooпросто обычный класс.Его run() метод может быть вызван другим потоком, который был запущен с его экземпляром, или он может быть вызван напрямую.В любом случае, когда метод terminate() вызывается непосредственно в каком-то потоке, Thread.currentThread() вернет этот поток.

Метод thread.interrupt() не обязательно вызывает InterruptedException быть брошенным.Это произойдет, если поток спит, ожидает или вызывает какую-либо блокирующую операцию, но в документации сказано:

Если ни одно из предыдущих условий не выполняется, то состояние прерывания этого потока будет установлено.

Состояние прерывания - это просто флаг, указывающий, что поток был прерван.При следующем вызове режима сна, ожидания или блокировки будет немедленно выдан InterruptedException.

Если вы хотите прервать конкретный поток, а не текущий, особенно для потока, который вы 'у нас есть простое решение: сохранить ссылку на поток при запуске.

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

А затем в Bar вместо вызова f.terminate() вызовите fthread.interrupt().

0 голосов
/ 25 сентября 2019

Чтобы ответить на ваш вопрос полностью:

  1. Вы правы.Как вы можете видеть здесь https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html Thread.currentThread() возвращает ссылку на текущий исполняемый поток.

  2. Да, есть. Android: как остановить Runnable?

  3. Потому что, как вы предложили в 1., вы прерываете текущий исполняемый поток, который является контекстом Barнаходится внутри. Bar вызывает его собственный InterruptedException.

...