1.CountDownLatch
CountDownLatch是一个同步工具类,用来协调多个线程之间的同步,或者说起到线程之间的通信。CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。使用一个计数器进行实现。计数器初始值为线程的数量。当每一个线程完成自己任务后,计数器的值就会减一。当计数器的值为0时,表示所有的线程都已经完成一些任务,然后在CountDownLatch上等待的线程就可以恢复执行接下来的任务。
2.多线程事务回滚
在使用多线程同时执行多个事务时,有时几个事务之间有着关联关系,即要么都成功要么都失败,在这种情况下,只是单纯的基于注解@Transactional是无法实现,因此当需要某个子线程事务失败了,其它相关的子线程也都需要回滚事务,下面用简单例子说明使用方式
直接上代码:实例代码用打印代替了实际的事务处理,注释写的很详细
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
public class Test {
public static void main(String[] args) throws InterruptedException {
// 主线程-数量就是相关联的子线程数
CountDownLatch mainThreadLatch = new CountDownLatch(10);
// 子线程-数量固定为 1
// 这样所有子线程都会由同一个rollBackLatch等待
// 然后在主线程里面只需rollBackLatch.countDown就可以同时放行所有子线程
CountDownLatch rollBackLatch = new CountDownLatch(1);
// 线程执行标志
// 用于标志是否有线程事务失败了
// 默认没有全部成功,在子线程执行中遇到有失败的才将这个值设为 true
AtomicBoolean rollbackFlag = new AtomicBoolean(false);
// 创建 10个线程
for (int i = 0; i < 10; i++) {
int finalI = i;
new Thread(() -> {
try {
// 用随机睡眠时间模拟业务处理
Thread.sleep((long) (Math.random() * 3000 + 1000));
System.err.println("线程:" + finalI + "执行完成,等其它线程结束待中...");
mainThreadLatch.countDown();
// 当前子线程等待其它线程结束
rollBackLatch.await();
if(rollbackFlag.get()) {
// 有失败的事务则当前事务回滚
System.err.println("有线程执行异常,将回滚事务,线程:" + finalI);
} else {
// 没有失败的事务则结束
System.err.println("线程:" + finalI + "执行完成!");
}
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
// 主线程等待子线程结束
mainThreadLatch.await();
//所有等待的子线程全部放开
rollBackLatch.countDown();
if(rollbackFlag.get()){
System.out.println("fail");
}else{
System.out.println("success");
}
}
}
没有失败事务的执行结果:
有失败的事务执行结果:
代码修改部分如下:(本次模拟是在第 8 个线程执行时将rollbackFlag设为 true)
// 用随机睡眠时间模拟业务处理
Thread.sleep((long) (Math.random() * 3000 + 1000));
if(finalI == 7) {
rollbackFlag.set(true);
} else {
System.err.println("线程:" + finalI + "执行完成,等其它线程结束待中...");
}
结果: