JUC并发包中提供了一系列原子性操作类,这些类都是使用非阻塞算法 CAS 实现的,比使用锁性能有提升。具体实现大致相同。
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 + '}'; } }
执行结果
AtomicIntegerFieldUpdater AtomicLongFieldUpdater AtomicReferenceFieldUpdater
LongAdder、 LongAccumulator 、 DoubleAdder 、 DoubleAccumulator
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); }