Отмена задания изнутри внутри себя в Executors или отмена извне после таймаута

1

Хорошо, поэтому я провел некоторое время, оглядываясь по сторонам, но не смог найти четкое решение. Ранее я опубликовал отдельный вопрос, но это немного другая проблема.

Проблема: я хочу опросить, чтобы условие происходило периодически. Если это условие все еще ложно, снова перепланировать. Если значение true, остановите планирование. Но я также хочу подождать только определенное количество времени. Вот что я написал

 final ScheduledExecutorService service = Executors.newScheduledThreadPool(1);

  final Future<?> future = service.schedule(new Runnable() {
        @Override
        public void run() {
            if (conditionFalse()) {
                System.out.println("its false. Rescheduling");
                service.schedule(this, 2, TimeUnit.SECONDS);
            } else {
                System.out.println("true. Exiting");
            }
        }
    }, 2, TimeUnit.SECONDS);

   //Wait only for 5 seconds 
   future.get(5, TimeUnit.SECONDS); // does not work
   //does not work either
     service.schedule(new Runnable() {
        @Override
        public void run() {
            future.cancel(true);
        }
    }, 5, TimeUnit.SECONDS);

Это позволяет перепланировать до тех пор, пока не будет выполнено условие. Любые предложения о том, почему он не работает? Как подождать только 5 секунд, а затем остановить выполнение задачи?

  • 0
    Не уверен, что это сработает, так как объект Future изменится после первого планирования.
  • 0
    Только что тоже попробовал. Добавлен future.cancel в том же исполнителе, но он продолжает работать.
Показать ещё 6 комментариев
Теги:
multithreading
executorservice
scheduledexecutorservice

1 ответ

1
Лучший ответ

Когда Future.get вернется, ваша первая задача была завершена, но, возможно, запланирована другая задача с использованием того же Runnable. Вызов cancel в первом Future имеет никакого эффекта тогда, поскольку он представляет первую (законченную) задачу, но не новую запланированную задачу. Имейте в виду, что каждый вызов schedule вернет новое Future.

В конце концов, непонятно, почему вы делаете задачу такой сложной. Его большое преимущество фоновых потоков заключается в том, что они могут выполнять операции блокировки, не влияя на общее выполнение программы. Поэтому, если вы хотите перепроверить условие каждые две секунды, просто создайте одну общую задачу, реализующую логику проверки каждые две секунды. Ожидание в две секунды заблокирует этот поток, но это нормально, его фоновый поток.

ExecutorService service=Executors.newFixedThreadPool(1);
Future<?> f=service.submit(new Runnable() {
  public void run() {
    try {
      while(conditionFalse()) {
        System.out.println("its false, will wait");
        Thread.sleep(TimeUnit.SECONDS.toMillis(2));
      }
      System.out.println("true. exiting.");
    } catch(InterruptedException ex) {
      System.out.println("interrupted. exiting.");
    }
  }
});
try {
  try {
    f.get(5, TimeUnit.SECONDS);
    System.out.println("conditions met even before trying to cancel");
  } catch(TimeoutException ex) {
    System.out.println("canceling");
    System.out.println(f.cancel(true)?
      "canceled before conditions met": "conditions met before canceled");
  }
} catch(InterruptedException | ExecutionException ex) {
  throw new AssertionError(ex);
}

Отмена задачи немедленно прекратит sleep, о чем вы говорили. Пока условия не выполняются и задача не отменяется, нет необходимости перепланировать что-то; цикл будет продолжать работать.

Если у вас больше задач, просто поднимите количество потоков исполнителя. Это может показаться потреблением ресурсов, но спальный поток не потребляет много ресурсов, а ScheduledExecutor будет поддерживать Thread спать между выполнением вашей задачи. Вы даже сохраняете некоторые операции, когда не выполняете реструктуризацию задач.

Важно то, является ли код понятным и понятным, и я думаю, что простой цикл выигрывает над (даже не работающим) перепланирующим кодом.

  • 0
    Имеет смысл. Я был склонен к планированию, потому что он обеспечивает время ожидания с помощью метода schedule и не хотел сам использовать Thread.sleep но да, это становилось действительно сложным.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню