Ответ 1
Нет, я не считаю ваше резюме правильным. Обычно, если вы пишете метод, который вызывает других, которые бросают InterruptedException
, тогда ваш метод также должен рекламировать throwing InterruptedException
, если у вас есть хороший план того, что делать, когда методы, на которых вы полагаетесь, прерывают прерывание сигнала.
Случаи, когда вы сможете поглотить такое прерывание, редки. Возможно, вы вычисляете итеративное решение, где точность возрастает со временем, но, когда прерывается ваш вызывающий поток, вы решаете, что решение, которое вы достигли в течение отведенного времени, достаточно хорошее и все еще достаточно корректно для возврата. Другими словами, это решение все еще находится в пределах диапазона ваших методов.
Представьте себе:
private double improveUpon(double start) throws InterruptedException {
// ...
}
public double compute() {
double result = 0.0;
try {
do {
result = improveUpon(result);
} while (couldBeImproved(result));
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
return result;
}
В качестве альтернативы, если вы просто хотите соблюдать запрос прерывания, вы можете сделать это без участия InterruptedException
:
private double improveUpon(double start) {
// ...
}
public double compute() {
final Thread current = Thread.currentThread();
double result = 0.0;
do {
result = improveUpon(result);
} while (couldBeImproved(result) &&
!current.isInterrupted());
return result;
}
В еще одном варианте рассмотрим случай, когда ваш метод должен либо завершить всю свою работу, либо указать вызывающему, что он не может его завершить, и требуется некоторое время, чтобы добраться туда, но вы хотите уважать прерывание потока. Что-то вроде этого будет достаточно:
private double improveUpon(double start) {
// ...
}
public double compute() throws InterruptedException {
final Thread current = Thread.currentThread();
double result = 0.0;
do {
if (current.interrupted())
throw new InterruptedException();
result = improveUpon(result);
} while (!isAdequate(result));
return result;
}
Обратите внимание, что мы вызвали Thread#interrupted()
, который имеет побочный эффект очистки статуса прерывания потока, если он был установлен. Если этот метод возвращает true, мы, как вызывающий, приняли на себя ответственность за сохранение и сообщение об этом состоянии прерывания. В этом случае, поскольку мы не предполагаем, что мы создали вызывающий поток, и у нас недостаточно видимой области видимости, чтобы узнать, что такое его политика прерывания, мы сообщили о состоянии прерывания, которое мы наблюдали и приняли, выбрасывая InterruptedException
.
Маркировка метода как "блокировки" всегда является вопросом степени; каждый метод блокирует его вызывающего абонента на некоторое количество времени. Различие, которое вы, возможно, ищете, заключается в том, блокирует ли метод блокирование на каком-либо внешнем входе, например, нажатие клавиши или сообщение, поступающее по сети. В тех случаях реклама, которую вы бросаете InterruptedException
, указывает вашему абоненту, что ваш метод безопасен для использования вызывающими пользователями из потоков, которые должны контролировать свою задержку. Вы говорите: "Это может занять некоторое время, но это займет не больше времени, чем вы готовы ждать". Вы говорите: "Я убегу, пока ты не скажешь мне". Это отличается от, скажем, java.io.InputStream#read()
, что грозит блокировать до тех пор, пока не произойдет одно из трех условий, ни один из которых не прерывается нить вызывающего.
В большинстве случаев ваше решение сводится к ответу на следующие вопросы:
- Чтобы удовлетворить требованиям моего метода, мне нужно вызвать любые методы, которые бросают
InterruptedException
? - Если это так, то работа, которую я сделал до этой точки, для моего вызова?
- Если нет, я тоже должен бросить
InterruptedException
. - Если ничего не вызывается throws
InterruptedException
, должен ли я соблюдать статус прерывания вызывающего потока? - Если да, то есть ли какая-либо работа, которую я сделал до того момента, когда я обнаружил, что меня прервал какой-либо доступ к моему абоненту?
- Если нет, я должен бросить
InterruptedException
.
Ситуации, в которых каждый обнаруживает текущее прерывание потока и проглатывают его, обычно ограничиваются теми, где вы, автор, создали соответствующий поток, и вы обязались выйти из потока run()
, как только поток получит прерываться. Это понятие "совместное аннулирование", в котором вы наблюдаете просьбу о том, что ваш поток перестает работать, и вы решили выполнить этот запрос, как можно быстрее завершив свою работу и разрешив стеку вызовов потоков. Опять же, если вы не являетесь автором метода потока run()
, вы проглатываете состояние прерывания потока, вероятно, наносите вред предполагаемому поведению ваших абонентов и других методов, на которые они звонят.
Я предлагаю вам изучить тему статуса прерывания потока и получить удобство с методами Thread#isInterrupted()
, Thread#interrupted()
и Thread#interrupt()
. Как только вы это поймете и увидите, что InterruptedException
находится в полете, это альтернативное представление Thread#isInterrupted()
, вернувшееся true, или вежливый перевод Thread#interrupted()
, вернувшийся true, все это должно стать более понятным.
Если вам нужно больше примеров для изучения, скажите об этом, и я могу добавить здесь рекомендации.