В настоящее время я выискиваю неприятную ошибку в многопоточной среде с использованием FutureTasks и Executors. Основная идея состоит в том, чтобы фиксированное число потоков выполняло отдельные задачи FutureTasks, которые вычисляют результат, который должен отображаться в таблице (не говоря уже о аспекте GUI).
Я так долго смотрю на это, что начинаю сомневаться в моем здравом уме.
Рассмотрим этот кусок кода:
public class MyTask extends FutureTask<Result> {
private String cellId;
...
protected void done() {
if (isCancelled()) return;
try {
Result r = get(); // should not wait, because we are done
... // some processing with r
sendMessage(cellId, r);
} catch (ExecutionException e) { // thrown from get
...
} catch (InterruptedException e) { // thrown from get
...
}
}
...
}
Когда done()
вызывается Исполнителем, обрабатывающим экземпляр MyTask, я проверяю, попал ли я туда, потому что задача была отменена. Если так, я пропускаю все оставшиеся действия, особенно я не звоню sendMessage()
.
Документация для FutureTask.done () гласит:
Защищенный метод вызывается при переходе этой задачи в состояние isDone (как обычно, так и через отмену). Реализация по умолчанию ничего не делает. Подклассы могут переопределять этот метод для вызова обратных вызовов завершения или для ведения учета. Обратите внимание, что вы можете запросить статус внутри реализации этого метода, чтобы определить, была ли эта задача отменена.
( Справочник по API )
Но из документации FutureTask
я не получаю семантику во время выполнения done()
. Что если я вначале сдаю проверку isCancelled()
, но сразу после этого какой-то другой поток вызывает мой метод cancel()
? Это заставит мою задачу передумать и с этого момента ответить isCancelled() == true
Если так, как я узнаю позже, отправлено ли сообщение? Глядя на isDone()
, я просто скажу, что выполнение задачи завершено, но поскольку isCancelled()
также было верным, я не мог знать, удалось ли отправить сообщение вовремя.
Может быть, это очевидно, но я сейчас не вижу этого.