java怎么控制多线程的事务??

就是几个线程的结果如果都成功了,就一起提交。如果有一个失败就全部回滚,并给出相关提示信息?网上没找到比较好的方案

阅读 16.2k
8 个回答

我先用中文描述一下思路(假设有3个线程):

  • 设置一个共享变量,记录成功个数

    • successCounter,对于单个线程来说,如果成功了就对这个变量++;否则,已失败,不必再等。
  • 等待

    • 等3个线程都执行完
  • 判断结果

    • 如果successCounter等于3,整体成功。否则,失败。

代码:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class App {
    public static void main(String[] args) {
        // 线程个数
        final int SIZE = 3;

        // 交给单个线程处理,成功了就加1
        final AtomicInteger successCounter = new AtomicInteger();

        final CountDownLatch latch = new CountDownLatch(SIZE);

        final ExecutorService pool = Executors.newCachedThreadPool();

        for (int i = 0; i < SIZE; i++) {
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    final boolean success = Math.random() > 0.1;
                    System.out.println(
                            Thread.currentThread().getName() +
                                    ", success = " + success);
                    if (success) {
                        // 单个成功
                        successCounter.getAndIncrement();
                        latch.countDown();
                    } else {
                        // 单个失败,亦整体失败
                        while (latch.getCount() > 0) {
                            latch.countDown();
                        }
                    }
                }
            });
        }

        pool.shutdown();

        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("成功的线程个数: " + successCounter);

        if (successCounter.get() == SIZE) {
            System.out.println("整体成功");
        } else {
            System.out.println("整体失败");
        }
    }
}

成功的case:

pool-1-thread-1, success = true
pool-1-thread-3, success = true
pool-1-thread-2, success = true
成功的线程个数: 3
整体成功

失败的case:

pool-1-thread-1, success = true
pool-1-thread-2, success = false
pool-1-thread-3, success = true
成功的线程个数: 2
整体失败

多个线程好解决,楼主想问的是不同进程怎么同步事务吧,比如多个dubbo服务。
确实有这个问题,首先有这样的技术,可以强一致,但效率牺牲太多,很少有公司这么干;大多数做法都是:服务A提交后,在某个东西(比如zookeeper)上记录节点;服务B提交后,记录另一个节点(这些节点都在表示本次事务的树枝节点下)……后续有个监听器类的东西,检查树枝节点下的节点数、状态等,如果有问题分别回滚或重试或人工干预等等……

并不是所有操作都能事务化啊,首先你得自己实现回滚操作再谈多线程事务吧。
可以用Future来保存多个异步操作,在循环中轮询所有Future,如果全部正常结束,则提交,如任何一个抛出异常,则调用所有异步操作对应的回滚操作。

数据库事务多线程比较麻烦,因为:

  1. 这会占用大量数据库连接;
  2. 不能用线程池,因为线程运行到最后必须等待协调,要么回滚要么提交。

在主方法new 一个InheritableThreadLocal 并设值为true,线程中如果出错则把值改为false。线程全部执行完之后,判断InheritableThreadLocal 的值,如果为false,你就手动抛出异常声明式回滚,或者自己写手动回滚。这样应该可以达到你的要求吧

CycleBarrier可能用得上。

通过一个线程安全的标志状态来同步吧

CountDownLatch
加上一个封装 transaction 和 state 的 queue 每个线程执行时,去队列中拿一个事务,执行完finally 扔回去并 count() , 并设置state = true;
最后在主线程判断所有transaction 的state 都是true ,然后就全部提交

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题