使用ScheduledExecutorService的多个期货进行异常处理

时间:2017-01-17 09:33:20

标签: java multithreading

我正在使用ScheduledExecutorService,我添加了提交Runnables以及预定的Runnables(使用scheduleWithFixedDelay)。 目的是拥有非常长的运行进程,因此我的runnables没有定义的生命周期。我基本上希望主线程只对异常和中断做出反应。 计划的任务很关键,例如生成热门,因此如果任何线程抛出一个runtimeexception,我想记录异常,中止所有其他线程并关闭程序。

我该如何处理例外情况?除非我运行Future.get()。

,ScheduledExecutorService会吞下所有异常

通过期货循环,如下所示,不起作用。如果期货列表中的第一个项目没有返回任何错误,这些错误将阻止线程监听可能返回错误的其他线程。

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

一个选项是循环通过期货询问它们是否已完成,如下所示,但我不太喜欢这个解决方案。我需要添加一个线程睡眠,因此对异常的响应会被延迟。

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();
        }
    }
}

1 个答案:

答案 0 :(得分:2)

您可以使用Listener或Observer-Like模式执行此操作:

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);

你仍然可能需要对此进行一些调整,但这是它的要点。

Guava的ListenableFuture @ @ dimo414在评论中写道会给你类似的东西。但是如果你不想/不允许使用第三方,这是你自己实现它的一种方式。

感谢@efekctive:我还建议记录异常。除了你确切知道自己在做什么之外,他们几乎不应该只是默默地吞下去。