您当前的位置: 首页 > 

恐龙弟旺仔

暂无认证

  • 3浏览

    0关注

    282博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

AtomicReference与AtomicReferenceFieldUpdater的使用

恐龙弟旺仔 发布时间:2021-11-06 22:02:47 ,浏览量:3

前言:

关于JDK提供的原子类,我们之前经常使用的就是基础类型的相关原子类,如AtomicInteger、AtomicLong、AtomicBoolean等。那么有没有关于对象类型的原子类呢,确实是有的,就是AtomicReference类。

笔者在学习Netty时,发现了一个更好玩的类AtomicReferenceFieldUpdater,可以对对象的属性实现原子修改。我们一起来学习下。

1.AtomicReference 1.1 基础使用

有关于其使用还是比较简单的,示例如下:

AtomicReference reference = new AtomicReference();
// 设置初始值
reference.set("test1");
// 原子性的将值从test1设置为test2
boolean isOk = reference.compareAndSet("test1", "test2");

基于以上示例,我们也可以进行对象的原子修改

AtomicReference reference = new AtomicReference();
// 设置初始值
Date date1 = new Date();
reference.set(date1);
// 需要的修改后的值
Date date2 = new Date();

boolean isOk = reference.compareAndSet(date1, date2);
1.2 源码释义
public class AtomicReference implements java.io.Serializable {
 
    // Unsafe对象
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    // 用于获取某个字段相对Java对象的起始地址的偏移量
    private static final long valueOffset;

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

    // 所包装的value值
    private volatile V value;
    // 初始化value值
    public AtomicReference(V initialValue) {
        value = initialValue;
    }
    
    // 本质上还是通过调用Unsafe来实现的
    public final boolean compareAndSet(V expect, V update) {
        return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
    }
    ...
}

很明显可以看到,其原子功能是通过Unsafe来实现的。更多关于Unsafe的知识点,读者可以自行查找。

2.AtomicReferenceFieldUpdater

既然已经有了AtomicReference实现对象的原子变更,那么AtomicReferenceFieldUpdater的具体作用是什么呢?

如果我们期望对对象的某个属性进行原子变更时,则可以使用其来实现。

我们先来看一下示例:

// 创建对Person对象的name属性的原子变更类
AtomicReferenceFieldUpdater fieldUpdater = AtomicReferenceFieldUpdater.newUpdater(Person.class, String.class, "name");

Person person = new Person();
fieldUpdater.set(person, "jack");

// 原子性的将name属性将原来的jack转变为lucy
boolean b = fieldUpdater.compareAndSet(person, "jack", "lucy");
String s = fieldUpdater.get(person);
Assert.assertEquals("lucy", s);

public class Person {
    volatile String name;
    volatile int age;
}

使用过程并不复杂,就是创建AtomicReferenceFieldUpdater时可能有点难度,newUpdater()方法的三个属性分别是:对象类型、修改的属性类型、修改的属性名称;

可以再来看下netty中关于其使用

private static final class DefaultResourceLeak extends WeakReference implements ResourceLeakTracker, ResourceLeak {
    // 实现对DefaultResourceLeak.head属性的原子修改
    private static final AtomicReferenceFieldUpdater> droppedRecordsUpdater =
        (AtomicIntegerFieldUpdater)
        AtomicIntegerFieldUpdater.newUpdater(DefaultResourceLeak.class, "droppedRecords");

    @SuppressWarnings("unused")
    private volatile TraceRecord head;
    
}

使用还是比较简单的,那么使用的时候有没有哪些需要注意的点呢?

操作的字段不能是static类型;
操作的字段不能是final类型的;
字段必须是volatile修饰的,也就是数据本身是读一致的;
属性必须对当前的Updater所在的区域是可见的,如果不是当前类内部进行原子更新器操作不能使用private,protected子类操作父类时修饰符必须是protect权限及以上,
如果在同一个package下则必须是default权限及以上,也就是说无论何时都应该保证操作类与被操作类间的可见性;
总结:

最后一个问题留给读者,既然我们想实现对对象的属性原子性修改,那直接在setxxx属性方法中,对其进行加锁处理,不也是一样的吗,为什么要这么麻烦呢?

关注
打赏
1655041699
查看更多评论
立即登录/注册

微信扫码登录

0.0759s