• AtomicReference 原子引用


    AtomicReference和AtomicInteger非常类似,不同之处就在于AtomicInteger是对整数的封装,底层采用的是compareAndSwapInt实现CAS,比较的是数值是否相等,而AtomicReference则对应普通的对象引用,底层使用的是compareAndSwapObject实现CAS,比较的是两个对象的地址是否相等。也就是它可以保证你在修改对象引用时的线程安全性。

    顺便说一下:引用类型的赋值是原子的。虽然虚拟机规范中说64位操作可以不是原子性的,可以分为两个32位的原子操作,但是目前商用的虚拟机几乎都实现了64位原子操作。

    .AtomicReference.set(V newValue) 注意此方法是原子的。这个方法里面就一句代码,引用赋值本身它就是原子性的不会被cpu打断的。

    源码如下:

    public class AtomicReference<V> implements java.io.Serializable {
    private static final long serialVersionUID = -1848883965231344442L;

    // 获取Unsafe对象,Unsafe的作用是提供CAS操作
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;

    static {
    try {
    valueOffset = unsafe.objectFieldOffset
    (AtomicReference.class.getDeclaredField("value"));
    } catch (Exception ex) { throw new Error(ex); }
    }

    // volatile类型
    private volatile V value;

    public AtomicReference(V initialValue) {
    value = initialValue;
    }

    public AtomicReference() {
    }

    public final V get() {
    return value;
    }

    public final void set(V newValue) {
    value = newValue;
    }

    public final void lazySet(V newValue) {
    unsafe.putOrderedObject(this, valueOffset, newValue);
    }

    public final boolean compareAndSet(V expect, V update) {
    return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
    }

    public final boolean weakCompareAndSet(V expect, V update) {
    return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
    }

    public final V getAndSet(V newValue) {
    while (true) {
    V x = get();
    if (compareAndSet(x, newValue))
    return x;
    }
    }

    public String toString() {
    return String.valueOf(get());
    }
    }
     

    public class Main{
    public static void main(String[] args) {

    // 创建两个Person对象,它们的id分别是101和102。
    Person2 p1 = new Person2(101);
    Person2 p2 = new Person2(102);
    // 新建AtomicReference对象,初始化它的值为p1对象
    AtomicReference ar = new AtomicReference(p1);
    //更改p1的id.
    p1.setId(106);
    // 通过CAS设置ar。如果ar的值为p1的话,则将其设置为p2。
    ar.compareAndSet(p1, p2);

    Person2 p3 = (Person2)ar.get();
    System.out.println("p3 is "+p3);
    System.out.println("p3.equals(p1)="+p3.equals(p1));
    }

    }
    class Person2 {
    volatile long id;
    public Person2(long id) {
    this.id = id;
    }
    public String toString() {
    return "id:"+id;
    }
    public void setId(long id){
    this.id=id;
    }
    }
    运行结果如下:

    p3 is id:102
    p3.equals(p1)=false

    可以看出,修改了p1的id对compareAndSet()并没有影响,因为修改id仅仅改变了p1的成员变量,而AtomicReference底层使用的是compareAndSwapObject实现CAS,比较的是两个对象的地址是否相等。也就是它可以保证你在修改对象引用时的线程安全性。上面代码成功的将原子类中的引用从p1变成p2,而且是线程安全的。

  • 相关阅读:
    2003系统IIS上传文件不能超过200K的解决方案
    ASP从编辑框中获取图片路径
    ASP 编码转换大全 UTF8、GB2312、二进制、十进制代码、十六进制
    解决IE6、IE7、IE8样式不兼容问题
    py2exe setup.py
    Python to 2bit
    python访问ACCESS
    Pamie Web自动化
    Perl 笔记
    常用工具全盗版 汗颜了
  • 原文地址:https://www.cnblogs.com/zyy1688/p/10654687.html
Copyright © 2020-2023  润新知