由并发扣款如何保证数据一致性引起的ABA问题的思考

在分布式环境下,并发扣款可能导致数据不一致。文章讨论了如何解决这一问题,包括使用分布式锁、悲观锁和乐观锁(CAS)。在乐观锁中,介绍了ABA问题及其对并发操作的影响,并提出通过增加版本号字段来防止此类问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

起因是看了公众号架构师之路 推送的一篇文章:并发扣款,如何保证数据的一致性?

1. 场景:

用户购买商品,对余额进行查询和修改,如果余额大于商品价格,购买商品并修改余额,单机或者无并发情况下,这个步骤没有任何问题;但分布式环境下,不同站点实例的多个业务操作同一个用户进行并发扣款(虽然我也不知道怎么会有这种场景,用户怎么可能在同一时间买多个商品),这样进程内互斥锁肯定无法起作用,最终导致数据不一致。以下是异常流程:

  1. 业务1和业务2并发查询余额,都是100元;
  2. 然后并发进行业务计算,业务1算出余额是28元,业务2算出余额是38元,
  3. 那么无论谁写回余额,都会覆盖另一个业务的操作结果。

这不就是第二类丢失更新吗?网上有一个关系表格图:
在这里插入图片描述
如图,mysql默认隔离级别为可重复读,能解决第二类丢失更新,那上面怎么这个是怎么回事?
这里有一个误区,所说能解决是基于update语句的加减不会丢失,比如 update t_account set money=money-1 where id=1, 如下:事务1在T3时刻查询余额为100,事务2在T5时刻执行update减1操作修改为99,T6时刻提交,由于可重复读&

<think>好的,我现在需要回答用户关于JVM原子性、一致性和原子类的问题。首先,我需要确认自己对这几个概念的理解是否正确,然后再组织语言,用清晰的中文解释给用户。 首先,原子性。在并发编程中,原子性指的是一个操作不可中断,要么全部完成,要么都不做。比如i++这个操作,实际上包含取、增加、写入三个步骤,如果没有同步措施,多线程下会导致问题。JVM如何保证原子性呢?常见的有synchronized关键字和Lock接口,它们通过锁机制确保同一时刻只有一个线程执行代码块。另外,原子类如AtomicInteger使用CAS(Compare and Swap)操作,底层由CPU指令支持,保证原子性。 接下来是一致性。这里可能指的是内存一致性或者程序执行结果的一致性。JVM的内存模型(JMM)定义了线程如何与主内存交互,通过happens-before规则确保可见性。比如volatile变量的写操作happens-before后续的操作,synchronized的解锁happens-before加锁。一致性需要原子性、可见性和有序性的共同保障,避免出现脏、幻问题。 然后是原子类,属于java.util.concurrent.atomic包下的类,比如AtomicInteger、AtomicLong等。它们利用CAS算法实现非阻塞的线程安全操作。CAS包含三个操作数:内存位置、预期原值和新值。如果内存位置的值等于预期原值,则更新为新值,否则不操作。这种机制相比锁机制,减少了线程阻塞,提高了并发性能。不过CAS可能存在ABA问题,可以通过AtomicStampedReference解决。 需要区分原子性和一致性之间的关系。原子性关注单个操作不可分割,而一致性关注多个操作的整体正确状态。比如转账操作,扣款和入账必须都成功或都失败,这需要原子性;而整个系统状态在操作前后保持一致,这是一致性。 在回答结构上,应该先分别解释原子性、一致性、原子类,再说明它们的联系和区别。可能需要举例说明,比如i++的问题,原子类如何解决,以及CAS的工作原理。同时,要指出原子类的优缺点,比如ABA问题和解决方法。 需要检查是否有遗漏的概念,比如JMM中的可见性和有序性是否应该提到。因为一致性涉及到这些方面,所以简要说明是有必要的。另外,用户可能对JVM底层如何实现这些机制感兴趣,比如内存屏障、CPU指令等,但需要保持回答不过于深入,保持易懂。 最后,确保使用正确的中文术语,结构清晰,分点说明,使用适当的例子帮助理解。避免使用Markdown格式,按照用户的要求用纯文本,数学公式用$...$和$$...$$。不过用户的问题中没有涉及数学公式,可能不需要使用,但要注意如果回答中有变量或代码,比如AtomicInteger,用代码块或者斜体表示?</think>### JVM原子性、一致性与原子类解析 #### 一、原子性(Atomicity) **定义**:原子性指一个操作不可被中断,要么全部执行成功,要么完全不执行。 **典型问题**:例如 `i++` 操作实际包含三步: 1. 取当前值 2. 值加1 3. 写回新值 若多线程同时执行,可能导致结果错误。 **JVM保障方式**: 1. **锁机制**(如 `synchronized`、`ReentrantLock`):确保同一时刻仅一个线程访问资源。 ```java synchronized (lock) { i++; } ``` 2. **原子类**(如 `AtomicInteger`):基于CAS(Compare and Swap)实现无锁线程安全。 ```java AtomicInteger atomicInt = new AtomicInteger(0); atomicInt.incrementAndGet(); // 原子性自增 ``` --- #### 二、一致性(Consistency) **定义**:一致性指多线程操作后,系统状态符合预期逻辑,遵循业务规则(如转账总额不变)。 **依赖条件**: 1. **原子性**:操作完整执行。 2. **可见性**:线程修改后其他线程立即可见。 3. **有序性**:代码执行顺序符合预期。 **JVM保障方式**: - **Happens-Before规则**: - 单线程规则:同一线程内操作按顺序生效。 - `volatile`变量:写操作先于操作。 - 锁释放:解锁先于后续加锁。 --- #### 三、原子类(Atomic Classes) **原理**:基于CAS(Compare and Swap)实现非阻塞同步。 **CAS流程**: 1. 取内存当前值$V$。 2. 计算新值$N$。 3. 若内存值仍为$V$,则更新为$N$;否则重试或放弃。 **常用类**: - `AtomicInteger`、`AtomicLong`:数值原子操作。 - `AtomicReference`:对象引用原子更新。 - `AtomicStampedReference`:解决CASABA问题(通过版本号)。 **优势**: - 无锁设计,减少线程阻塞,提升并发性能。 **缺点**: - **ABA问题**:值从$A→B→A$,CAS误认为未变化。 - **解决方案**:使用`AtomicStampedReference`记录版本号。 --- #### 四、总结与联系 | 特性 | 关键点 | 实现方式 | |------------|-----------------------------------|--------------------------| | **原子性** | 操作不可分割 | 锁、CAS | | **一致性** | 系统状态正确性 | 原子性+可见性+有序性 | | **原子类** | 无锁线程安全 | CAS底层支持 | **示例场景**: - 无锁计数器:`AtomicInteger` 替代 `synchronized`,性能更高。 - 状态标记:`AtomicBoolean` 控制线程开关。 通过合理使用原子类和锁机制,可在JVM中高效实现线程安全与数据一致性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值