Вариант использования для Future.cancel (false)? - PullRequest
12 голосов
/ 17 июля 2010

В какой ситуации нужно передать false для параметра mayInterruptIfRunning в <a href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/java/util/concurrent/Future.html#cancel%28boolean%29" rel="noreferrer">Future.cancel()</a>?

Если я правильно понимаю, если вы передадите false и задача будет отменена, но потокЕсли не прервано, результат (или ExecutionException) никогда не будет доступен, поскольку задача все еще помечена как отмененная (т. е. isCancelled() возвращает true и get() throws CancellationException.)

Другие возможные ситуации:

  • Реализация Runnable или Callable не проверяет прерывания и будет выполняться до завершения, даже если вы его прерываете (здесь прерывание не делаетразница)
  • Задача, уже выполненная до того, как вы вызвали cancel() (опять же, прерывание не имеет значения)
  • Задача должна выполнить некоторую очистку, прежде чем завершится (хорошо написанная реализация будет использоватьtry ... finally для этого.)
  • Задача не может быть немедленно завершена и должна продолжать выполнять операции, на которые будут влиять прерывания, например, блокировка ввода / вывода (в этом случае вам, вероятно, следуетне звонить cancel вообще)

Так когда / почему вы бы отменили задачу, не прерывая ее?

Ответы [ 3 ]

9 голосов
/ 04 августа 2011

ТЛ; др;Future.cancel(false) полезен только для того, чтобы избежать запуска задач, которые еще не были запущены.

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

Во-первых, в Java отмена является чисто кооперативной.Java сигнализирует о запросе отмены, используя методы блокировки InterruptedExcetions и устанавливая флаг в Thread.Реализация задачи отвечает за уведомление о запросе отмены и отмену самого себя.Брайан Гетц объясняет прерывание в своем посте Работа с InterruptedException .Не все реализации задач будут правильно обрабатывать прерывания.

Второе, на что следует обратить внимание, это то, что объект Future является заполнителем для результатов выполнения задачи в будущем.Если у вас не запущено много потоков, возможно, что задача начинает выполняться сразу, но также возможно, что все потоки уже используются, и задача должна ждать.То, что у вас есть ссылка на объект Future, не означает, что соответствующая задача фактически запущена.Это своего рода резервирование.

У вас есть объект Future, но задача может находиться в одном из следующих состояний:

  1. Ожидание.Например, он может находиться в очереди других задач, ожидающих времени процессора.
  2. Выполняется.
  3. Завершено.

Если ваша задача находится в первом состоянии «Ожидание», то и Future.cancel(true), и Future.cancel(false) пометят будущее как отмененное.Задача остается в очереди задач для выполнения, но когда исполнитель попадает к задаче, он замечает отмененный флаг и пропускает его.

Если ваша задача находится в третьем состоянии «Завершено», то оба значения Future.cancel(true) иFuture.cancel(false) верните false и ничего не делайте.Это имеет смысл, потому что они уже сделаны, и нет способа отменить их.

Флаг mayInterruptIfRunning важен, только если ваша задача находится во втором состоянии «Выполняется».

Если ваша задача выполняется и mayInterruptIfRunning имеет значение false, то исполнитель не выполняетчто угодно и позволяет завершить задачу.

Если ваша задача выполняется и mayInterruptIfRunning имеет значение true, то исполнитель прервет задачу.Но помните немного о совместной отмене - чтобы прерывание работало, должна быть реализована задача обработки отмены.

Резюме:

Future.cancel(true) подходит, когда:

  1. Future представляет собой долгосрочную задачу, которая, как известно, была реализована для обработки прерываний.

Future.cancel(false) будет правильным:

  1. Реализация задачине может обработать прерывание.
  2. Неизвестно, поддерживает ли реализация задачи отмену.
  3. Вы готовы дождаться завершения уже запущенных задач.
7 голосов
/ 17 июля 2010

Если вы боитесь, что прерывание выполнения задачи может привести к плохому состоянию, и вы просто хотите пометить его как отмененное, чтобы пользователи Future знали об этом (например, они должны знать запрошенную статистику).не были выполнены вовремя).

Написание многопоточного кода, который правильно обрабатывает прерывания, совсем не тривиально, и поэтому можно было бы просто предпочесть этого избежать.* здесь , здесь и, конечно, в великой книге Параллельное программирование на Java (автором, который первоначально написал java.util.concurrent).

1 голос
/ 09 декабря 2015

У меня есть вариант использования, который может быть вам интересен: у меня есть один поток, который выполняет набор запланированных задач. Одна из задач может быть перенесена либо самой, либо другой задачей.

Для этого я использую Future.cancel(false) для существующей копии в очереди, а затем планирую задание на новое время.

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

...