必威体育Betway必威体育官网
当前位置:首页 > IT技术

经典的ABA问题与解决方法

时间:2019-08-21 03:44:26来源:IT技术作者:seo实验室小编阅读:58次「手机版」
 

aba

1:AbA问题的产生

要了解什么是ABA问题,首先我们来通俗的看一下这个例子,一家火锅店为了生意推出了一个特别活动,凡是在五一期间的老用户凡是卡里余额小于20的,赠送10元,但是这种活动没人只可享受一次。然后火锅店的后台程序员小王开始工作了,很简单就用cas技术,先去用户卡里的余额,然后包装成Atomicinteger,写一个判断,开启10个线程,然后判断小于20的,一律加20,然后就很开心的交差了。可是过了一段时间,发现账面亏损的厉害,老板起先的预支是2000块,因为店里的会员总共也就100多个,就算每人都符合条件,最多也就2000啊,怎么预支了这么多。小王一下就懵逼了,赶紧debug,tail -f一下日志,这不看不知道,一看吓一跳,有个客户被充值了10次!

阐述:

假设有个线程A去判断账户里的钱此时是15,满足条件,直接+20,这时候卡里余额是35.但是此时不巧,正好在连锁店里,这个客人正在消费,又消费了20,此时卡里余额又为15,线程B去执行扫描账户的时候,发现它又小于20,又用过cas给它加了20,这样的话就相当于加了两次,这样循环往复肯定把老板的钱就坑没了!

本质:

ABA问题的根本在于cas在修改变量的时候,无法记录变量的状态,比如修改的次数,否修改过这个变量。这样就很容易在一个线程将A修改成B时,另一个线程又会把B修改成A,造成casd多次执行的问题。

2:AtomicStampReference 

AtomicStampReference在cas的基础上增加了一个标记stamp,使用这个标记可以用来觉察数据是否发生变化,给数据带上了一种实效性的检验。它有以下几个参数:

//参数代表的含义分别是 期望值,写入的新值,期望标记,新标记值

public boolean compareAndSet(V expected,V newReference,int expectedStamp,int newStamp);

public V getRerference();

public int getStamp();

public void set(V newReference,int newStamp);

3:AtomicStampReference的使用实例

我们定义了一个money值为19,然后使用了stamp这个标记,这样每次当cas执行成功的时候都会给原来的标记值+1。而后来的线程来执行的时候就因为stamp不符合条件而使cas无法成功,这就保证了每次

只会被执行一次。

public class AtomicStampReferenceDemo {

    static AtomicStampedReference<Integer>  money =new AtomicStampedReference<Integer>(19,0);

    public static void main(String[] args) {

        for (int i = 0; i < 3; i++) {

            int stamp = money.getStamp();

            System.out.println("stamp的值是"+stamp);

            new Thread(){         //充值线程

                @Override
                public void run() {

                        while (true){

                            Integer account = money.getReference();

                            if (account<20){

                                if (money.compareAndSet(account,account+20,stamp,stamp+1)){

                                    System.out.println("余额小于20元,充值成功,目前余额:"+money.getReference()+"元");
                                    break;
                                }
                            }else {

                                System.out.println("余额大于20元,无需充值");
                            }
                        }
                    }
                }.start();
            }


            new Thread(){

                @Override
                public void run() {    //消费线程

                    for (int j = 0; j < 100; j++) {

                        while (true){

                            int timeStamp = money.getStamp();//1

                            int currentMoney =money.getReference();//39

                            if (currentMoney>10){
                                System.out.println("当前账户余额大于10元");
                                if (money.compareAndSet(currentMoney,currentMoney-10,timeStamp,timeStamp+1)){

                                    System.out.println("消费者成功消费10元,余额"+money.getReference());

                                    break;
                                }
                            }else {
                                System.out.println("没有足够的金额");

                                break;
                            }
                            try {
                                Thread.sleep(1000);
                            }catch (Exception ex){
                                ex.printstacktrace();
                                break;
                            }

                        }

                    }
                }
            }.start();

        }
    }

这样实现了线程去充值和消费,通过stamp这个标记属性来记录cas每次设置值的操作,而下一次再cas操作时,由于期望的stamp与现有的stamp不一样,因此就会设值失败,从而杜绝了ABA问题的复现。

摘自:https://www.cnblogs.com/wyq178/p/8965615.html 

相关阅读

无法定位程序输入点nextafterf/fesetround于动态链接

报错:无法定位程序输入点nextafterf于动态链接库MSVCR120_CLR0400.dll上,如何解决?初步判定需要安装.NET Framework4.0框架和VC ++ 2

adb.exe 已停止工作 频繁弹窗问题

问题提示(我当时候没有截图暂用网上的,内容有点不同,我的弹窗只有关闭程序这一个选项): 用adb命令总是报错 怀疑端口被占用,于是查询

智能公交应用都怎么做?车到哪体验问题报告

一、背景当工业时代缓慢地放下了笨重的锄头,互联时代已经坐着无人汽车向马路飞去。从外卖行业的饿了不叫妈,到双十一全国妇女的肺腑

No input file specified解决方法

原因在于使用的PHP5.6是fast_cgi模式,而在某些情况下,不能正确识别path_info所造成的错误默认的.htaccess里面的规则: IfModule mod

遇到的奇奇怪怪的问题

1 无法生成静态文件 问题描述:本地环境可以生成静态文件,而测试环境只能生成90%左右,可以确保代码层面没有问题 产生原因:测试服务

分享到:

栏目导航

推荐阅读

热门阅读