3.2.8 堆栈去哪里了:在线程池中寻找堆栈
public class TheadFind {
public static class TestThread implements Runnable{
int a,b;
public TestThread(int a,int b) {
this.a=a;
this.b=b;
}
public void run() {
double re=a/b;
System.out.println(re);
}
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int i = 0; i < 5; i++) {
executorService.submit(new TestThread(100,i));
}
}
}
运行结果如下:
100.0
33.0
25.0
50.0
细心的你肯定会说,我们明明是开启了5个线程,为什么会得到4个结果呢,即使是100/0,那么也会报异常,为什么会没有呢。难道是线程池把错了“吃了吗?”。对于我们来说如果发现错误但是没有异常信息那是一件多么可怕的事情啊。
所以线程池好用,但是也存在我们所说的坑啊。上面的问题,最简单的解决方案是 将 submit()方法替换 execute(),运行结果如下:
100.0
Exception in thread "pool-1-thread-1" java.lang.ArithmeticException: / by zero
50.0
at 第三章.堆栈去哪里了.在线程池中寻找堆栈$TestThread.run(在线程池中寻找堆栈.java:19)
33.0
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
25.0
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
at java.lang.Thread.run(Thread.java:662)
第二种:
Future submit = executorService.submit(new TestThread(100, i));
try {
submit.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
很明显我们发现了错误。所以大家在以后使用线程池的时候 一定要谨慎,一定要避免吃掉异常这一现象。
当然 以上只是能满足我们部分的需求,那么为了避免出现此类情况,在初期我们麻烦一点,将其封装下(以下是我给出的范例)
package 第三章.堆栈去哪里了;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Created by zzq on 2018/2/8.
*/
public class TraceThreadPoolExecutor extends ThreadPoolExecutor{
public TraceThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
public void execute(Runnable task) {
super.execute(wrap(task, clientTrace(Thread.currentThread().getName()), Thread.currentThread().getName()));
}
private Runnable wrap(final Runnable task, final Exception clientTrace, final String name) {
return new Runnable() {
public void run() {
try {
task.run();
} catch (Exception e) {
clientTrace.printStackTrace();
try {
throw e;
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
};
}
private Exception clientTrace(String name) {
return new Exception("Client stack trace------"+name);
}
public static class TestThread implements Runnable{
int a,b;
public TestThread(int a,int b,String name) {
this.a=a;
this.b=b;
Thread.currentThread().setName(name);
}
public void run() {
double re=a/b;
System.out.println(re);
}
}
public static void main(String[] args) {
TraceThreadPoolExecutor traceThreadPoolExecutor=new TraceThreadPoolExecutor(5,5,0l,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(5));
for (int i = 0; i < 5; i++) {
traceThreadPoolExecutor.execute(new TestThread(100,i,"第--"+i+"个"));
// executorService.execute(new TestThread(100,i));
}
}
}
那么我们就可以定位问题出现的位置,尽快解决。
submit和excuce 方法,一个是void 一个是Future 所以excuce直接抛出异常, Future为一个sync,里面包含callable,exception,如果通过get方法,发现 exception不为空,那么就抛异常。