栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

AtomicStampedReference源码详解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

AtomicStampedReference源码详解

一、AtomicStampedReference原子类介绍 1、问题的提出

使用CAS方式会保证对原子类操作是线程安全的,它相较于传统的加锁来操作有一些优势,比如更加轻量级,速度更快;但是它同样也存在一些缺点,比如不能象同步代码块一样保证多个操作是线程安全的、当并发高时多个线程同时执行CAS不成功造成CPU利用率飙升,除了这些它还有一个比较致命的缺点:ABA问题,当两个线程都执行下面这段代码:

public final boolean getAndSet(boolean newValue) {
    boolean prev;
    do {
        prev = get();
    } while (!compareAndSet(prev, newValue));
    return prev;
}

当线程1执行到do时卡住,此时线程2将newValue值由true改为false,之后又改为true,这是线程1开始执行,发现get()到的value为true,就进行CAS,但是他不知道这个true已经被修改过了,有时我们不允许这样,就产生了AtomicStampedReference这个原子类,它的本质就是AtomicReference。

2、内部结构介绍
private static class Pair {
    final T reference;
    final int stamp;
    private Pair(T reference, int stamp) {
        this.reference = reference;
        this.stamp = stamp;
    }
    static  Pair of(T reference, int stamp) {
        return new Pair(reference, stamp);
    }
}

私有静态内部类,两个属性,泛型对象和版本号(类似于乐观锁)。

private volatile Pair pair;
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
private static final long pairOffset =
    objectFieldOffset(UNSAFE, "pair", AtomicStampedReference.class);

属性

public AtomicStampedReference(V initialRef, int initialStamp) {
    pair = Pair.of(initialRef, initialStamp);
}

构造方法。

public V getReference() {
    return pair.reference;
}

public int getStamp() {
    return pair.stamp;
}
public V get(int[] stampHolder) {
    Pair pair = this.pair;
    stampHolder[0] = pair.stamp;
    return pair.reference;
}

将stamp传给整形数组,并返回reference。

public boolean weakCompareAndSet(V   expectedReference,
                                 V   newReference,
                                 int expectedStamp,
                                 int newStamp) {
    return compareAndSet(expectedReference, newReference,
                         expectedStamp, newStamp);
}

public boolean compareAndSet(V   expectedReference,
                             V   newReference,
                             int expectedStamp,
                             int newStamp) {
    Pair current = pair;
    return
        expectedReference == current.reference &&
        expectedStamp == current.stamp &&
        ((newReference == current.reference &&
          newStamp == current.stamp) ||
         casPair(current, Pair.of(newReference, newStamp)));
}

private boolean casPair(Pair cmp, Pair val) {
    return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
}

解决ABA问题的关键就是compareAndSet,这里compareAndSet方法首先判断expectedReference和expectedStamp是否与current相等,这是因为它CAS操作的时候要使用地址,而传进来的参数是值,我们就需要根据值是否相等来转换为current地址,之后进行CAS操作。

public void set(V newReference, int newStamp) {
    Pair current = pair;
    if (newReference != current.reference || newStamp != current.stamp)
        this.pair = Pair.of(newReference, newStamp);
}

无条件赋值

public boolean attemptStamp(V expectedReference, int newStamp) {
    Pair current = pair;
    return
        expectedReference == current.reference &&
        (newStamp == current.stamp ||
         casPair(current, Pair.of(expectedReference, newStamp)));
}

设置newStamp设置新版本号。

static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
                              String field, Class klazz) {
    try {
        return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
    } catch (NoSuchFieldException e) {
        // Convert Exception to corresponding Error
        NoSuchFieldError error = new NoSuchFieldError(field);
        error.initCause(e);
        throw error;
    }
}

返回对象属性距离对象地址的偏移量。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/603500.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号