不带时间戳的原子并发类:
原理:
- 查询线程安全:使用volatile修饰value,保证value的可见性,不同的线程总是可以获取到最新value值。
- 更新线程安全:使用cas的方式对value进行操作,保证更新操作是线程安全的。
- 这里的CAS:由jdk的Unsafe类实现,利用CPU自身的特性保证原子性,即CPU的指令集封装compare and swap两个操作为一个指令来保证原子性。
优点:
- 对其进行简单的运算是线程安全的。(简单的运算:出现ABA情况时,不影响value的计算)。
- CAS 可以看做是一种乐观锁,故比较适合读多写少的场景。
缺点:
- CAS操作存在ABA的问题,复杂运算的场景下不能绝对保证线程安全。
- CAS操作比较消耗CPU,故在写多的场景下会占用较多的cpu。
AtomicInteger
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;
}
方法:
- 查询:get方法。
- 更新:set、getAndIncrement、incrementAndGet、getAndAdd等方法。
AtomicReference
public class AtomicReference<V> implements java.io.Serializable {
private static final long serialVersionUID = -1848883965231344442L;
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicReference.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile V value;
}
带时间戳的原子引用类型:
AtomicStampedReference
原理:时间戳作为版本号来解决CAS的ABA问题。
优点:可以避免CAS的ABA问题。
源码:
public class AtomicStampedReference<V> {
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 volatile Pair<V> pair;
/**
* Creates a new {@code AtomicStampedReference} with the given
* initial values.
*
* @param initialRef the initial reference
* @param initialStamp the initial stamp
*/
public AtomicStampedReference(V initialRef, int initialStamp) {
pair = Pair.of(initialRef, initialStamp);
}
}