Как определить, отменено ли ScheduledFuture на самом деле не отменено? - PullRequest
5 голосов
/ 30 апреля 2019

Я использую ScheduledExecutorService и отправляю задачу, подобную этой:

future = scheduledExecutorService.schedule(myRunnableTask, delay, timeunit)

Однако через неопределенное время может произойти определенное событие, которое сигнализирует о том, что эта задача больше не нужна. И поэтому мне нужно отменить эту задачу, и я использую

boolean cancelled = future.cancel(false) строка.

После отмены я должен предпринять различные действия в зависимости от того, действительно ли запущенный запускаемый файл запущен или нет. А здесь давайте сначала перейдем к документации Oracle и прочитаем, что означает флаг cancelled:

https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html#cancel(boolean)

Возвращает: false, если задача не может быть отменена, как правило, потому что она уже была выполнена нормально; в противном случае

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

Теперь обратим внимание на случай, когда он возвращает true. Здесь есть две возможности:

  1. Задача была фактически отменена, и работоспособность не выполнялась.
  2. Runnable находится в процессе запуска и поэтому не может быть отменен. (если я не использую логику прерывания потока, чего я не хочу)

Я согласен с обоими случаями, но я хочу ЗНАТЬ, какой из них действительно произошел, и принять соответствующие меры. Если исполняемый файл находится в процессе, тогда я в порядке, когда он заканчивает свою работу, я хочу дождаться его завершения и затем сделать одну вещь. Но если он был отменен и никогда не будет работать, я хочу сделать что-то другое.

Не могли бы вы порекомендовать подход к этому? Я что-то упустил?

1 Ответ

1 голос
/ 30 апреля 2019

Вы можете достичь своей цели с помощью:

  • A Set<Runnable>, который отслеживает Runnable s, которые начали выполнение пулом потоков.
  • A Map<ScheduledFuture<?>, Runnable>, который отображает ScheduledFuture<?> на соответствующий Runnable.
    • После планирования задачи вы должны немедленно добавить ScheduledFuture и соответствующие Runnable к Map.
    • Если эта вставка в Map выполняется атомарно с планированием самой задачи, тогда вы можете избежать крайнего случая, когда ScheduledFuture никогда не добавлялся к Map, даже после того, как он был отменен.

Я рекомендую изменить ScheduledExecutorService на ScheduledThreadPoolExecutor, что позволит вам переопределить метод beforeExecute(Thread, Runnable); этот метод вызывается непосредственно перед запуском задачи в пуле после того, как ему уже назначен поток, который будет выполнять задачу.

При переопределении этого метода вы можете добавить Runnable к вашему Set<Runnable>.

Затем, когда ScheduledFuture отменяется, вы можете позвонить set.contains(map.get(future)), который сообщит вам, был ли выполнен Runnable (на который ScheduledFuture отображается).


Обратите внимание, что ваши реализации Set<Runnable> и Map<ScheduledFuture<?>, Runnable> должны быть защищены от потоков, чтобы избежать возможных условий гонки.

...