2. 原子性 Atomic
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2. 原子性 Atomic相关的知识,希望对你有一定的参考价值。
参考技术A 对于涉及 共享变量 访问的操作,若该操作从其执行线程以外的任意线程来看是 不可分割的 ,那么该操作就是原子操作,称该操作具有原子性在Java中,对 基础数据类型(除double、long以外)的变量 和 引用变量 的 写操作 都是 原子性 的
Java中的double、long类型变量会占用64位(8字节)的存储空间,32位的Java虚拟机对这种变量的写操作可能会分解为两个步骤实施,比如先写低32位,后写高32位,故不能保证原子性
Java中对任何变量的读操作都是原子性的
Java语言规范特别地规定对于 volatile 关键字修饰的 long/double 类型变量的 写操作 是具有原子性的
可以使用synchronized关键字来保证操作的原子性
原子操作 + 原子操作 != 原子操作
Java源码Atomic部分源码解析
AtomicXXX
加了volatile保证了可见性。
本质上这一系列的都是采用的CAS的方式来更新原来的值的。
boolean实际上是用的int值来存储的。
AtomicXXXArray
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final int base = unsafe.arrayBaseOffset(long[].class);
private static final int shift;
private final long[] array;
基本的操作大体的意思应该是:
计算出来的地址就是:基础地址+偏移量=最终要定位的元素的地址。
然后Cas操作修改这个地址上的数据。
AtomicReferenceArray里面多了一个arrayFieldOffset,这个域用来支持反序列化的。其次,与AtomicIntegerArray不同,AtomicReferenceArray并没有scale域,取而代之的是shift域。阅读代码可知,其实目的都是计算rawIndex = base + index * scale,只不过AtomicReferenceArray里面把一部分运算转换为等价的位操作(当然前提是scala为2的幂)。(了解更多位操作技巧,可参考Hacker's Delight)。
public final void set(int i, long newValue)
unsafe.putLongVolatile(array, checkedByteOffset(i), newValue);
AtomicXXXFieldUpdater
- 原子域更新器,一般用于一些原子同步结构中。
/**
* Standard hotspot implementation using intrinsics
*/
private static class AtomicIntegerFieldUpdaterImpl<T> extends AtomicIntegerFieldUpdater<T>
private static final Unsafe unsafe = Unsafe.getUnsafe();
private final long offset;
private final Class<T> tclass;
private final Class cclass;
AtomicIntegerFieldUpdaterImpl构造过程中会目标class,和目标域的访问权限、还要要检查目标域是否为int型,是否由volatile修饰、当然还要获取目标域的偏移量,为后面的CAS操作做准备。
AtomicLongFieldUpdater,结构和AtomicIntegerFieldUpdater类似,有一点区别就是,它有两个实现,根据平台是否支持8字节的CAS操作,来选择不同的实现
AtomicReferenceFieldUpdater和AtomicIntegerFieldUpdater类似的结构,AtomicReferenceFieldUpdater一般用于某些原子数据结构中,支持某些节点的引用域的独立原子更新操作。
其实直接使用AtomicReference也可以完成类似的工作,那么为什么要使用AtomicReferenceFieldUpdater?主要原因还是为了提高性能。假设要设计一个支持原子操作的队列,队列的链接节点必然会进行频繁的操作,如果利用AtomicReference表示这些结点,那么AtomicReference本身的创建过程也需要一些开销,使用AtomicReferenceFieldUpdater可以省去这些开销。辅助创建一个实例,
AtomicStampedReference & AtomicMarkableReference
防止ABA问题,分别靠时间戳和Mark标记位来方式ABA问题的发生。
private static class Pair<T>
final T reference;
final int stamp;
private Pair(T reference, int stamp)
this.reference = reference;
this.stamp = stamp;
static <T> Pair<T> of(T reference, int stamp)
return new Pair<T>(reference, stamp);
private static class Pair<T>
final T reference;
final boolean mark;
private Pair(T reference, boolean mark)
this.reference = reference;
this.mark = mark;
static <T> Pair<T> of(T reference, boolean mark)
return new Pair<T>(reference, mark);
以上是关于2. 原子性 Atomic的主要内容,如果未能解决你的问题,请参考以下文章