Ограничение по времени для отдельных потоков с помощью ExecutorService

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

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

Ответ 1

Используйте 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;
}

Ответ 2

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

Ответ 3

Лучший способ сделать это - представить еще одного Исполнителя. Вы можете использовать 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);
}

Ответ 4

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

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

Ответ 5

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

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

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