Почему InterruptedExceptions очищают прерванное состояние потока?

Если поток прерван в то время как внутри Object.wait() или Thread.join(), это бросает InterruptedException, который сбрасывает прерванное состояние потока. Т.е., если у меня есть цикл как эта внутренняя часть a Runnable.run():

while (!this._workerThread.isInterrupted()) {
    // do something
    try {
        synchronized (this) {
            this.wait(this._waitPeriod);
        }
    } catch (InterruptedException e) {
        if (!this._isStopping()) {
            this._handleFault(e);
        }
    }
}

поток продолжит бежать за вызовом interrupt(). Это означает, что я должен явно убежать из цикла путем проверки на мой собственный флаг остановки в условии цикла, повторно бросить исключение или добавить a break.

Теперь, это не точно проблема, так как это поведение хорошо документируется и не препятствует тому, чтобы я делал что-либо способ, которым я хочу. Однако я, кажется, не понимаю понятия позади него: Почему поток не считают прерванным еще, после того как исключение было выдано? Подобное поведение также происходит, если Вы получаете прерванное состояние с interrupted() вместо isInterrupted(), затем также поток будет только казаться прерванным однажды.

Я делаю что-то необычное здесь? Например, это более распространенный для ловли InterruptedException вне цикла?

(Даже при том, что я не точно новичок, я отметил этого "новичка", потому что это походит на очень простой вопрос мне, смотря на него.)

17
задан Hanno Fietz 26 March 2010 в 13:52
поделиться

3 ответа

Идея состоит в том, что прерывание должно обрабатываться один раз. Если явное InterruptedException не очистило флаг «прерывание», то большинству ловушек для InterruptedException пришлось бы явно сбросить этот флаг. И наоборот, вы можете «не очистить» флаг самопрерыванием ( Thread.currentThread (). Interrupt () ). Разработчики Java пошли на семантику, которая в большинстве случаев экономила бы нажатия клавиш (т.е. вам чаще нужно сбросить флаг, чем оставить его установленным).

9
ответ дан 30 November 2019 в 14:32
поделиться

Напишите свой код таким образом, и вам не понадобится флаг:

try {
    while (!this._workerThread.isInterrupted()) {
        // do something
        synchronized (this) {
            this.wait(this._waitPeriod);
        }
        // do something else
    }
} catch (InterruptedException e) {
    // ignore ...
}

Как указывает @Boyan, подавлять это исключение прерывания - плохая идея ... в общем. В этом случае контекст будет определять, следует ли вам раздавить его (как указано выше), установить флаг прерывания (снова) или разрешить распространение исключения. Среди прочего, это зависит от того, что означает прерывание в вашем приложении.

1
ответ дан 30 November 2019 в 14:32
поделиться

Это потому, что InterruptedException считается ненормальным событием, когда кто-то другой пытается остановить поток извне.

Если вы действительно хотите прервать поток, вы просто нарушаете его условие цикла, задав логическое значение или что-то подобное. Или вы используете .wait () и .notify () изнутри этого потока . Но если вы выполняете wait () извне:

  • генерируется исключение, чтобы уведомить, что внешний поток попытался прервать меня или заставить меня ждать
  • , поток продолжает свою работу, потому что он этого не делает. не принимайте заказы из другого потока! Но повышение исключения позволяет вам добавить специальную обработку и делать все, что вы хотите, а также эффективно останавливать поток.
0
ответ дан 30 November 2019 в 14:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: