Java高效并发(九)----扩展线程池寻找堆栈信息

线程池的异常堆栈

使用线程池实现高并发会更有可能出现一些意想不到的异常,而线程池往往可能会“吃”点这些异常,就是我们常说的Runnable没有返回值,不能抛出受检查的异常。让我们的结果有误但是却不给我们异常信息。要排查这些异常找出问题所在,我们就要分析异常堆栈,追踪问题出在哪里。

让线程池返回异常堆栈的信息,最简单的就是在线程池提交任务的时候不用submit(),而是改用execute()方法

Future<?> submit(Runnable task);位于java.util.concurrent.ExecutorService接口中

void execute(Runnable command);位于java.util.concurrent.Executor接口

比如下面这个例子,在程序中让100除以5个数,其中一个数是0,本来要抛出异常,可是使用submit却没有

package xidian.lili.reentrantlock;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
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) {
		ExecutorService pool=new ThreadPoolExecutor(0,Integer.MAX_VALUE,0L,TimeUnit.MILLISECONDS,new SynchronousQueue<Runnable>());
		for(int i=0;i<5;i++){
			DivTask task=new DivTask(100,i);
			pool.submit(task);
			//pool.execute(task);
		}
	//	System.out.println(100/0);
	}
}

结果:

 改用execute(task),可以看到部分堆栈信息

 或者也可以使用下面的submit,也可以捕获部分堆栈信息。我们常说Callable是有返回值的。Future一般我们认为是Callable的返回值,但他其实代表的是任务的生命周期(当然了,它是能获取得到Callable的返回值的)

Future re=pool.submit(task);
			try {
				re.get();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}

结果:

 

但是这样的异常只告诉我们异常是哪里抛出的,看不到任务是在哪里提交的

所以扩展ThreadPoolExecutor,重写submit方法和execute方法

和上一篇扩展方式不同,上一篇再用内名内部类,简单的重写了三个方法,进行拓展

这次我们通过继承实现新的带追踪追站的我们自己的线程池类,通过继承,我们调用父类的构造方法创建线程池,但是重写submit和execute方法,其实就是对提交过来的任务进行包装成一个新的任务。

command使我们原本提交过来的任务,我们在包装任务(wrap是想runnable接口)中执行这个任务,并用try-catch捕获并抛出任务执行中可能遇到的异常

其实就是run方法嵌套

private Runnable wrap(Runnable command, Exception clientTrace, String Threadname) {
        return new Runnable(){

            @Override
            public void run() {
                try{
                    command.run();//执行原本任务时捕获异常
                }catch(Exception e){
                    clientTrace.printStackTrace();
                    throw e;//抛出原本任务中的异常
                }
            }
            
        };
    }

package xidian.lili.reentrantlock;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TraceThreadPoolExecutor extends ThreadPoolExecutor{

	public TraceThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
			BlockingQueue<Runnable> workQueue) {
		super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
	}

	@Override
	public void execute(Runnable command) {
		super.execute(wrap(command,clientTrace(),Thread.currentThread().getName()));
	}

	private Runnable wrap(Runnable command, Exception clientTrace, String Threadname) {
		return new Runnable(){

			@Override
			public void run() {
				try{
					command.run();
				}catch(Exception e){
					clientTrace.printStackTrace();
					throw e;
				}
			}
			
		};
	}

	private Exception clientTrace() {		
		return new Exception("Client stack trace");
	}

	@Override
	public Future<?> submit(Runnable task) {
		return super.submit(wrap(task,clientTrace(),Thread.currentThread().getName()));

	}
	
}

这样我们用我们自己的线程池类创建线程池并进行实验    

package xidian.lili.reentrantlock;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class DivTaskTrace implements Runnable{
	int a,b;
	public DivTaskTrace(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) {
		ExecutorService pool=new TraceThreadPoolExecutor(0,Integer.MAX_VALUE,0L,TimeUnit.MILLISECONDS,new SynchronousQueue<Runnable>());
		for(int i=0;i<5;i++){
			DivTask task=new DivTask(100,i);
			//pool.submit(task);
			/*
			Future re=pool.submit(task);
			try {
				re.get();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
			*/
			pool.execute(task);
		}
	}
}

 得到的结果:

在java除法中,允许浮点数运算时除数为零,所得结果是Infinity

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值