java学习总结——线程中异常的处理

       异常分为可检查异常(checked exception)和不可检查异常(unchecked exception);对于可检查异常,必须在代码中进行显示的处理,要么通过throws关键字抛出,要么通过try{  }catch块处理。而对于不可检查异常(运行时发生的异常),不需要显示的处理。也就是说,不可检查异常不需要throws关键字抛出,也不需要catch块处理,前提是你不想处理。 示例代码:

public class RunnableThread implements Runnable{
	
	private int number;

	public RunnableThread(int number) {
		this.number = number;
	}

	@Override
	public void run() {
		 //throw new RuntimeException(); //不可检查异常(运行时异常),可以编译通过
		 throw new FileNotFoundException();//可检查异常,编译不通过
	}
}

public class RunnableThread implements Runnable{
	
	private int number;

	public RunnableThread(int number) {
		this.number = number;
	}

	@Override
	public void run() {
		//throw new RuntimeException();
		try {
			throw new FileNotFoundException(); //可检查异常,必须显示的处理
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} 
		 
		try {
			throwException(); //throwException将自己方法体内部的异常直接抛出,然后run方法不能直接抛出异常,所以必须使用catch块处理
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	 
	public void throwException() throws Exception{ //将方法体内部的异常直接抛出
		throw new NullPointerException();
	}
}

再看一段示例代码:

public class ThreadTest13 {

	public static void main(String[] args) throws Exception {
		   RunnableThread runnableThread = new RunnableThread(1);
		   Thread thread1 = new Thread(runnableThread);
		   try{
			   thread1.start();
		   }catch(Exception e){
			   System.out.println("异常被捕获!!!"); //这里虽然声明了catch块,但是是捕捉不到线程中抛出的异常的
		   }
	}
}

public class RunnableThread implements Runnable{
	
	private int number;

	public RunnableThread(int number) {
		this.number = number;
	}

	@Override
	public void run() {
		 int number = 1/0; //0不能做被除数,这里会抛出运行时异常:ArithmeticException
	}
}

//输出结果(没有打印出“异常被捕获”):
//Exception in thread "Thread-0" java.lang.ArithmeticException: / by zero 
从上面的两段代码中可以得出两个结论:1、run方法不能直接显示的抛出非运行时异常;2、run方法中的运行时异常不能被主线程捕获。 那该如何处理线程中抛出的异常呢?

 一、线程中运行时异常的处理

        JDK中有一个UncaughtExceptionHandler接口,叫做异常捕捉器。主要是用来捕获线程中抛出的异常的。通过示例代码看一下如何使用这个接口:

public class ExceptionHandler implements  UncaughtExceptionHandler{ //创建一个异常处理器类

	@Override
	public void uncaughtException(Thread t, Throwable e) {
		 System.out.println("异常捕获成功!!");
	}
}

public class RunnableThread implements Runnable{
	
	private int number;

	public RunnableThread(int number) {
		this.number = number;
	}

	@Override
	public void run() {
		 int number = 1/0; //0不能是做被除数,这里会抛出运行时异常:ArithmeticException
	}
}

public class ThreadTest13 {

	public static void main(String[] args) throws Exception {
		   RunnableThread runnableThread = new RunnableThread(1);
		   Thread thread1 = new Thread(runnableThread);
		   thread1.setUncaughtExceptionHandler(new ExceptionHandler()); //创建一个异常处理实例,并将其加入线程中。加入的时机是:异常发生之前。即setUncaughtExceptionHandler方法可以在start方法之后,抛出异常之前执行,也可以捕捉到异常。
		   thread1.start();
	}
}

//输出结果:异常捕获成功!!
上面的代码中已经成功的捕获了异常。

        对于线程异常的处理还有两种辅助的方式:1、如果线程不传入异常捕捉器,就使用默认的异常捕捉器;2、线程组(多个线程的集合)的异常处理。示例代码:

//线程实例对象级别的处理器
public class ExceptionHandler implements  UncaughtExceptionHandler{ //创建一个异常处理器类

	@Override
	public void uncaughtException(Thread t, Throwable e) {
		 System.out.println("异常捕获成功!!");
	}
}

//类级别的异常处理器
public class ThreadClassExceptionHandler implements UncaughtExceptionHandler{

	@Override
	public void uncaughtException(Thread t, Throwable e) {
		 System.out.println(t.getName()+" 线程实例,异常被Thread类捕获!!");
	}
}

//线程组级别的异常处理
public class ThreadGroupException extends ThreadGroup{ //处理方式有些不同,是重写uncaughtException方法

	public ThreadGroupException(String name){
		super(name);
	}
	
	@Override
	public void uncaughtException(Thread t, Throwable e) { //线程组异常处理
		 System.out.println(t.getName()+" 线程实例,异常被ThreadGroup捕获!!");
	}
}

public class RunnableThread implements Runnable{
	
	private int number;

	public RunnableThread(int number) {
		this.number = number;
	}

	@Override
	public void run() {
		 int number = 1/0; //0不能是做被除数,这里会抛出运行时异常:ArithmeticException
	}
}

public class ThreadTest13 {

	public static void main(String[] args) throws Exception {
		   Thread.setDefaultUncaughtExceptionHandler(new ThreadClassExceptionHandler());//这个是Thread类级别的处理器,所有线程实例都可以使用
		   ThreadGroupException threadGroup = new ThreadGroupException("threadGroup"); //创建线程组
		
		   RunnableThread runnableThread = new RunnableThread(1);
		   Thread thread1 = new Thread(threadGroup,runnableThread);//将thread1线程加入线程组中 
		   thread1.setName("Thread-1");
		   thread1.setUncaughtExceptionHandler(new ExceptionHandler()); //传入异常处理器
		   thread1.start();
		   
		   Thread thread2 = new Thread(threadGroup,runnableThread); //将thread2线程加入线程组中。没有传入异常处理器
		   thread2.setName("Thread-2");
		   thread2.start();
	}
}

//输出结果:
//Thread-2 线程实例,异常被ThreadGroup捕获!!
//Thread-1 线程实例,异常被捕获!!
从代码中可以看到:

      1、线程实例对象有自己的异常处理器时,会优先被调用;

      2、线程实例对象没有自己的处理器时,但线程所在线程组重新覆写了异常处理方法,此时会调用线程组的异常处理方法;

      3、当线程实例对象没有自己的处理器,且所在线程组中也没有重新定义异常处理方法,则会调用Thread类的默认异常处理器(这里可以通过把ThreadGroupException中的uncaughtException注释掉进行验证),如果有默认的处理器的话。如果没有默认的处理器,则会直接抛出异常。

所以得到的异常处理器调用顺序是:线程对象 > 线程组 > Thread


二、线程中非运行时异常的处理

     在run方法中, 对于非运行时异常的处理,除了可以使用catch块来处理之外,还可以将非运行时异常转换成运行时异常抛出。示例代码;

//异常处理器
public class ExceptionHandler implements  UncaughtExceptionHandler{

	@Override
	public void uncaughtException(Thread t, Throwable e) {
		 System.out.println(t.getName()+" 线程实例,异常被捕获!!");
	}
}

public class RunnableThread implements Runnable{
	
	private int number;

	public RunnableThread(int number) {
		this.number = number;
	}

	@Override
	public void run() {
	    String name = Thread.currentThread().getName();
	    if("Thread-1".equals(name)){ //Thread-1执行抛出异常
	    	int number = 1/0; //0不能是做被除数,这里会抛出运行时异常:ArithmeticException
	    }
		 
		if("Thread-2".equals(name)){//Thread-2执行抛出异常
			try {
				throw new FileNotFoundException();
			} catch (FileNotFoundException e) {
				throw new RuntimeException(e); //转换成运行时异常抛出
			} 
		}
		 
		if("Thread-3".equals(name)){ //Thread-3执行抛出异常
			try {
				throwException(); 
			} catch (Exception e) {
				throw new RuntimeException(e);//转换成运行时异常抛出
			}
		}
	}

	public void throwException() throws Exception{
		throw new IOException();
	}
}

public class ThreadTest13 {

	public static void main(String[] args) throws Exception {
		   RunnableThread runnableThread = new RunnableThread(1);
		   Thread thread1 = new Thread(runnableThread); 
		   thread1.setName("Thread-1");
		   thread1.setUncaughtExceptionHandler(new ExceptionHandler()); //传入异常处理器
		   thread1.start();
		   
		   Thread thread2 = new Thread(runnableThread); 
		   thread2.setUncaughtExceptionHandler(new ExceptionHandler()); //传入异常处理器
		   thread2.setName("Thread-2");
		   thread2.start();
		   
		   Thread thread3 = new Thread(runnableThread); 
		   thread3.setUncaughtExceptionHandler(new ExceptionHandler()); //传入异常处理器
		   thread3.setName("Thread-3");
		   thread3.start();
	}
}

//输出结果:
//Thread-2 线程实例,异常被捕获!!
//Thread-3 线程实例,异常被捕获!!
//Thread-1 线程实例,异常被捕获!!
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值