【发布时间】:2017-02-07 01:46:23
【问题描述】:
我正在处理一个多线程项目,其中Thread 可能会抛出Error(不是Exception)。没有找到任何关于如何在多线程中处理错误的可靠信息,我决定做一些测试,发现结果可能不一致。
这是我的测试代码以及注释结果。
public class MultiThreadError {
public static class ErrorThrowingRunnable implements Runnable{
private final boolean throwsError;
public ErrorThrowingRunnable(boolean throwsError){
this.throwsError = throwsError;
}
@Override
public void run() {
try {
// Wait between .5 and 1.5 seconds
Thread.sleep(500 + new Random().nextInt(1000));
} catch (InterruptedException ex) {}
if(throwsError){
throw new Error(Thread.currentThread().getName());
}else{
System.out.println(Thread.currentThread().getName());
}
}
}
public static void regularThreadPool(){
// Crashes individual thread; swallows error
ExecutorService threadPool = Executors.newFixedThreadPool(5);
threadPool.submit(new ErrorThrowingRunnable(false));
threadPool.submit(new ErrorThrowingRunnable(false));
threadPool.submit(new ErrorThrowingRunnable(false));
threadPool.submit(new ErrorThrowingRunnable(false));
threadPool.submit(new ErrorThrowingRunnable(true));
threadPool.shutdown();
}
public static void onDemandThreads(){
// Crashes individual thread; displays error
new Thread(new ErrorThrowingRunnable(false)).start();
new Thread(new ErrorThrowingRunnable(false)).start();
new Thread(new ErrorThrowingRunnable(false)).start();
new Thread(new ErrorThrowingRunnable(false)).start();
new Thread(new ErrorThrowingRunnable(true)).start();
}
public static void onDemandThreadPool(){
// Same as onDemandThreads()
ExecutorService threadPool = Executors.newFixedThreadPool(5);
threadPool.execute(new ErrorThrowingRunnable(false));
threadPool.execute(new ErrorThrowingRunnable(false));
threadPool.execute(new ErrorThrowingRunnable(false));
threadPool.execute(new ErrorThrowingRunnable(false));
threadPool.execute(new ErrorThrowingRunnable(true));
threadPool.shutdown();
}
public static void tooSmallThreadPool(){
// When an error is thrown, apparently the thread that threw
// the error is not reused, reducing the pool size
ExecutorService threadPool = Executors.newFixedThreadPool(3);
threadPool.execute(new ErrorThrowingRunnable(true));
threadPool.execute(new ErrorThrowingRunnable(false));
threadPool.execute(new ErrorThrowingRunnable(false));
threadPool.execute(new ErrorThrowingRunnable(false));
threadPool.execute(new ErrorThrowingRunnable(false));
threadPool.execute(new ErrorThrowingRunnable(false));
threadPool.execute(new ErrorThrowingRunnable(false));
threadPool.execute(new ErrorThrowingRunnable(false));
threadPool.shutdown();
}
}
似乎结果应该是我所期望的:抛出错误的线程终止,显示消息。事实证明,当使用submit(Runnable) 将Runnable 传递给ExecutorService 时,它被包裹在不处理错误的RunnableFuture<Void> 中,除了直接更改外,我找不到其他方法来更改此行为调用execute(Runnable),由于某种原因没有表现出相同的行为。
对此有“最佳实践”吗?如果我知道线程可能会抛出错误,有没有办法将 submit 发送到 ExecutorService 而不会吞下错误?
【问题讨论】:
-
在小风格笔记上,您应该避免抛出
Errors。它们表明您无论如何都不应该尝试处理的严重问题(例如内存不足)。如果你想从Runnable中抛出一些东西,你应该改用RuntimeException(或其子类)。 -
只是为了确保
RunnableFuture处理错误就好了。所有可运行的调用都包含在 try/finally 中。你的意思是说你看不到我怀疑的错误信息。
标签: java multithreading error-handling