aba会导致问题_CAS导致的ABA问题以及解决方案

代码案例:

//线程操作资源,原子类ai的初始值为4

static AtomicInteger ai = new AtomicInteger(4);

public static void main(String[] args) {

new Thread(() -> {

//利用CAS将ai的值改成5

boolean b = ai.compareAndSet(4, 5);

System.out.println(Thread.currentThread().getName()+"是否成功将ai的值修改为5:"+b);

//休眠一秒

try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}

//利用CAS将ai的值改回4

b = ai.compareAndSet(5,4);

System.out.println(Thread.currentThread().getName()+"是否成功将ai的值修改为4:"+b);

},"A").start();

new Thread(() -> {

//模拟此线程执行较慢的情况

try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}

//利用CAS将ai的值从4改为10

boolean b = ai.compareAndSet(4, 10);

System.out.println(Thread.currentThread().getName()+"是否成功将ai的值修改为10:"+b);

},"B").start();

//等待其他线程完成,为什么是2,因为一个是main线程,一个是后台的GC线程

while (Thread.activeCount() > 2) {

Thread.yield();

}

System.out.println("ai最终的值为:"+ai.get());

}

执行结果:

2d75d88ea7a36640bde94d0382f0e803.png

可以看到,线程B最终是将ai的值修改成功了。

上面例子模拟的是A、B两个线程操作一个资源ai,A的执行速度比B的快,在B执行前,A就已经将ai的值改为5之后马上又把ai的值改回为4,但是B不感知,所以最后B就修改成功了。

比如有两个单身狗A、B,A在某个时间段内找到女朋友但是又分开了,但是没告诉B,此时B还是会在A是单身狗的情况下带A去打游戏。

ABA问题的解决方案?

数据库有个锁称为乐观锁,是一种基于数据版本实现数据同步的机制,每次修改一次数据,版本就会进行累加。

同样,Java也提供了相应的原子引用类AtomicStampedReference

449f61726d884e14247cfbc8ec969436.png

上图中的初始邮票就是版本号。

根据之前的代码改动的例子:

static AtomicStampedReference ai = new AtomicStampedReference<>(4,0);

public static void main(String[] args) {

new Thread(() -> {

//四个参数分别是预估内存值,更新值,预估版本号,初始版本号

//只有当预估内存值==实际内存值相等并且预估版本号==实际版本号,才会进行修改

boolean b = ai.compareAndSet(4, 5,0,1);

System.out.println(Thread.currentThread().getName()+"是否成功将ai的值修改为5:"+b);

try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}

b = ai.compareAndSet(5,4,1,2);

System.out.println(Thread.currentThread().getName()+"是否成功将ai的值修改为4:"+b);

},"A").start();

new Thread(() -> {

try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}

boolean b = ai.compareAndSet(4, 10,0,1);

System.out.println(Thread.currentThread().getName()+"是否成功将ai的值修改为10:"+b);

},"B").start();

while (Thread.activeCount() > 2) {

Thread.yield();

}

System.out.println("ai最终的值为:"+asri.getReference());

}

运行结果:

a0e5723522a3731362ce9f2f15624b60.png

可以看到,最终B并没有成功修改ai的值

51632b6331a97d7ff12a94963cdf2b14.png

=======================================================

我是Liusy,一个喜欢健身的程序员。

欢迎关注公众号【Liusy01】,一起交流Java技术及健身,获取更多干货。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值