ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

AtomicStampedReference

2021-02-12 15:32:55  阅读:162  来源: 互联网

标签:private ar static compareAndSet new AtomicStampedReference AtomicReference


AtomicReference底层:
AtomicReference原子应用类,可以保证你在修改对象引用时的线程安全性,比较时可以按照偏移量进行
怎样使用AtomicReference:

AtomicReference ar = new AtomicReference();
ar.set(“hello”);
//CAS操作更新
ar.compareAndSet(“hello”, “hello1”);
AtomicReference的成员变量:

private static final long serialVersionUID = -1848883965231344442L;
//unsafe类,提供cas操作的功能
private static final Unsafe unsafe = Unsafe.getUnsafe();
//value变量的偏移地址,说的就是下面那个value,这个偏移地址在static块里初始化
private static final long valueOffset;
//实际传入需要原子操作的那个类实例
private volatile V value;

类装载的时候初始化偏移地址:

static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicReference.class.getDeclaredField(“value”));
} catch (Exception ex) { throw new Error(ex); }
}
compareAndSet方法:

//就是调用Unsafe的cas操作,传入对象,expect值,偏移地址,需要更新的值,即可,如果更新成功,返回true,如果失败,返回false
public final boolean compareAndSet(V expect, V update) {
return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}

对于String变量来说,必须是对象相同才视为相同,而不是字符串的内容相同就可以相同:

AtomicReference ar = new AtomicReference();
ar.set(“hello”);
System.out.println(ar.compareAndSet(new String(“hello”), “hello1”));//false
AtomicReference用法不做详细说明

这里的compareAndSet方法即cas操作本身是原子的,但是在某些场景下会出现异常场景

此处说一下ABA问题:

比如,我们只是简单得要做一个数值加法,即使在我取得期望值后,这个数字被不断的修改,只要它最终改回了我的期望值,我的加法计算就不会出错。也就是说,当你修改的对象没有过程的状态信息,所有的信息都只保存于对象的数值本身。

但是,在现实中,还可能存在另外一种场景。就是我们是否能修改对象的值,不仅取决于当前值,还和对象的过程变化有关,这时,AtomicReference就无能为力了。

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

详细实例

AtomicReference即可解决上篇博客的问题volatile不具有原子性的理解之解读i++疑惑
即AtomicReference可以保证结果是正确的.

private static volatile Integer num1 = 0;
private static AtomicReference ar=new AtomicReference(num1);

public void dfasd111() throws InterruptedException{
    for (int i = 0; i < 1000; i++) {
        new Thread(new Runnable(){
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++)
                    while(true){
                        Integer temp=ar.get();
                        if(ar.compareAndSet(temp, temp+1))break;
                    }
            }       
        }).start();
    }
    Thread.sleep(10000);
    System.out.println(ar.get()); //10000000
}

类似i++这样的"读-改-写"复合操作(在一个操作序列中, 后一个操作依赖前一次操作的结果), 在多线程并发处理的时候会出现问题, 因为可能一个线程修改了变量, 而另一个线程没有察觉到这样变化, 当使用原子变量之后, 则将一系列的复合操作合并为一个原子操作,从而避免这种问题, i++=>i.incrementAndGet()

标签:private,ar,static,compareAndSet,new,AtomicStampedReference,AtomicReference
来源: https://blog.csdn.net/u014162993/article/details/113794972

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有