多线程异常 和 事务(一)

1,首先提出几个问题:


1.1,子线程中的异常在主线程中是否可以catch

1.2,在spring中主线程有事务,那么子线程中有事务码


2,先看第一个问题


2.1,我们在main方法里面测试,代码如下

package com.pingan.test.call;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;


public class MutiThreadException {

	
	public static void main(String[] args) {
		System.out.println("MutiThreadException.main()------>start<------");
		try {
			List<Future<Object>> resultList = new ArrayList<Future<Object>>();  
//			ExceptionHandle exceptionHandle = new ExceptionHandle();
			ExecutorService service=Executors.newFixedThreadPool(6);
			for (int i = 0; i < 3; i++) {
				Thread t=new Thread(new  Runnable() {
					@Override
					public void run() {
						System.out.println("id "+Thread.currentThread().getName()+"---start>");
						if(Thread.currentThread().getName().endsWith("2")){
//							int i=1/0;
							  throw new RuntimeException();  
						}
						try {
							Thread.sleep(2000);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						System.out.println("id "+Thread.currentThread().getName()+"----end:");
					}
				});
//				t.setUncaughtExceptionHandler(new ExceptionHandle());
				t.start();
//				Future<Object> future = (Future<Object>) service.submit(t);
//				resultList.add(future);
			}
//			for(Future f:resultList){
//				Object o=f.get();
//				System.out.println(o);
//			}
//			service.shutdown();
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("MutiThreadException.main()------>end<------");
	}
}

run后的结果如下

MutiThreadException.main()------>start<------
id Thread-0---start>
id Thread-1---start>
MutiThreadException.main()------>end<------
id Thread-2---start>
Exception in thread "Thread-2" java.lang.RuntimeException
	at com.pingan.test.call.MutiThreadException$1.run(MutiThreadException.java:26)
	at java.lang.Thread.run(Thread.java:662)
id Thread-0----end:
id Thread-1----end:
可以看出日志打印了异常,是否就说明我们catch到了异常呢,答案:否。我们可以吧catch中的 e.printStackTrace()注释,然后再次运行,会发现结果依然一样。
什么原因呢,其实是异常在子线程中逃逸到了控制台,并没有被主线程catch到。thread的run方法不允许抛出异常,所以我们要在线程里自己处理,对于运行时异常如果没有catch那么就逃逸到控制台。
当然API也提供了一个接口UncaughtExceptionHandler,我们实现就可以然后在set到线程中,代码如下
package com.pingan.test.call;

import java.lang.Thread.UncaughtExceptionHandler;

public class ExceptionHandle implements UncaughtExceptionHandler{

	@Override
	public void uncaughtException(Thread t, Throwable e) {
		System.out.println("ExceptionHandle.uncaughtException()");
	}

	
}

2.2,我们把测试代码中的这一行注释掉t.setUncaughtExceptionHandler(new ExceptionHandle());
run后的结果如下:

MutiThreadException.main()------>start<------
id Thread-0---start>
id Thread-1---start>
MutiThreadException.main()------>end<------
id Thread-2---start>
ExceptionHandle.uncaughtException()
id Thread-1----end:
id Thread-0----end:

可以看到异常被内部捕获处理掉,但是id Thread-2---end没有打印,说明线程异常后直接结束了,没有走下面的代码。所以我觉得这个接口没有实际的应用场景。

2.3,如果要是用线程池呢

我们注释掉这两行

t.setUncaughtExceptionHandler(new ExceptionHandle());

t.start();

这两行放开注释 

Future<Object> future = (Future<Object>) service.submit(t);

service.shutdown();

Run代码运行如下

MutiThreadException.main()------>start<------
MutiThreadException.main()------>end<------
id pool-1-thread-1---start>
id pool-1-thread-2---start>
id pool-1-thread-3---start>
id pool-1-thread-1----end:
id pool-1-thread-3----end:

可以看到控制台没有异常,说明ExecutorService已经处理过了,那我们怎么知道子线程是否有异常呢,代码中我们看到submit是有返回值的,修改测试代码如下

package com.pingan.test.call;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;


public class MutiThreadException {

	
	public static void main(String[] args) {
		System.out.println("MutiThreadException.main()------>start<------");
		ExecutorService service=null;
		try {
			List<Future<Object>> resultList = new ArrayList<Future<Object>>();  
//			ExceptionHandle exceptionHandle = new ExceptionHandle();
			service=Executors.newFixedThreadPool(6);
			for (int i = 0; i < 3; i++) {
				Thread t=new Thread(new  Runnable() {
					@Override
					public void run() {
						System.out.println("id "+Thread.currentThread().getName()+"---start>");

						if(Thread.currentThread().getName().endsWith("1")){
							try {
								Thread.sleep(2000);
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
							int i=1/0;
//							  throw new RuntimeException();  
						}
						if(Thread.currentThread().getName().endsWith("2")){
							try {
								Thread.sleep(1000);
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
//							int i=1/0;
							  throw new RuntimeException();  
						}
						try {
							Thread.sleep(1000);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						System.out.println("id "+Thread.currentThread().getName()+"----end:");
					}
				});
//				t.setUncaughtExceptionHandler(new ExceptionHandle());
//				t.start();
				Future<Object> future = (Future<Object>) service.submit(t);
				resultList.add(future);
			}
			System.out.println("resultList.size:"+resultList.size());
			for(Future<Object> f:resultList){
				System.out.println("f------>"+f);
				Object o=null;
//				try {
					o=f.get();
//				} catch (ExecutionException  e) {
//					e.printStackTrace();
//				}
//				System.out.println(o);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			service.shutdown();
		}
		System.out.println("MutiThreadException.main()------>end<------");
	}
}


Run运行结果如下

MutiThreadException.main()------>start<------
id pool-1-thread-1---start>
id pool-1-thread-2---start>
resultList.size:3
id pool-1-thread-3---start>
f------>java.util.concurrent.FutureTask@7d67d940
id pool-1-thread-3----end:
java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
	at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222)
	at java.util.concurrent.FutureTask.get(FutureTask.java:83)
	at com.pingan.test.call.MutiThreadException.main(MutiThreadException.java:63)
Caused by: java.lang.ArithmeticException: / by zero
	at com.pingan.test.call.MutiThreadException$1.run(MutiThreadException.java:33)
	at java.lang.Thread.run(Thread.java:662)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
	at java.util.concurrent.FutureTask.run(FutureTask.java:138)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
	at java.lang.Thread.run(Thread.java:662)
MutiThreadException.main()------>end<------

这个里面信息还是比较多的,可以看到线程1和2都没有结束,打印的异常是线程1抛出的异常,线程1一共休眠了3秒,线程2休眠了2秒,为什么线程1的异常打印了而没有打印1的异常呢?为什么?为什么呢?
这里要怪我烦的错误,我们是吧Futrue放到List里面然后遍历获取的,肯定是按顺序获取线程1,2,3的结果的,当获取1的时候f.get方法就抛了异常了,方法直接就结束了。所以我们修改代码吧f.get()方法try/catch住,捕获ExecutionException捕获执行异常,再次运行

MutiThreadException.main()------>start<------
id pool-1-thread-1---start>
id pool-1-thread-2---start>
resultList.size:3
id pool-1-thread-3---start>
f------>java.util.concurrent.FutureTask@2ce83912
id pool-1-thread-3----end:
java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
	at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222)
	at java.util.concurrent.FutureTask.get(FutureTask.java:83)
	at com.pingan.test.call.MutiThreadException.main(MutiThreadException.java:63)
Caused by: java.lang.ArithmeticException: / by zero
	at com.pingan.test.call.MutiThreadException$1.run(MutiThreadException.java:33)
	at java.lang.Thread.run(Thread.java:662)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)null
f------>java.util.concurrent.FutureTask@4318f375

	at java.util.concurrent.FutureTask.run(FutureTask.java:138)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
	at java.lang.Thread.run(Thread.java:662)
java.util.concurrent.ExecutionException: java.lang.RuntimeException
	at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222)
	at java.util.concurrent.FutureTask.get(FutureTask.java:83)
	at com.pingan.test.call.MutiThreadException.main(MutiThreadException.java:63)
Caused by: java.lang.RuntimeException
	at com.pingan.test.call.MutiThreadException$1.run(MutiThreadException.java:43)
	at java.lang.Thread.run(Thread.java:662)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
	at java.util.concurrent.FutureTask.run(FutureTask.java:138)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
	at java.lang.Thread.run(Thread.java:662)
null
f------>java.util.concurrent.FutureTask@1b17a8bd
null
MutiThreadException.main()------>end<------

这次看到两个异常都捕获到了我们在主线程拿到了子线程抛出的异常。上面犯错要反省一下,什么原因导致我烦的错误呢,就是我在最外面用EXCEPTION捕获的所有异常,所以eclipse没有提示f.get()方法的异常。我们应该在for循环的里面捕获异常,让循环走下去。日志还有一个信息那就是返回值我们看到是null,因为thread的run方法确实没有返回值。


感觉文章有点长了,下面文章接着继续,我们在spring中看下关于事务的问题





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值