2017-01-17 3 views
1

Я использую службу ScheduledExecutorService, к которой я добавляю как входящие, так и запланированные Runnables (используя scheduleWithFixedDelay). Намерение состоит в том, чтобы иметь очень длинные процессы, и, следовательно, у меня не было определенных жизненных циклов. Я в основном хочу, чтобы основной поток реагировал только на исключения и прерывания. Плановые задачи являются критическими, например. генерируя тепловые биты, и, таким образом, если какая-либо нить бросает ошибку runtimeexception, я хочу зарегистрировать исключение, прервать все остальные потоки и закрыть программу.Обработка исключений с несколькими фьючерсами из ScheduledExecutorService

Как я должен обрабатывать исключения? Служба ScheduledExecutorService проглатывает все исключения, если я не запустил Future.get().

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

for (Future<?> future : futures) { 
    future.get(); 
} 

Один из вариантов будет пробегаем по фьючерсам с просьбой, если они сделаны, как показано ниже, но мне не очень нравится это решение. Мне нужно добавить поток sleep и, таким образом, отклик на исключение задерживается.

boolean allActive = true; 
while (allActive) { 
    for (Future<?> future : futures) { 
     if (!future.isDone()) { 
      allActive = false; 
      break; 
     } 
    } 
    Thread.sleep(50); 
} 

Какие еще варианты у меня есть? Или я неправильно подхожу к проблеме? Не следует ли вообще использовать ScheduledExecutorService и реализовать расписание самостоятельно в моем собственном потоке?

Пример кода, попробуйте изменить порядок в будущем списке! Я хочу, чтобы поведение, которое вы получите, если добавить ручку, прежде чем handle2 но порядок списка не имеет значения:

import java.util.ArrayList; 
import java.util.List; 
import java.util.concurrent.Executors; 
import java.util.concurrent.Future; 
import java.util.concurrent.ScheduledExecutorService; 
import java.util.concurrent.TimeUnit; 

public class Test { 

    private static int i = 0; 

    public static void main(String[] args) throws Exception { 

     ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); 

     Future<?> handle = scheduler.scheduleWithFixedDelay(new Runnable() { 
      public void run() { 
       System.out.println("No exception!"); 
       if (i > 2) { 
        System.out.println("Exception!"); 
        throw new RuntimeException("foo"); 
       } 
       i++; 
      } 
     }, 0, 500, TimeUnit.MILLISECONDS); 

     Future<?> handle2 = scheduler.scheduleWithFixedDelay(new Runnable() { 
      public void run() { 
       System.out.println("Running!"); 
      } 
     }, 0, 500, TimeUnit.MILLISECONDS); 


     List<Future<?>> futures = new ArrayList<>(); 
     futures.add(handle2); 
     futures.add(handle); 

     try { 
      for (Future<?> future : futures) { 
       future.get(); 
      } 
     } catch (Exception e) { 
      scheduler.shutdownNow(); 
      System.out.println(scheduler.awaitTermination(1, TimeUnit.SECONDS)); 
      System.out.println("Shuwdown complete"); 
      e.printStackTrace(); 
     } 
    } 
} 
+2

Для таких задач вам может понравиться ['ListenableFuture'] Guava (https://github.com/google/guava/wiki/ListenableFutureExplained). – dimo414

+0

Вы думали использовать «isCancelled()»? – efekctive

ответ

2

Вы можете сделать это с Слушателя или наблюдателями трафаретом:

interface IFutureListener{ 
    void onException(Throwable t); 
} 


final IFutureListener errHandler = new IFutureListener(){ 
    @override public void onException(Throwable t){ 
      // shutdown Service here 
    } 
}; 
// ... 
Future<?> handle = scheduler.scheduleWithFixedDelay(new Runnable() { 
     final IFutureListener callback = errHandler; 
     public void run() { 
      try{ 
      System.out.println("No exception!"); 
      if (i > 2) { 
       System.out.println("Exception!"); 
       throw new RuntimeException("foo"); 
      } 
      i++; 
      } 
      catch(Exception ex){ 
       callback.onException(ex); 
      } 
     } 
    }, 0, 500, TimeUnit.MILLISECONDS); 

Возможно, вам понадобятся некоторые изменения, но это суть.

Гуава ListenableFuture как @ dimo414 пишет в комментарии даст вам нечто подобное. Но если вы не хотите/не можете использовать третьи стороны, это способ, которым вы можете реализовать его самостоятельно.

Благодаря @efekctive: Я также предлагаю исключение регистрации. Их почти никогда нельзя просто проглатывать молча, за исключением того, что вы точно знаете, что делаете.

+0

Я посмотрю на Гуаву, но похоже, что он должен сделать трюк. Благодаря! – Vejto

+0

Просто создайте класс, где main - это слушатель, и укажите среднее значение, которое должно вызывать исключение. – efekctive

+0

@efekctive Это был всего лишь пример, чтобы заставить его начать. Вы также можете сделать подпись метода интерфейса 'void onException (Throwable t, Runnable r)' и называть его как 'onException (ex, this)' ... вы можете настроить его разными способами. Я основывал свое предложение на коде вопроса самым простым способом добиться того, чего пытается достичь ОП. – Fildor

Смежные вопросы