多线程异常 和 事务(二)

1.接着上一篇代码变形一下

首先我们在上一篇文章的基础上把代码变形的面向对象一些

package com.wei.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

public class MultiThreadExceptionAndReturnValSHow {

	public static void main(String[] args) {
		final ThreadFactory threadFactory = new ThreadFactoryBuilder()
				.setNameFormat("Orders-%d-Thread:").build();

		int minPoolSize = 5;
		int maxPoolSize = 10;

		//SynchronousQueue同步队列容量0,就是说线程池没有等待队列
		ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
				minPoolSize, maxPoolSize, 60L, TimeUnit.SECONDS,
				new SynchronousQueue<Runnable>(), threadFactory);

		//测试一个Runnable
		for (int i = 0; i < 5; i++) {
			ExceptionRunThread thread = new ExceptionRunThread();
			threadPoolExecutor.submit(thread);
		}
		//测试一个callable
		for (int i = 0; i < 5; i++) {
			ExceptionCallableThread call = new ExceptionCallableThread();
			threadPoolExecutor.submit(call);
		}
		//测试多个callable
		List<Callable<String>> callList = new ArrayList<Callable<String>>();
		for (int i = 0; i < 5; i++) {
			ExceptionCallable call = new ExceptionCallable();
			callList.add(call);
		}
		invokeAllTask(threadPoolExecutor, callList);
		//等待任务完成后,关闭线程池
		threadPoolExecutor.shutdown();
	}

	private static <T> List<T> invokeAllTask(
			ThreadPoolExecutor threadPoolExecutor, List<Callable<T>> callList) {
		List<Future<T>> futureAll = null;
		List<T> resultList = new ArrayList<T>();
		try {
			futureAll = threadPoolExecutor.invokeAll(callList);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		AtomicInteger in = new AtomicInteger(1);
		for (Future<T> f : futureAll) {
			try {
				T result = f.get();
				System.out.println("count:" + in.getAndIncrement() + ":"
						+ result);
				resultList.add(result);
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
		}
		return resultList;
	}

}

class ExceptionRunThread implements Runnable {

	@Override
	public void run() {
		try {
			System.out.println(Thread.currentThread().getName()
					+ "do something start......");
			if (Thread.currentThread().getName().contains("2")) {
				throw new RuntimeException("测试 uncheck exception");
			}
			Thread.sleep(100);// do something
			System.out.println(Thread.currentThread().getName()
					+ "do something end......");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

class ExceptionCallableThread implements Callable<String> {

	@Override
	public String call() {
		try {
			System.out.println(Thread.currentThread().getName()
					+ "do something start......");
			if (Thread.currentThread().getName().contains("2")) {
				throw new RuntimeException("测试 uncheck exception");
			}
			Thread.sleep(100);// do something
			System.out.println(Thread.currentThread().getName()
					+ "do something end......");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return Thread.currentThread().getName();
	}
}


这里面有有一个重要的地方,就是线程的命名,我们借助google线程工厂的一个类,线程的命名很重要,大家可以把线程数量修改到20,
Run结果

Orders-0-Thread:do something start......
Orders-1-Thread:do something start......
Orders-2-Thread:do something start......
Orders-3-Thread:do something start......
Orders-4-Thread:do something start......
Orders-5-Thread:do something start......
Orders-6-Thread:do something start......
Orders-7-Thread:do something start......
Orders-8-Thread:do something start......
Orders-9-Thread:do something start......
Orders-10-Thread:do something start......
Orders-11-Thread:do something start......
Orders-12-Thread:do something start......
Orders-13-Thread:do something start......
Orders-14-Thread:do something start......
Orders-0-Thread:do something end......
Orders-1-Thread:do something end......
Orders-4-Thread:do something end......
Orders-3-Thread:do something end......
Orders-6-Thread:do something end......
Orders-5-Thread:do something end......
Orders-8-Thread:do something end......
Orders-7-Thread:do something end......
Orders-9-Thread:do something end......
Orders-14-Thread:do something end......
Orders-11-Thread:do something end......
Orders-10-Thread:do something end......
Orders-13-Thread:do something end......
count:1:Orders-10-Thread:
count:2:Orders-11-Thread:
java.util.concurrent.ExecutionException: java.lang.RuntimeException: 测试 uncheck exception
	at java.util.concurrent.FutureTask$Sync.innerGet(Unknown Source)
	at java.util.concurrent.FutureTask.get(Unknown Source)
	at com.wei.service.impl.MultiThreadExceptionAndReturnValSHow.invokeAllTask(MultiThreadExceptionAndReturnValSHow.java:63)
	at com.wei.service.impl.MultiThreadExceptionAndReturnValSHow.main(MultiThreadExceptionAndReturnValSHow.java:46)
Caused by: java.lang.RuntimeException: 测试 uncheck exception
	at com.wei.service.impl.ExceptionCallable.call(MultiThreadExceptionAndReturnVal.java:138)
	at com.wei.service.impl.ExceptionCallable.call(MultiThreadExceptionAndReturnVal.java:1)
	at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
	at java.util.concurrent.FutureTask.run(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)
count:3:Orders-13-Thread:
count:4:Orders-14-Thread:

输出不难理解,线程2和12线程都没有正常结束,而线程12正好运行的是有返回值的所以count:5:orders-12-Thread是异常的。

2下面我们集成到spring中去看,有了上面的代码变形,那么集成到spring中会比较容易

先看线程池业务接口类
package com.wei.service;

import java.util.List;
import java.util.concurrent.Callable;

import com.wei.service.facade.vo.CommonResonse;

public interface MultiThreadTaskExecutorService {

	public <T> CommonResonse<T> invokeAll(List<Callable<T>> taskList);
}
实现类,我们可以看到线程执行器被包在了这个里面
package com.wei.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

import com.alibaba.fastjson.JSON;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.wei.service.MultiThreadTaskExecutorService;
import com.wei.service.facade.vo.CommonResonse;


public class MultiThreadTaskExecutorServiceImpl implements
		MultiThreadTaskExecutorService, InitializingBean, DisposableBean {

	private Logger logger = LoggerFactory.getLogger(this.getClass());
	private ThreadPoolExecutor threadPoolExecutor;
	private int minPoolSize;
	private int maxPoolSize;

	@Override
	public <T> CommonResonse<T> invokeAll(List<Callable<T>> taskList) {
		try {
			List<Future<T>> futures = threadPoolExecutor.invokeAll(taskList);
			List<T> resultList = new ArrayList<T>();
			for (Future<T> future : futures) {
				try {
					resultList.add(future.get());
				} catch (ExecutionException e) {
					e.printStackTrace();
				}
			}
			logger.info("result={}",JSON.toJSONString(resultList));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public void destroy() throws Exception {
		threadPoolExecutor.shutdown();
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		final ThreadFactory threadFactory = new ThreadFactoryBuilder()
        .setNameFormat("Orders-%d")
        .build();
		threadPoolExecutor = new ThreadPoolExecutor(minPoolSize, maxPoolSize,
				60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(),threadFactory);
	}

	public int getMinPoolSize() {
		return minPoolSize;
	}

	public void setMinPoolSize(int minPoolSize) {
		this.minPoolSize = minPoolSize;
	}

	public int getMaxPoolSize() {
		return maxPoolSize;
	}

	public void setMaxPoolSize(int maxPoolSize) {
		this.maxPoolSize = maxPoolSize;
	}

}


xm里bean的配置
	<bean id="multiThreadTaskExecutorService"
		class="com.wei.service.impl.MultiThreadTaskExecutorServiceImpl">
		<property name="minPoolSize" value="5" />
		<property name="maxPoolSize" value="10" />
	</bean>

aop事务的配置
<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
		</tx:attributes>
	</tx:advice>
	<aop:config>
		<aop:pointcut id="servicePiontCut"
			expression="execution(* com.wei.service..*(..))" />
		<aop:advisor advice-ref="txAdvice" pointcut-ref="servicePiontCut" />
	</aop:config>


在看业务接口类
package com.wei.service;

import java.util.List;
import java.util.concurrent.Callable;

import com.wei.dao.entity.User;


public interface CallTaskService extends Callable<List<User>>{

	List<User> call();
}

package com.wei.service;

import java.util.List;
import java.util.concurrent.Callable;

import com.wei.dao.entity.User;


public interface CallTask2Service extends Callable<List<User>>{

	List<User> call();
}


业务接口实现
package com.wei.service.impl;

import java.util.List;
import java.util.concurrent.Callable;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.wei.dao.entity.User;
import com.wei.dao.mapper.UserMapper;
import com.wei.service.CallTaskService;

@Service
public class CallTaskServiceImpl implements CallTaskService ,Callable<List<User>>{


	@Autowired
	UserMapper userMapper;
	
	@Override
	public List<User> call() {
		return userMapper.select(null);
	}
}

下面是依赖这几个接口的测试类,接口没有写大家自己补一下
package com.wei.service.impl;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;

import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.wei.dao.entity.User;
import com.wei.dao.mapper.UserMapper;
import com.wei.service.CallTask2Service;
import com.wei.service.CallTaskService;
import com.wei.service.MultiThreadTaskExecutorService;
import com.wei.service.UserService;
import com.wei.service.vo.UserVo;

@Service
public class UserServiceImpl implements UserService{

	@Autowired
	UserMapper userMapper;
	@Autowired
	CallTask2Service callTask2Service;
	@Autowired
	CallTaskService callTaskService;
	@Autowired
	MultiThreadTaskExecutorService multiThreadTaskExecutorService;
	
	@Override
	public void testThreadRollBack(UserVo userVo) {
		List<Callable<List<User>>> taskList=new ArrayList<Callable<List<User>>>();
//		taskList.add(new Callable<List<User>>() {
//			@Override
//			public List<User> call() throws Exception {
//				System.out.println("---------->"+"select");
//				return userMapper.select(null);
//			}
//		});
//		taskList.add(new Callable<List<User>>() {
//			@Override
//			public List<User> call() throws Exception {
//				User user=new User();
//				user.setCreateDate(new Date());
//				SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//				user.setId("rollbank20160421-"+sdf.format(new Date()));
//				user.setName("rollback"+sdf.format(new Date()));
//				user.setPassword("2222222");
//				userMapper.insert(user);
//				System.out.println("---------->"+"insert and select");
//				userMapper.select(null);
//				int i=1/0;
//				return userMapper.select(null);
//			}
//		});
		taskList.add(callTask2Service);
		taskList.add(callTaskService);
		multiThreadTaskExecutorService.invokeAll(taskList);
//		User user=new User();
//		user.setCreateDate(new Date());
//		SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//		user.setId("rollbank20160421-"+sdf.format(new Date()));
//		user.setName("rollback"+sdf.format(new Date()));
//		user.setPassword("11111111");
//		userMapper.insert(user);
		int i=1/0;
	}

}

通过测试,结果我就不贴出来了,我们可以看到只要是spring托管的bean切面的事务就是起作用的,new的就没有事务,runnable和callable也一样,new出来的匿名内部类spring不管理他的事务,因为他没有交给spring托管。想开启事务要自己编码。
另外线程之间也是没有影响的,一个线程异常结束,不会影响其他线程,仔细想想道理都知道,还是做实验区印证了下。再重复下, 只有spring托管的bean才会去管理事务,自己new出来的不管理事务,相信自己学的,重要的说三遍,标红吧。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值