脚本宝典收集整理的这篇文章主要介绍了

【实战Java高并发程序设计 3】带有时间戳的对象引用:AtomicStampedReference

脚本宝典小编觉得挺不错的,现在分享给大家,也给大家做个参考,希望能帮助你少写一行代码,多一份安全和惬意。

【实战Java高并发程序设计1】Java中的指针:Unsafe类
【实战Java高并发程序设计2】无锁的对象引用:AtomicReference
AtomicReference无法解决上述问题的根本是因为对象在修改过程中,丢失了状态信息。对象值本身与状态被画上了等号。因此,我们只要能够记录对象在修改过程中的状态值,就可以很好的解决对象被反复修改导致线程无法正确判断对象状态的问题。

AtomicStampedReference正是这么做的。它内部不仅维护了对象值,还维护了一个时间戳(我这里把它称为时间戳,实际上它可以使任何一个整数,它使用整数来表示状态值)。当AtomicStampedReference对应的数值被修改时,除了更新数据本身外,还必须要更新时间戳。当AtomicStampedReference设置对象值时,对象值以及时间戳都必须满足期望值,写入才会成功。因此,即使对象值被反复读写,写回原值,只要时间戳发生变化,就能防止不恰当的写入。

AtomicStampedReference的几个API在AtomicReference的基础上新增了有关时间戳的信息: //比较设置 参数依次为:期望值 写入新值 期望时间戳 新时间戳 public boolean compareAndSet(V expectedReference,V   newReference,int expectedStamp,int newStamp) //获得当前对象引用 public V getReference() //获得当前时间戳 public int getStamp() //设置当前对象引用和时间戳 public void set(V newReference, int newStamp) 

有了AtomicStampedReference这个法宝,我们就再也不用担心对象被写坏啦!现在,就让我们使用AtomicStampedReference在修正那个贵宾卡充值的问题的:

01 public class AtomicStampedReferenceDemo { 02 static AtomicStampedReference<Integer> money=new AtomicStampedReference<Integer>(19,0); 03    public staticvoid main(String[] args) { 04        //模拟多个线程同时更新后台数据库,为用户充值 05        for(int i = 0 ; i < 3 ; i++) { 06            final int timestamp=money.getStamp(); 07             newThread() {   08                public void run() {  09                    while(true){ 10                        while(true){ 11                             Integerm=money.getReference(); 12                             if(m<20){ 13                          if(money.compareAndSet(m,m+20,timestamp,timestamp+1)){ 14           System.out.println("余额小于20元,充值成功,余额:"+money.getReference()+"元"); 15                                     break; 16                                 } 17                             }else{ 18                                //System.out.println("余额大于20元,无需充值"); 19                                 break ; 20                             } 21                        } 22                    } 23                }  24            }.start(); 25         } 26         27        //用户消费线程,模拟消费行为 28        new Thread() {  29             publicvoid run() {  30                for(int i=0;i<100;i++){ 31                    while(true){ 32                        int timestamp=money.getStamp(); 33                        Integer m=money.getReference(); 34                        if(m>10){ 35                             System.out.println("大于10元"); 36                          if(money.compareAndSet(m, m-10,timestamp,timestamp+1)){ 37                       System.out.println("成功消费10元,余额:"+money.getReference()); 38                                 break; 39                             } 40                        }else{ 41                            System.out.println("没有足够的金额"); 42                             break; 43                        } 44                    } 45                    try {Thread.sleep(100);} catch (InterruptedException e) {} 46                 } 47             }  48        }.start();  49    } 50 } 

第2行,我们使用AtomicStampedReference代替原来的AtomicReference。第6行获得账户的时间戳。后续的赠予操作以这个时间戳为依据。如果赠予成功(13行),则修改时间戳。使得系统不可能发生二次赠予的情况。消费线程也是类似,每次操作,都使得时间戳加1(36行),使之不可能重复。

执行上述代码,可以得到以下输出:

余额小于20元,充值成功,余额:39元 大于10元 成功消费10元,余额:29 大于10元 成功消费10元,余额:19 大于10元 成功消费10元,余额:9 没有足够的金额 

可以看到,账户只被赠予了一次。
摘自《实战Java高并发程序设计》一书
bVsQzu

总结

以上是脚本宝典为你收集整理的

【实战Java高并发程序设计 3】带有时间戳的对象引用:AtomicStampedReference

全部内容,希望文章能够帮你解决

【实战Java高并发程序设计 3】带有时间戳的对象引用:AtomicStampedReference

所遇到的程序开发问题,欢迎加入QQ群277859234一起讨论学习。如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典网站推荐给程序员好友。 本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。

80%的人都看过