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

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

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

 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 секунд, а затем остановить выполнение задачи?

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("it’s 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 спать между выполнением ваших задач, а также. Вы даже сохраняете некоторые операции, когда не перепланируете задачи.

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

Другие вопросы по тегам