扩展ThreadPoolExecutor打印线程错误堆栈

来源:互联网 发布:python 判断加载完成 编辑:程序博客网 时间:2024/06/05 05:42

在使用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;}@Overridepublic 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.025.033.050.0

我们可以将submit方法改成execute方法或者使用 Future  re = pools.submit(new DivTask(100,i)); re.get()来打印错误堆栈,改后输出如下:

Exception in thread "pool-1-thread-1" java.lang.ArithmeticException: / by zeroat 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.025.050.033.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;}@Overridepublic 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>()){@Overridepublic void execute(Runnable command) {Runnable newCommand = wrap(command,clientTrace(),Thread.currentThread().getName());super.execute(newCommand);}@Overridepublic 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(){@Overridepublic 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堆栈去哪里了

0 0
原创粉丝点击