子线程中的异常在主线程中是不可以catch的
在spring中主线程有事务,那么子线程中有事务么?
捕获异常
我们使用多线程时,会涉及到某些线程执行失败了,而抛出异常,但是主线程却捕捉不到子线程的异常。这时候我们就要处理一下子线程的异常,然后让主线程捕获到。
使用的是多线程的话:我们使用
ThreadOperation threadOperation= new ThreadOperation();
Thread innerThread = new Thread(threadOperation);
innerThread.setUncaughtExceptionHandler(new ExceptionHandle());
innerThread.start();
可以通过上面的四行代码来捕获到异常
具体代码如下:
package com.chuxin.fight.demo.thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* @FileName: MutiThreadException
* @Description: 多线程的异常处理
* @author: <a href="***@163.com">myp</a>
* @create: 2019-01-08 17:06
*/
public class MutiThreadException {
//https://blog.csdn.net/weijiaxiaobao/article/details/51217265
public static void main(String[] args) {
System.out.println("MutiThreadException.main()------>start<------");
try {
List<Future<Object>> resultList = new ArrayList<>();
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(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("id "+Thread.currentThread().getName()+"----end:");
}
});
//不是用线程池执行线程,使用循环的方式创建多线程,那么就用下面这两行和ExceptionHandle类来捕获子线程中的异常
// t.setUncaughtExceptionHandler(new ExceptionHandle());
// t.start();
//使用线程池的方式执行线程,如果子线程有异常的话,ExecutorService就已经捕获到了,我们可以从future对象中获取异常。正常情况下future对象中获取的是null,有异常的话获取到的就是异常信息
Future<Object> future = (Future<Object>) service.submit(t);
resultList.add(future);
}
for(Future f:resultList){
//在这里遍历就可以获取到future里面的异常,如果获取到的是null就说明成功执行了,没有异常。这里使用future的get方法时必须使用try catch才能获取到future对象里面的异常
try {
Object o=f.get();
System.out.println(o);
} catch (Exception e) {
System.out.println(e.toString()+"===========================");
}
}
service.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("MutiThreadException.main()------>end<------");
}
}
package com.chuxin.fight.demo.thread;
/**
* @FileName: ExceptionHandle
* @Description: ExceptionHandle
* @author: <a href="mailto:***@163.com">myp</a>
* @create: 2019-01-08 17:11
*/
public class ExceptionHandle implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("子线程的异常,通过主线程捕获到了");
}
}
事务控制
在事务内另起线程是实现不了的
只有spring托管的bean才会去管理事务,自己new出来的不管理事务
举个例子,如果我们多线程运行的任务是一个添加的方法,如果某个线程添加失败的时候,我们需要事务控制。
如果我们在主线程上面直接使用注解@Transactional来控制事务是不好使的,我们需要控制的是子线程的事务,所以这里提供的解决办法就是,我们run方法里面调用的添加方法不放在当前类里面,放在其他的类里面,然后将那个类通过注入的方法注入到当前的类里面,然后通过那个类进行调用,这样事务就可以通过使用注解@Transactional来控制事务了。同样也就解释了上面红色字体的那句话,我们通过注入的方式来使用添加方法,那么那个类(也就是一个Bean)就交给spring托管了,这样spring就帮我们管理事务了。
图例.png
需要在B类里面的添加方法上面添加注解@Transactional
网友评论