工具类
工具类
public class ThreadPool3<T,K> {
//单个线程处理的数据量
private int singleCount;
//处理的总数据量
private int listSize;
//开启的线程数
private int runSize;
//操作的数据集
private List<T> list;
//计数器
private CountDownLatch begin,end;
//线程池
private ExecutorService executorService;
//回调
private CallBack<T,K> callBack;
//每个线程的结果集
List<Future<K>> result;
public void setCallBack(CallBack<T,K> callBack) {
this.callBack = callBack;
}
public ThreadPool3(int singleCount, List<T> list){
this.singleCount = singleCount;
this.list = list;
if (list != null){
this.listSize = list.size();
this.runSize = (this.listSize/this.singleCount) + 1;
}
result = new ArrayList<>( );
}
public List<Future<K>> excute() throws InterruptedException {
executorService = Executors.newFixedThreadPool(runSize);
begin = new CountDownLatch(1);
end = new CountDownLatch(runSize);
//创建线程
int startIndex = 0;
int endIndex = 0;
List<T> newList = null;
for (int i = 0; i < runSize; i++) {
//计算每个线程对应的数据
if (i < (runSize - 1)){
startIndex = i * singleCount;
endIndex = (i + 1) * singleCount;
newList = list.subList(startIndex,endIndex);
}else {
startIndex = i * singleCount;
endIndex = listSize;
newList = list.subList(startIndex,endIndex);
}
//创建线程类处理数据
MyThread<T,K> myThread = new MyThread<T,K>(newList, begin, end) {
@Override
public K method(List<T> list) {
return callBack.method( list );
}
};
//执行线程
Future<K> submit = executorService.submit( myThread );
result.add( submit );
}
//计数器减一
begin.countDown();
end.await();
//关闭线程池
executorService.shutdown();
return result;
}
//抽象线程类
public abstract class MyThread<T,K> implements Callable<K> {
private List<T> list;
private CountDownLatch begin,end;
public MyThread(List<T> list, CountDownLatch begin, CountDownLatch end){
this.list = list;
this.begin = begin;
this.end = end;
}
@Override
public K call() throws Exception {
try {
//执行程序
K k = method(list);
begin.await();
return k;
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//计数器减一
end.countDown();
}
return null;
}
public abstract K method(List<T> list);
}
//回调接口定义
public interface CallBack<T,K>{
public K method(List<T> list);
}
}
线程回调返回值的类
@Data
public class ThreadResult {
private String threadName;
private Integer code;
private String msg;
}
测试实体类
@Data
public class Pool {
@TableId(type= IdType.AUTO)
private Integer id;
private String name;
private Integer type = (int)new Random( ).nextInt( 10 );
}
事务测试
1.传统spring事务能控制吗?
@Override
public void test() throws InterruptedException {
long start = System.currentTimeMillis();
List<Pool> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
Pool pool = new Pool();
pool.setName( "hello"+i );
list.add(pool);
}
ThreadPool3<Pool, ThreadResult> threadPool3 = new ThreadPool3<>( 1000,list );
threadPool3.setCallBack( new ThreadPool3.CallBack<Pool, ThreadResult>() {
@Override
public ThreadResult method(List<Pool> list) {
ThreadResult threadResult = new ThreadResult();
//数据处理
try {
for (int i = 0; i < list.size(); i++) {
if (list.get( i ).getName().equals( "hello4789" )) {
int temp = 1 / 0;
}
poolRepository.insert( list.get( i ) );
}
threadResult.setCode( 200 );
threadResult.setMsg( null );
threadResult.setThreadName( Thread.currentThread().getName() );
}catch (Exception e){
log.error( "线程:{},错误信息:{}",Thread.currentThread().getName(),e.getMessage() );
threadResult.setCode( 500 );
threadResult.setMsg( e.getMessage() );
threadResult.setThreadName( Thread.currentThread().getName() );
}
return threadResult;
}
} );
List<Future<ThreadResult>> excute = threadPool3.excute();
}
我故意在name 这一块抛出一个异常,自己在捕获一下。正常按照事务的准则来说应该是这个子线程回滚或者主线程回滚,因为每个子线程数据都是规则排序好的,是但是经过查询数据来说,该子线程对应的数据hello4000 - hello4999,但是hello4789(包括在内)-hello4999的数据都是null,这就说明该子线程在抛出异常后没进行回滚,而是终止了这个线程
结论:主线程上家@Transactional 对子线程无效
原因:spring保证事务的原因是因为connection 是一个就可以设置事务,而每个线程的connection都是通过ThreadLocal保存的(我不知道InheritableThreadLocal有用吗)
2.保证单个线程的事务性
分析:上面也说了事务是针对线程的,那自己单个在抛出异常的时候手动回滚
@Autowired
private PlatformTransactionManager platformTransactionManager;
@Autowired
private TransactionDefinition transactionDefinition;
TransactionStatus transactionStatus = null;
transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
platformTransactionManager.commit(transactionStatus);
platformTransactionManager.rollback(transactionStatus);
关键编程式事务回滚代码就是这几行了
再次测试后发现只有9000条数据了
说明那个子线程被回滚了
3.保证全局事务
我返回值记录了那个线程有问题,但是至于怎么全局回滚,还没找到方案。因为每个线程有自己的connection,无法控制10个线程在同一个connection。当然我知道如果通过控制connection来保证事务。
总结
其实我们用多线程解决问题其实就是拿空间换时间效率
利用线程池的好处有
- 减少资源的开销
- 方便统一管理
然而使用多线程也会遇到很多问题比如我现在想到的
- 如果保证全局事务
- 多数据源下事务问题