我正在使用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();
}
}
}
答案 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:我还建议记录异常。除了你确切知道自己在做什么之外,他们几乎不应该只是默默地吞下去。