1.背景
最近在修改Seata线程并发的一些问题,把其中一些经验总结给大家。先简单描述一下这个问题,在Seata这个分布式事务框架中有个全局事务的概念,在大多数情况下,全局事务的流程基本是顺序推进不会出现并发问题,但是当一些极端的情况下,会出现多线程访问导致我们全局事务处理不正确。 如下面代码所示: 在我们全局事务commit阶段,有一个如下代码:
if (status == GlobalStatus.Begin) {
globalSession.changeStatus(GlobalStatus.Committing);
}
代码有些省略,就是先判断status状态是否Begin状态,然后改变状态为Committing。
在我们全局事务rollback阶段,有一个如下代码:
if (status == GlobalStatus.Begin) {
globalSession.changeStatus(GlobalStatus.Rollbacking);
}
同样的也省略了部分代码,这里先判断status状态是否为begin,然后改变为Rollbacking。这里再Seata的代码中并没有做一些线程同步的手段,如果这两个逻辑同时执行(一般情况下不会,但是极端情况下可能会出现),会让我们的结果出现不可预料的错误。而我们所要做的就是解决这种极端情况下来的并发出现的问题。
2.悲观锁
对于这种并发出现问题我相信大家第一时间想到的肯定是加锁,在Java中我们我们一般采用下面两个手段进行加锁:
Synchronized
ReentrantLock
我们可以利用Synchronized 或者 ReentrantLock进行加锁,可以将代码修改成下面的逻辑:
synchronized:
synchronized(globalSession){
if (status == GlobalStatus.Begin) {
globalSession.changeStatus(GlobalStatus.Rollbacking);
}
}
ReentrantLock进行加锁:
reentrantLock.lock();
try {
if (status == GlobalStatus.Begin