星空网 > 软件开发 > Java

【实战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高并发程序设计 1】Java中的指针:Unsafe类

【实战Java高并发程序设计 2】无锁的对象引用:AtomicReference

 

 

摘自:实战Java高并发程序设计

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




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

关键词:JAVA

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。

首场!TikTok Shop新加坡8.8大促将于下月举行:https://www.goluckyvip.com/news/7652.html
Shopee运营干货和开店法则:https://www.goluckyvip.com/news/7653.html
shopee运营思路,新手怎么做好shopee?:https://www.goluckyvip.com/news/7654.html
上海港报关指南之进口黑胡椒酱到国内如何办理清关申报手续:https://www.goluckyvip.com/news/7655.html
做电商为什么选做东南亚市场?:https://www.goluckyvip.com/news/7656.html
吃鲸MCN|TIKTOK3000万观看量!品牌挑战赛,奥利奥赢麻了! :https://www.goluckyvip.com/news/7657.html
TikTok 将推出先买后付服务 :https://www.kjdsnews.com/a/1836651.html
TikTok 将推出先买后付服务 :https://www.goluckyvip.com/news/188219.html
相关文章
我的浏览记录
最新相关资讯
海外公司注册 | 跨境电商服务平台 | 深圳旅行社 | 东南亚物流