Остановка пула нитей на удовлетворительном состоянии - PullRequest
0 голосов
/ 04 сентября 2011

Я использую ExecutorService для обработки тысяч небольших независимых задач. Каждое задание по завершении сохраняет результат (который либо имеет значение true, либо false).

Итак, вместо того, чтобы обрабатывать все задачи, я хочу преждевременно отключить пул потоков, если задача нашла ответ! Такое ощущение, что я упускаю что-то очень очевидное здесь ...

Ответы [ 2 ]

2 голосов
/ 04 сентября 2011

Рассмотрите возможность использования метода invokeAny. Возвращается, когда сделано только одно.

http://download.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html#invokeAny(java.util.Collection)

0 голосов
/ 04 сентября 2011

Желание, которое вы выражаете, напоминает мне о бутылке Кляйна , где мало что различается между тем, что «внутри» и «снаружи».Здесь задачи, отправленные на ExecutorService, должны знать, что они должны уведомить защелкивающиеся ворота за пределами пула потоков и закрыть его при первом переходе от невидимых истинных результатов задачи к просмотру хотя бы одного.

Я не буду писать код для вас, но я нарисую решение.Это может помочь определить интерфейс, по которому задачи должны вызываться при завершении:

interface TaskObserver
{
  void completed(boolean result);
}

Каждый экземпляр задачи может быть создан со ссылкой на такой TaskObserver, для которого тело задачи будет вызывать толькодо его завершения и возвращает управление обратно вызывающему ExecutorService.Вы могли бы даже написать базовый класс, чтобы помочь в участии в этом протоколе:

public abstract class ObservableTask implements Callable<Boolean>
{
  protected ObservableTask(TaskObserver observer)
  {
    if (null == observer)
      throw NullPointerException();
    observer_ = observer;
  }


  public final Boolean call()
  {
    final boolean result = evaluate();
    observer_.completed(result);
    return result;
  }


  protected abstract boolean evaluate();


  private final TaskObserver observer_;
}

В качестве альтернативы, вместо использования расширения для определения задач, вы можете написать конкретный класс, подобный этому, который принимает ссылку в Callable<Boolean> в своем конструкторе в дополнение к ссылке TaskObserver и работает через делегирование.

В дальнейшем реализация TaskObserver будет хранить AtomicBoolean, который должен быть изначально установлен в значение false.Тело метода completed(boolean) должно пытаться установить AtomicBoolean из false в true, если результат, переданный в completed(boolean), равен true.Если переход от ложного к истинному завершился успешно, выключите ExecutorService и прекратите отправлять больше задач;любые последующие вызовы на номер TaskObserver будут поступать из задач, которые уже были отправлены и были слишком далеко, чтобы удовлетворить запрос на отмену.

public void complete(boolean result)
{
  if (result &&
      latch_.compareAndSet(false, true))
  {
    // Set a flag to cease submitting new tasks.
    service_.shutdownNow();
    if (!service_.awaitTermination(timeoutMagnitude, timeoutUnit))
    {
      // Report a problem in shutting down the pool in a timely manner.
    }
  }
}

Если этого недостаточно, чтобы начать работуПожалуйста, ответьте на дополнительные вопросы.

...