Ограничение времени для отдельных потоков с ExecutorService - PullRequest
13 голосов
/ 27 января 2011

У меня есть ExecutorService, управляющая несколькими Callables.Задачи, которые запускают Callables, - это в основном преобразования черного ящика и сокращение чисел.При определенных условиях преобразуемые данные будут колебаться, и завершению потока потребуется более часа.Для сравнения, большинство потоков завершаются в течение минуты.

Было обнаружено, что данные из долго работающих потоков не являются подходящими.Я хотел бы прервать любой поток, который работает дольше, чем определенное количество времени.Какой лучший способ сделать это?

Ответы [ 5 ]

21 голосов
/ 27 января 2011

Используйте ScheduleExecutorService, чтобы запланировать задачу на taskFuture.cancel(true) долгосрочную задачу по истечении времени ожидания.Если задание завершится раньше, оно не будет отменено.

ExecutorService service = Executors.newFixedThreadPool(N);
ScheduledExecutorService canceller = Executors.newSingleThreadScheduledExecutor();

public <T> Future<T> executeTask(Callable<T> c, long timeoutMS){
   final Future<T> future = service.submit(c);
   canceller.schedule(new Callable<Void>(){
       public Void call(){
          future.cancel(true);
          return null;
       }
    }, timeoutMS, TimeUnit.MILLI_SECONDS);
   return future;
}
5 голосов
/ 27 января 2011

Вы можете отменить будущее и т. Д., Как и в других ответах, но вам нужно убедиться, что ваши потоки, которые "сокращают число", могут обрабатывать прерывание и корректно завершаться .Вы говорите, что это операция черного ящика - насколько вы уверены, что прерванное состояние потока активно проверяется в черном ящике?Если это не так, вы не можете отменить его с прерыванием.Черный ящик должен быть написан с перерывом.

3 голосов
/ 27 января 2011

Лучший способ сделать это - представить еще одного исполнителя.Вы можете использовать ScheduledExecutorService для отмены всех длительных задач, например:

ExecutorService service = Executors.newFixedThreadPool(N);

ScheduledExecutorService canceller = Executors.newScheduledThreadPool(1);

public void executeTask(Callable<?> c){
   final Future<?> future = service.submit(c);
   canceller.schedule(new Runnable(){
       public void run(){
          future.cancel(true);
       }
    }, SECONDS_UNTIL_TIMEOUT, TimeUnit.SECONDS);
}
0 голосов
/ 27 января 2011

Вы можете использовать этот метод

<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                              long timeout,
                              TimeUnit unit)
                          throws InterruptedException

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

0 голосов
/ 27 января 2011

Вы можете получить список ваших соответствующих Фьючерсов (которые создаются, когда вы отправляете Callable) вместе со временем его запуска.

Другая задача может затем проверять каждую минуту, если какая-либо задача выполняется дольше определенного времени, и если да, вызывать отмена (true) в будущем. Готовые фьючерсы будут удалены из списка.

...