1、通过引入版本戳(stamp)机制解决ABA问题:
每次修改时递增版本号 执行CAS时同时检查值和版本号 即使值相同但版本不同,操作也会失败
2、具体代码实现
import java.util.concurrent.atomic.AtomicStampedReference; public class AtomicStampedReferenceDemo { // 账户余额初始值为100,版本号初始为0private static final AtomicStampedReference< Integer> accountBalance = new AtomicStampedReference<> ( 100 , 0 ) ; public static void main( String[ ] args) throws InterruptedException { System.out.println( "============== AtomicStampedReference解决ABA问题 ==============" ) ; System.out.println( "初始账户余额: " + accountBalance.getReference( ) +"元, 版本号: " + accountBalance.getStamp( )) ; System.out.println( ) ; // 创建ABA操作线程Thread abaThread = new Thread(( ) - > {int[] stampHolder = new int[1 ]; int currentValue; / / 第一次修改:100 → 50 System.out.println( stampHolder[0 ]) ; currentValue = accountBalance.get( stampHolder) ; int currentStamp = stampHolder[0 ]; System.out.println( "[ABA线程] 读取余额: " + currentValue + "元, 版本: " + currentStamp) ; boolean success = accountBalance.compareAndSet( currentValue, 50 , currentStamp, currentStamp + 1 ) ; System.out.println( "[ABA线程] 修改余额为50 元: " + ( success ? "成功" : "失败") + ", 新版本: " + accountBalance.getStamp( )) ; System.out.println( "当前余额: " + accountBalance.getReference( ) + "元" ) ; System.out.println( ) ; // 第二次修改:50 → 100 currentValue = accountBalance.get( stampHolder) ; currentStamp = stampHolder[ 0 ] ; System.out.println( "[ABA线程] 读取余额: " + currentValue + "元, 版本: " + currentStamp) ; success = accountBalance.compareAndSet( currentValue,100 ,currentStamp,currentStamp + 1 ) ; System.out.println( "[ABA线程] 恢复余额为100元: " + ( success ? "成功" : "失败" ) +", 新版本: " + accountBalance.getStamp( )) ; System.out.println( "当前余额: " + accountBalance.getReference( ) + "元" ) ; System.out.println( ) ; } ) ; // 创建转账线程Thread transferThread = new Thread(( ) - > {int[] stampHolder = new int[1 ]; int currentValue = accountBalance.get( stampHolder) ; int currentStamp = stampHolder[0 ]; System.out.println( "[转账线程] 读取余额: " + currentValue + "元, 版本: " + currentStamp) ; System.out.println( "[转账线程] 开始处理转账...") ; try {/ / 模拟处理耗时Thread.sleep( 2000 ) ; } catch ( InterruptedException e) {e.printStackTrace( ) ; }System.out.println( "[转账线程] 转账处理完成,尝试更新账户") ; / / 尝试更新余额(增加50 元)boolean success = accountBalance.compareAndSet( currentValue, currentValue + 50 , currentStamp, currentStamp + 1 ) ; System.out.println( "\n== == = 转账操作结果 == == = ") ; System.out.println( "操作结果: " + ( success ? "成功" : "失败")) ; System.out.println( "预期版本: " + currentStamp + ", 实际版本: " + accountBalance.getStamp( )) ; System.out.println( "预期余额: " + currentValue + "元, 当前余额: " + accountBalance.getReference( ) + "元" ) ; System.out.println( "=====================\n " ) ; } ) ; // 启动线程transferThread.start( ) ; Thread.sleep( 500 ) ; // 确保转账线程先读取初始值abaThread.start( ) ; // 等待线程完成abaThread.join( ) ; transferThread.join( ) ; System.out.println( "\n 最终账户余额: " + accountBalance.getReference( ) + "元, 版本号: " + accountBalance.getStamp( )) ; System.out.println( "============== 演示结束 ==============" ) ; }
}
== == == == == == == AtomicStampedReference解决ABA问题 == == == == == == ==
初始账户余额: 100 元, 版本号: 0 [ 转账线程] 读取余额: 100 元, 版本: 0
[ 转账线程] 开始处理转账.. .
0
[ ABA线程] 读取余额: 100 元, 版本: 0
[ ABA线程] 修改余额为50元: 成功, 新版本: 1
当前余额: 50 元[ ABA线程] 读取余额: 50 元, 版本: 1
[ ABA线程] 恢复余额为100元: 成功, 新版本: 2
当前余额: 100 元[ 转账线程] 转账处理完成,尝试更新账户== == = 转账操作结果 == == =
操作结果: 失败
预期版本: 0 , 实际版本: 2
预期余额: 100 元, 当前余额: 100 元
== == == == == == == == == == = 最终账户余额: 100 元, 版本号: 2
== == == == == == == 演示结束 == == == == == == == Process finished with exit code 0