所谓 Atomic,翻译过来就是原子。原子被认为是操作中最小的单位,一段代码如果是原子的,则表示这段代码在执行过程中,要么执行成功,要么执行失败。原子操作一般都是底层通过 CPU 的指令来实现。而 atomic 包下的这些类,则可以让我们在多线程环境下,通过一种无锁的原子操作来实现线程安全。
atomic 包下的类基本上都是借助 Unsafe 类,通过 CAS 操作来封装实现的。Unsafe 这个类不属于 Java 标准,或者说这个类是 Java 预留的一个后门类,JDK 中,有关提升性能的 concurrent 或者 NIO 等操作,大部分都是借助于这个类来封装操作的。
Java 是种编译型语言,不像 C 语言能支持操作内存,正常情况下都是由 JVM 进行内存的创建回收等操作,但这个类提供了一些直接操作内存相关的底层操作,使得我们也可以手动操作内存,但从类的名字就可以看出,这个类不是安全的,官方也是不建议我们使用的。
CAS原理
CAS 包含 3 个参数 CAS(V,E,N). V 表示要更新的变量, E 表示预期值, N表示新值.
仅当V值等于E值时, 才会将V的值设为N, 如果V值和E值不同, 则说明已经有其他线程做了更新, 则当前线程什么都不做. 最后, CAS返回当前V的真实值. CAS操作是抱着乐观的态度进行的, 它总是认为自己可以成功完成操作.
当多个线程同时使用CAS操作一个变量时, 只有一个会胜出, 并成功更新, 其余均会失败.失败的线程不会被挂起,仅是被告知失败, 并且允许再次尝试, 当然也允许失败的线程放弃操作.基于这样的原理, CAS操作即时没有锁,也可以发现其他线程对当前线程的干扰, 并进行恰当的处理.
在 JDK8 的 atomic 包下,大概有 16 个类,按照原子的更新方式,大概可以分为 4 类:原子更新普通类型,原子更新数组,原子更新引用,原子更新字段。
原子更新普通类型
atomic 包下提供了三种基本类型的原子更新,分别是 AtomicBoolean,AtomicInteger,AtomicLong,这几个原子类对应于基础类型的布尔,整形,长整形,至于 Java 中其他的基本类型,如 float 等,如果需要,可以参考这几个类的源码自行实现。
AtomicBoolean
主要接口
public final boolean get();
public final boolean compareAndSet(boolean expect, boolean update);
public boolean weakCompareAndSet(boolean expect, boolean update);
public final void set(boolean newValue);
public final void lazySet(boolean newValue);
public final boolean getAndSet(boolean newValue);
这里面的操作都很正常,主要都是用到了 CAS。这个类中的方法不多,基本上上面都介绍了,而内部的计算则是先将布尔转换为数字0/1,然后再进行后续计算。
AtomicLong
主要接口
public final long get();
public final void set(long newValue);
public final void lazySet(long newValue);
public final long getAndSet(long newValue);
public final boolean compareAndSet(long expect, long update);
public final boolean weakCompareAndSet(long expect, long update);
public final long getAndIncrement();
public final long getAndDecrement();
public final long getAndAdd(long delta);
public final long incrementAndGet();
public final long decrementAndGet();
public final long addAndGet(long delta);
public final long getAndUpdate(LongUnaryOperator updateFunction);
public final long updateAndGet(LongUnaryOperator updateFunction);
这个和下面要讲的 AtomicInteger 类似,下面具体说下。
AtomicInteger
主要接口