在使用JDK Executors产生线程池执行任务时,如果使用threadPool.submit(Runnable)来提交任务,且不调用future.get时,如果线程发生错误,程序是不会打印错误堆栈的,比如下面的程序,当i==0时,100/i发生运行时异常,只有四组输出(应该有五组),但是程序不会打印任何异常信息,
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class DivTask implements Runnable{
int a,b;
public DivTask(int a,int b){
this.a = a;
this.b = b;
}
@Override
public void run() {
double re = a/b;
System.out.println(re);
}
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(0,Integer.MAX_VALUE,
0L,TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
for(int i=0;i<5;i++){
pool.submit(new DivTask(100, i));
}
}
}
输出为:
100.0
25.0
33.0
50.0
我们可以将submit方法改成execute方法或者使用 Future re = pools.submit(new DivTask(100,i)); re.get()来打印错误堆栈,改后输出如下:
Exception in thread "pool-1-thread-1" java.lang.ArithmeticException: / by zero
at test.DivTask.run(DivTask.java:17)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
100.0
25.0
50.0
33.0
我们打印了堆栈,看到了错误,却看不到任务是在哪里提交到,要想看到错误,需要扩展线程池,如下:
package test;
import java.util.concurrent.Future;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class DivTask implements Runnable{
int a,b;
public DivTask(int a,int b){
this.a = a;
this.b = b;
}
@Override
public void run() {
double re = a/b;
System.out.println(re);
}
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(0,Integer.MAX_VALUE,
0L,TimeUnit.SECONDS,new SynchronousQueue<Runnable>()){
@Override
public void execute(Runnable command) {
Runnable newCommand = wrap(command,clientTrace(),Thread.currentThread().getName());
super.execute(newCommand);
}
@Override
public Future<?> submit(Runnable task) {
Runnable newTask = wrap(task,clientTrace(),Thread.currentThread().getName());
return super.submit(newTask);
}
private Runnable wrap(final Runnable task, final Exception clientStack,
String clientThreadName){
return new Runnable(){
@Override
public void run() {
try{
task.run();
}catch(Exception e){
clientStack.printStackTrace();
throw e;
}
}
}; //return语句结束
}
private Exception clientTrace(){
return new Exception("Client stack trace");
}
};
for(int i=0;i<5;i++){
pool.execute(new DivTask(100, i));
}
}
}
上面程序重写了ThreadPoolExecutor的executor和submit方法,并且为任务提供了一个包装函数,就可以打印出在哪里提交的任务了,下面红色部分:
100.0
25.0
33.0
50.0
java.lang.Exception: Client stack trace
at test.DivTask$1.clientTrace(DivTask.java:56)
at test.DivTask$1.execute(DivTask.java:29)
at test.DivTask.main(DivTask.java:61)
Exception in thread "pool-1-thread-1" java.lang.ArithmeticException: / by zero
at test.DivTask.run(DivTask.java:18)
at test.DivTask$1$1.run(DivTask.java:46)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
参考《实战java高并发程序设计》3.2.8堆栈去哪里了