Java: вызов прерываемых методов из кода - PullRequest
2 голосов
/ 25 октября 2011

Я читаю 7-ю главу «Параллелизм Java на практике».

В разделе, в котором говорится о методах, которые не имеют собственной политики отмены, но вызывают методы, которые могут быть прерваны, книга содержитСледующее, что нужно сказать.

Действия, которые не поддерживают отмену, но все еще вызывают методы прерываемой блокировки, должны будут вызывать их в цикле, повторяя попытку при обнаружении прерывания. В этом случае они должны сохранить прерываниестатус локально и восстановить его непосредственно перед возвратом, а не сразу после перехвата InterruptedException.

Я не полностью понял это.

Означает ли это, что если я вызову Thread.sleep в своем методе, мне придется вызывать его в цикле или как-то еще?

Может кто-нибудь объяснить, почему это нужно сделать?

Ответы [ 4 ]

4 голосов
/ 25 октября 2011

Я вызываю Thread.sleep в моем методе, мне придется вызывать его в цикле или как-то еще?

Thread.sleep() сгенерирует InterruptedException, когда текущий потокпрервано (другим потоком).Это ваш выбор, как реагировать на это.Если вы хотите спать, независимо от того, пытается ли кто-то вас прервать, тогда да, вы должны построить какой-то цикл вокруг блока try-catch.Вероятно, вам следует использовать часы (например, System.nanoTime()), чтобы проверить, сколько времени вы спали до того, как сработало исключение, а затем продолжить спать в течение оставшегося времени и т. Д.

Обратите внимание, что InterruptedException брошено только , если другой поток прервал текущий поток, вызвав (current)Thread.interrupt().Это не происходит само по себе, поэтому в общем случае вам не нужно строить какие-либо циклы вокруг снов или что-то в этом роде.Обычно потоки прерываются только по уважительной причине (например, закрытие приложения), поэтому вы, вероятно, захотите поддержать отмену / прерывание, если нет особой причины не делать этого.«Особой причиной» может быть, например, запись в устройство ввода-вывода и попытка гарантировать, что все данные будут записаны независимо от попыток отмены.

2 голосов
/ 27 октября 2011

Сначала объяснение:

Прерванный статус потока - это в основном логический флаг, который устанавливается в «true» с помощью interrupt(). Текущее состояние этого флага может быть читать с использованием Thread.currentThread().isInterrupted().

Если прерываемая операция (например, Object.wait() или Thread.sleep()) находит установленный флаг прерывания он выбросит InterruptedException и в то же время очистит (со значением «false») флаг, который может выглядеть следующим образом:

if ( Thread.interrupted() ) { throw new InterruptedException(); }

Обратите внимание и запомните, что Thread.interrupted() неявно очищает прерванный флаг! Это означает, что к тому времени, когда ваш catch( InterruptedException ie) {...} будет выполнен, Сам поток не знает, что он был прерван.

Тем не менее, давайте рассмотрим два примера:

Сначала пример задачи, которая поддерживает отмену. Здесь нам не важно, как далеко продвигается задание до того, как его прервать:

  public void run() {

    int x = 0;

    try {

      while (x < 10) {
        Thread.sleep(1000); // Some interruptible operation
        x++;
      }

      System.out.println("x = " + x);

    } catch (InterruptedException ie) {

      System.out.println("Interrupted: x = " + x);

      // We know we've been interrupted. 
      // Let the caller know it, too:
      Thread.currentThread().interrupt();
    }

  }

Этот код пытается посчитать x от 0 до 10. Если он не прерван, он завершится и выдаст «x = 10». Однако, если поток прерывается между ними, InterruptedException будет выброшено, прерывая текущую задачу увеличения x. В этом случае вывод может быть любым от «Прервано: x = 0» до «Прервано: x = 9», в зависимости от того, когда поток был прерван.

Обратите внимание, что считается хорошей практикой восстанавливать прерванный флаг потока перед выходом, так как в противном случае прерванный статус не будет виден вызывающей стороне этого run() метода.

Теперь, если крайне важно, чтобы наша задача выполнялась полностью, чтобы вывод всегда был "x = 10", что означает, что задача не поддерживает отмену, нам нужен другой подход:

  public void run() {
    int x = 0;

    boolean wasInterrupted = false; // <- This is the local variable to store the interruption status

    while (x < 10) {

      wasInterrupted = wasInterrupted || Thread.interrupted(); // not really needed in this case, but for the sake of completeness...

      try {

        Thread.sleep(1000); // <- Some interruptible operation

      } catch (InterruptedException e) {
        wasInterrupted = true;
      }

      x++;
    }

    System.out.println("x = " + x);

    if ( wasInterrupted ) {
      Thread.currentThread().interrupt();
    }

  }

В этом случае мы продолжаем обработку даже после InterruptedException, пока задача не будет завершена. Чтобы быть хорошим, если мы обнаруживаем прерывание, мы сохраняем это условие в wasInterrupted, чтобы мы могли правильно установите флаг прерывания перед возвратом из метода.

Вот что означает

должен сохранить статус прерывания локально и восстановить его непосредственно перед возвратом.

Там написано «должен», потому что мы не обязаны строго обрабатывать прерывания - мы можем просто игнорировать любые InterruptedException и просто завершить нашу задачу, а затем вернуться. Однако это не является хорошей практикой, упомянутой выше, и может вызвать проблемы в некоторых сценариях.

0 голосов
/ 25 октября 2011

У меня нет книги.Но, насколько я понял, если активность прервалась (кстати, сон не является сигналом прерывания. Но вы можете вывести нить из сна с помощью сигнала прерывания), активность должна сохранить текущие динамические данные (состояние прерывания), чтобывосстановить себя и вернуться из предыдущего состояния.Например;

//Let's say you have integer data named "a"...
a = 45646;

//Normally after interruption, and terminating the activity data a is currently
//referencing @memory will be released...

//If you want to continue using data in a you have to save it somewhere
// persistant(Let's say a file)
void onInterruptionDetected()
{
    saveToSomeFile(a, "temp.txt");
}

//After re-execution of activity(Assuming we need a's previous data in order to 
// continue...), we can recover a's data(which is 45646) in previous interruption...
void onResumeDetected()
{
    a = loadFromFile("temp.txt")
}

Надеюсь, это поможет, я все еще сонный, может быть ошибка:)

0 голосов
/ 25 октября 2011

Насколько я понимаю: долго работающая служба, которая сама по себе не может или не должна прерываться, вызывает другие методы, которые могут быть прерваны. Таким образом, эта долго работающая служба должна быть в состоянии обнаружить это и сообщить об этом с помощью метода или флага. Но он должен быть в состоянии повторить операцию, а не просто выбросить исключение InterruptedException.

Чтобы вызвать метод, который блокирует средства, текущее выполнение блокируется и ожидает, пока метод блокировки не вернет значение. Это может быть сделано в цикле. Тогда вы знаете, был ли вызов метода успешным или вызванный метод прерван.

...