在实践中引用并发:
要为池线程设置UncaughtExceptionHandler,请提供 ThreadFactory到ThreadPoolExecutor构造函数。 (和所有人一样 线程操作,只有线程的所有者才应该更改它 UncaughtExceptionHandler。)标准线程池允许未被捕获 任务异常终止池线程,但使用try-finally 阻止在发生这种情况时收到通知,以便更换线程。 没有未捕获的异常处理程序或其他故障通知 机制,任务可能看起来无声地失败,这可能是非常的 混乱。如果您希望在任务因某个问题而失败时收到通知 例外,以便您可以执行某些特定于任务的恢复操作, 用可捕获的Runnable或Callable包装任务 异常或覆盖THReadPoolExecutor中的afterExecute挂钩。
Book没有提供任何如何实现这一目的的例子。
你能展示这种技术吗?
我尝试编写代码示例:
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 4, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread();
thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
e.printStackTrace();
}
});
System.out.println("created thread with id " + Thread.currentThread().getId());
return thread;
}
});
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getId() + " started");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getId() + " termination");
throw new RuntimeException();
}
};
threadPoolExecutor.submit(runnable);
threadPoolExecutor.submit(runnable);
threadPoolExecutor.submit(runnable);
threadPoolExecutor.submit(runnable);
}
但是这个输出
created thread with id 1
created thread with id 1
总是
答案 0 :(得分:1)
您的代码中存在多个错误。首先,您必须将传递给Runnable
的{{1}}传递给创建的线程,否则,您将保留一个不执行任何任务的断线。其次,您在工厂中打印ThreadFactory
的id,这显然不是新创建的线程。这就是为什么它打印两次Thread.currentThread()
的id。
但是,在修复这些错误后,您将看不到未捕获的异常。原因是虽然线程池执行程序的行为符合规定,但1
方法将submit
包装到Runnable
中,以便自己捕获所有异常,以便在调用时报告它们FutureTask
。
此时,我们必须记住,有一个任意get()
的队列,它不必是Runnable
个实例。所以未被捕获的例外仍然是可能的,例如当我们通过FutureTask
直接排队runnables时。
所以固定的例子:
execute
将打印
public class Test {
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 4, 1,
TimeUnit.MINUTES, new LinkedBlockingQueue<>(), r -> {
Thread thread = new Thread(r);
thread.setUncaughtExceptionHandler((t, e) -> {
synchronized(System.out) {
System.out.println("Uncaught exception in "+t.getId());
e.printStackTrace(System.out);
}
});
System.out.println("created thread with id " + thread.getId());
return thread;
});
Runnable runnable = () -> {
System.out.println(Thread.currentThread().getId() + " started");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getId() + " termination");
throw new RuntimeException();
};
threadPoolExecutor.execute(runnable);
threadPoolExecutor.execute(runnable);
threadPoolExecutor.execute(runnable);
threadPoolExecutor.execute(runnable);
threadPoolExecutor.shutdown();
}
}
当然,消息的数量和顺序可能不同。
如引用中所述,您还可以通过覆盖created thread with id 11
created thread with id 12
11 started
12 started
11 termination
12 termination
created thread with id 14
created thread with id 15
Uncaught exception in 11
java.lang.RuntimeException
at smp.Test.lambda$main$2(Test.java:28)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
15 started
14 started
Uncaught exception in 12
java.lang.RuntimeException
at smp.Test.lambda$main$2(Test.java:28)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
14 termination
15 termination
Uncaught exception in 14
java.lang.RuntimeException
at smp.Test.lambda$main$2(Test.java:28)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Uncaught exception in 15
java.lang.RuntimeException
at smp.Test.lambda$main$2(Test.java:28)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
了解异常:
afterExecute
尽管如此,在我的测试中,默认的未捕获异常处理程序也打印了堆栈跟踪...