Java 原子类笔记

Java的原子类

JUC并发包中提供了一系列原子性操作类,这些类都是使用非阻塞算法 CAS 实现的,比使用锁性能有提升。具体实现大致相同。

原子更新基本类型

AtomicBoolean、AtomicInteger、AtomicLong

关键实现代码

public class AtomicLong extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 1927816293512124184L;
    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
    private static final long VALUE = U.objectFieldOffset(AtomicLong.class, "value");

    private volatile long value;
    ···
}

核心方法

public final boolean compareAndSet(long expectedValue, long newValue) {
    return U.compareAndSetLong(this, VALUE, expectedValue, newValue);
}

public final long getAndIncrement() {
    return U.getAndAddLong(this, VALUE, 1L);
}

public final long getAndDecrement() {
    return U.getAndAddLong(this, VALUE, -1L);
}
public final long incrementAndGet() {
    return U.getAndAddLong(this, VALUE, 1L) + 1L;
}


public final long decrementAndGet() {
    return U.getAndAddLong(this, VALUE, -1L) - 1L;
}

原子更新数组类型

AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray

调用构造方法时,会对参数数组拷贝一次。

原子更新引用类型

AtomicReference (存在ABA问题)

AtomicStampedReference(带有时间戳,处理ABA问题)

AtomicMarkableReference(通过添加带有对象是否被修改的boolean值,处理ABA问题)

例子:

public class HelloWorld {
    public static void main(String[] args) {
        User user1 = new User();
        user1.setAge(14);
        user1.setName("hello");
        AtomicReference<User> userAtomicReference = new AtomicReference<>(user1);
        User user2 = new User();
        user2.setName("world");
        user2.setAge(34);
        userAtomicReference.compareAndSet(user1,user2);
        System.out.println(userAtomicReference.get());
    }

}
class User{
    private String name;
    private Integer age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '/'' +
                ", age=" + age +
                '}';
    }
}

执行结果

Java 原子类笔记

原子更新类字段类型

AtomicIntegerFieldUpdater AtomicLongFieldUpdater AtomicReferenceFieldUpdater

优化后的原子操作类

LongAdder、 LongAccumulatorDoubleAdderDoubleAccumulator

AtomicLong类使用 CAS 提供非阻塞原子操作,比起锁已经优化了很多,但使用 AtomicLong 在多线程环境下会造成线程不断自旋尝试(源码使用无限循环),浪费 CPU 资源。为了解决此问题,LongAdder 类在内部维护的多个 Cell 元素来分担对单个变量进行争夺的开销。、

LongAdder 类继承自 Striped64 类,实现序列化。Striped64内部维护着三个变量

volatile long base;//初始值
    volatile int cellsBusy;//用来实现自旋锁,状态值 0 与 1 
    volatile Cell[] cells;//原子可见的Cell元素

底层通过 CAS 算法实现非阻塞原子操作

@sun.misc.Contented//避免Cell数组的伪分享出现,导致降低并发访问的性能
    static final class Cell{
        volatile long value;
        Cell(long x){
            value = x;
        }
        final boolean cas(long cmp,long val){
            return UNSAFE.compareAndSwapLong(this,valueOffest,cmp,val);//使用Unsafe类实现对Cell元素操作的原子性
        }
    }

在 LongAdder 类中维护的变量 cells 采用延迟初始化策略。cells 的元素通过 cas 函数的 CAS 操作达到原子性更新。

public long sum();//返回当前的值,内部所有 cell 和 base 的和,相加时未使用锁,返回值不精确,此时可能有 cell 被修改。多线程有问题。+
    public void reset();//重置,base 置0 ,若 cells 的元素有值则置0.
    public long sumThenReset(); //累加后置0,多线程有问题。
    public long longValue(); //等价与sum();

LongAccumulator(JDK8)

LongAdder 类是 LongAccumulator 的一个特例,LongAccumulator 更加强大。

构造方法:

//当 function 为null时,双目运算器为默认的加法运算器
public LongAccumulator(LongBinaryOperator function, long identify){
    this.function = function;
    base = this.identify = identify;//可以提供非0的初始值
}
//LongBinaryOperator双目运算器接口
public interface LongBinaryOperator{
    long applyAsLong(long left, long right);
}

原文 

https://segmentfault.com/a/1190000022642706

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » Java 原子类笔记

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址