用多线程模拟2PC事务提交

用多线程模拟2PC事务提交

前言

  • 之前遇到过一个面试题,要求的是在多线程执行同一批任务里,如果有有一个线程执行失败,那么需要把其他线程通知回滚任务。其实就是要么全部执行成功,要么全部执行失败。很明显这就相当于满足事务的原子性。
  • 废话不多说,下面直接上代码。

代码实现

/**
 * 2PC事务 -> 分布式事务
 *
 * @Author: ZRH
 * @Date: 2021/4/1 10:16
 */
public class Test1 {

    /**
     * 子线程最后提交事务还是回滚事务的标识
     */
    private static volatile Boolean SUBMIT = Boolean.TRUE;

    public static void main (String[] args) {
        // 模拟5个线程
        int num = 5;
        // 子线程执行结果集合
        List<Boolean> childList = new ArrayList<>();
        // 子线程执行通信
        CountDownLatch PASS_COUNT = new CountDownLatch(num);
        // 主线程通知子线程提交通信
        CountDownLatch NOTICE_COUNT = new CountDownLatch(1);
        // 初始化5个核心线程数的线程池
        ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(num + 1, num + 1, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10));
        for (int i = 0; i < num; i++) {
            int ii = i;
            EXECUTOR.execute(() -> {
                try {
                    System.out.println(Thread.currentThread().getName() + ":开始执行");

                    if (ii == 2) {
                        // 模拟子线程异常,执行事务回滚操作
//                        throw new Exception(Thread.currentThread().getName() + ":我异常了,哈哈");
                    }

                    childList.add(Boolean.TRUE);
                    Thread.sleep(10);
                    System.out.println(Thread.currentThread().getName() + ":可以准备提交数据,等待主线程响应");
                    // 通知等待中的主线程
                    PASS_COUNT.countDown();
                    // 等待主线程唤醒
                    NOTICE_COUNT.await();
                    if (SUBMIT) {
                        System.out.println(Thread.currentThread().getName() + ":提交数据成功");
                    } else {
                        System.out.println(Thread.currentThread().getName() + ":有线程异常,回滚提交");
                    }
                } catch (Exception e) {
                    System.out.println(Thread.currentThread().getName() + ":我异常了");
                    // 异常处理
                    childList.add(Boolean.FALSE);
                    PASS_COUNT.countDown();
                }
            });
        }
        try {
            // 等待子线程执行完后的唤醒
            PASS_COUNT.await();
            // 解析子线程执行结果:得到的全部子线程的运行结果并且结果全部为true
            SUBMIT = childList.size() == num && childList.stream().allMatch(Boolean::booleanValue);
            // 唤醒子线程执行最后的事务提交或事务回滚
            NOTICE_COUNT.countDown();
        } catch (Exception e) {
        }
    }
}
---------------------------------------------------
结果:
pool-1-thread-1:开始执行
pool-1-thread-2:开始执行
pool-1-thread-3:开始执行
pool-1-thread-4:开始执行
pool-1-thread-5:开始执行
pool-1-thread-2:可以准备提交数据,等待主线程响应
pool-1-thread-1:可以准备提交数据,等待主线程响应
pool-1-thread-5:可以准备提交数据,等待主线程响应
pool-1-thread-3:可以准备提交数据,等待主线程响应
pool-1-thread-4:可以准备提交数据,等待主线程响应
pool-1-thread-2:提交数据成功
pool-1-thread-1:提交数据成功
pool-1-thread-5:提交数据成功
pool-1-thread-3:提交数据成功
pool-1-thread-4:提交数据成功
  • 这里把代码中的模拟异常情况注释取消
if (ii == 2) {
    // 模拟子线程异常,执行事务回滚操作
    throw new Exception(Thread.currentThread().getName() + ":我异常了,哈哈");
}
------------------------------------------------------------
结果:
pool-1-thread-1:开始执行
pool-1-thread-2:开始执行
pool-1-thread-4:开始执行
pool-1-thread-3:开始执行
pool-1-thread-5:开始执行
pool-1-thread-3:我异常了
pool-1-thread-2:可以准备提交数据,等待主线程响应
pool-1-thread-1:可以准备提交数据,等待主线程响应
pool-1-thread-5:可以准备提交数据,等待主线程响应
pool-1-thread-4:可以准备提交数据,等待主线程响应
pool-1-thread-2:有线程异常,回滚提交
pool-1-thread-4:有线程异常,回滚提交
pool-1-thread-5:有线程异常,回滚提交
pool-1-thread-1:有线程异常,回滚提交

最后

  • 如果把上述代码中的多个线程看做多个微服务,那就对分布式事务的2PC两阶段提交的实现了。
  • 分布式事务里除了两阶段提交,还有3阶段提交(3PC) TCC XA Seata等等模式。如果有兴趣读者可以自行查看和实现。
    参考文章
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值