本博客系列是学习并发编程过程中的记录总结。由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅。
在java.util.concurrent.atomic
中,普通的原子类型有以下四种:
- AtomicBoolean:提供对基本数据类型boolean的原子性更新操作。
- AtomicInteger:提供对基本数据类型int的原子性更新操作。
- AtomicLong:提供对基本数据类型long的原子性更新操作。
- AtomicReference
:这是一个泛型类,提供对引用类型的原子性更新操作。
数组相关的操作类有:
- AtomicLongArray:提供对int[]数组元素的原子性更新操作。
- AtomicIntegerArray:提供对long[]数组元素的原子性更新操作。
- AtomicReferenceArray:提供对引用类型[]数组元素的原子性更新操作。
由于上面的原子操作类的实现原理差不多,我们这边就选择AtomicInteger
来分析。
代码分析
构造函数
public class AtomicInteger extends Number implements java.io.Serializable { private static final long serialVersionUID = 6214790243416807050L; //Unsafe类提供底层的CAS机制 private static final Unsafe unsafe = Unsafe.getUnsafe(); //valueOffset是value值的内存地址值偏移值,这个值的作用是获取value在主内存中的值 private static final long valueOffset; //类加载的时候获取valueOffset的值 static { try { valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } //AtomicInteger具体的值存放在这个变量中, //这个变量使用volatile修饰,具有可见性 private volatile int value; public AtomicInteger(int initialValue) { value = initialValue; } //默认为0 public AtomicInteger() { } }
get和set方法分析
//value使用volatile修饰,每次能拿到最新值 public final int get() { return value; } //value使用volatile修饰,赋值操作具有原子性,是线程安全的 public final void set(int newValue) { value = newValue; } //这个方法可能比较令人疑惑,我查了下unsafe的putOrderedInt方法,如下 /** Sets the value of the integer field at the specified offset in the * supplied object to the given value. This is an ordered or lazy * version of <code>putIntVolatile(Object,long,int)</code>, which * doesn't guarantee the immediate visibility of the change to other * threads. It is only really useful where the integer field is * <code>volatile</code>, and is thus expected to change unexpectedly. */ 上面的意思大致是:putOrderedInt方法不保证可见性,只有在变量是volatile修饰时才有用, 我们这边的value变量就是用volatile修饰的,所以我认为AtomicInteger的`set`方法和`lazySet`方法 功能是一致的。 public final void lazySet(int newValue) { unsafe.putOrderedInt(this, valueOffset, newValue); } //将value设置成给定值,并返回旧值 public final int getAndSet(int newValue) { return unsafe.getAndSetInt(this, valueOffset, newValue); } //使用CAS机制更新 public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } //使用CAS机制更新 public final boolean weakCompareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } //CAS加1,并且返回原始值 public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); } //CAS减1,并且返回原始值 public final int getAndDecrement() { return unsafe.getAndAddInt(this, valueOffset, -1); } //CAS加减delta值,并且返回原始值 public final int getAndAdd(int delta) { return unsafe.getAndAddInt(this, valueOffset, delta); } //CAS加1,并且返回最新值 public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; } //CAS减1,并且返回最新值 public final int decrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, -1) - 1; } //CAS加减delta值,并且返回最新值 public final int addAndGet(int delta) { return unsafe.getAndAddInt(this, valueOffset, delta) + delta; }
策略更新
下面几个方法个人觉得不是很有用,和上面的区别就是更新的值不是穿进去的,而是通过IntUnaryOperator
和IntBinaryOperator
接口算出来的。
public final int getAndUpdate(IntUnaryOperator updateFunction) { int prev, next; do { prev = get(); next = updateFunction.applyAsInt(prev); } while (!compareAndSet(prev, next)); return prev; } public final int updateAndGet(IntUnaryOperator updateFunction) { int prev, next; do { prev = get(); next = updateFunction.applyAsInt(prev); } while (!compareAndSet(prev, next)); return next; } public final int getAndAccumulate(int x, IntBinaryOperator accumulatorFunction) { int prev, next; do { prev = get(); next = accumulatorFunction.applyAsInt(prev, x); } while (!compareAndSet(prev, next)); return prev; } public final int accumulateAndGet(int x,IntBinaryOperator accumulatorFunction) { int prev, next; do { prev = get(); next = accumulatorFunction.applyAsInt(prev, x); } while (!compareAndSet(prev, next)); return next; }
简单总结
总体来说,AtomicBoolean、AtomicInteger、AtomicLong和AtomicReference原理比较简单:使用CAS保证原子性,使用volatile保证可见性,最终能保证共享变量操作的线程安全。
AtomicLongArray、AtomicIntArray和AtomicReferenceArray的实现原理略有不同,是用CAS机制配合final机制来实现共享变量操作的线程安全的。感兴趣的同学可以自己分析下,也是比较简单的。
来源:https://www.cnblogs.com/54chensongxia/p/12161719.html