sun.misc.Unsafe 使Java拥有了像C语言的指针一样操作内存空间的能力,一旦能够直接操作内存
Unsafe类使Java拥有了像C语言的指针一样操作内存空间的能力,一旦能够直接操作内存,这也就意味着。 (1)不受jvm管理,也就意味着无法被GC,需要我们手动GC,稍有不慎就会出现内存泄漏。
(2)Unsafe的不少方法中必须提供原始地址(内存地址)和被替换对象的地址,偏移量要自己计算,一旦出现问题就是JVM崩溃级别的异常,会导致整个JVM实例崩溃,表现为应用程序直接crash掉。
(3)直接操作内存,也意味着其速度更快,在高并发的条件之下能够很好地提高效率。
因此,从上面三个角度来看,虽然在一定程度上提升了效率但是也带来了指针的不安全性。
使用方法
获取 Unsafe 实例
sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
或者也可以使用反射或者Spring提供的UnsafeUtils工具类(如下图)获取到Unsafe实例
如何具体使用
普通读写
Unsafe 可以 读写 一个类的非static属性,即使这个属性是私有的。
public native int getInt(Object var1, long var2);
public native void putInt(Object var1, long var2, int var4);
...
volatile 读写
普通读写无法保证 可见性和有效性,而 volatile 就可以保证 可见性和有效性,但是 相对于 普通读写 更加 昂贵。
public native Object getObjectVolatile(Object var1, long var2);
public native void putObjectVolatile(Object var1, long var2, Object var4);
...
有序写入
有序写入 只保证有序性、不保证可见性,就是 一个线程写入不保证其它线程立即可见。
与 volatile 写入相比,有序写入 代价 相对较小。putOrderedXX写入不保证可见性,但是保证有序性,所谓有序性,就是保证指令不会重排序。
public native void putOrderedObject(Object var1, long var2, Object var4);
public native void putOrderedInt(Object var1, long var2, int var4);
public native void putOrderedLong(Object var1, long var2, long var4);
内存管理(直接操作内存)
//内存管理和操作
public native long allocateMemory(long var1); //申请内存
public native long reallocateMemory(long var1, long var3); //调整内存
public native void setMemory(Object var1, long var2, long var4, byte var6);
public void setMemory(long var1, long var3, byte var5) { //将给定内存块中的所有字节设置为固定值(通常是0)。
this.setMemory((Object)null, var1, var3, var5);
}
public native void copyMemory(Object var1, long var2, Object var4, long var5, long var7); //内存复制 可以实现 对象浅拷贝
public void copyMemory(long var1, long var3, long var5) { //内存复制
this.copyMemory((Object)null, var1, (Object)null, var3, var5);
}
public native void freeMemory(long var1); //释放内存
CAS 操作
CAS操作为java的锁机制提供一种新的方案,比如 AtomicInteger等类都是通过该方法实现的。compareAndSwap*方法是原子的,可以避免繁重的锁机制,提高代码效率。
CAS 还广泛应用于 乐观锁 比如 ReentrantLock、ConcurrentHashMap,ConcurrentLinkedQueue等都有用到CAS来实现乐观锁。
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
偏移量
Unsafe 还提供了获取 对象的指针,通过对 指针进行 偏移,不仅可以修改 指针指向的的数据(即使它们是私有的),甚至可以
找到JVM已经认定为 垃圾、可以进行回收的对象。
public native long staticFieldOffset(Field var1); //获取静态属性Field在对象中的偏移量,读写静态属性时必须获取其偏移量
public native long objectFieldOffset(Field var1); //获取非静态属性Field在对象实例中的偏移量,读写对象的非静态属性时会用到这个偏移量
public native Object staticFieldBase(Field var1); //返回Field所在的对象
...
线程调度
通过park方法将线程进行挂起, 线程将一直阻塞到超时或中断条件出现。unpark方法可以终止一个挂起的线程,使其恢复正常。
整个并发框架中对线程的挂起操作被封装在LockSupport类中,LockSupport类中有各种版本park方法,但最终都调用了Unsafe.park()方法。
public native void unpark(Object var1); //唤醒线程
public native void park(boolean var1, long var2); //挂起线程 ;park(false,0) 表示永不到期,一直挂起,直至被唤醒
//park的参数,表示挂起的到期时间,第一个如果是true,表示绝对时间,则var2为绝对时间值,单位是毫秒。第一个参数如果是false,表示相对时间,则var2为相对时间值,单位是纳秒。
类加载 及 非常规对象实例化
可以 动态地创建类、动态的创建一个匿名内部类、判断是否需要初始化一个类、 保证已经初始化过一个类;
public native boolean shouldBeInitialized(Class<?> var1); //判断是否需要初始化一个类
public native void ensureClassInitialized(Class<?> var1); //保证已经初始化过一个类
public native Class<?> defineClass(String var1, byte[] var2, int var3, int var4, ClassLoader var5, ProtectionDomain var6); //方法定义一个类,用于动态地创建类
public native Class<?> defineAnonymousClass(Class<?> var1, byte[] var2, Object[] var3); //动态的创建一个匿名内部类
通常,我们通过new或反射来实例化对象,而Unsafe类提供的allocateInstance方法,可以直接生成对象实例,且无需调用构造方法和其他初始化方法;这在对象反序列化的时候会很有用,能够重建和设置final字段,而不需要调用构造方法。
public native Object allocateInstance(Class<?> var1) throws InstantiationException; //实例化一个 类实例 (非常规对象实例化)
内存屏障
public native void loadFence(); //保证在这个屏障之前的所有读操作都已经完成
public native void storeFence(); //保证在这个屏障之前的所有写操作都已经完成
public native void fullFence(); //保证在这个屏障之前的所有读写操作都已经完成
数组操作
arrayBaseOffset(获取数组第一个元素的偏移地址)与arrayIndexScale(获取数组中元素的增量地址)配合起来使用,
就可以定位数组中每个元素在内存中的位置。
由于Java的数组最大值为Integer.MAX_VALUE,使用Unsafe类的内存分配方法可以实现超大数组。实际上这样的数据就可以认为是C数组,因此需要注意在合适的时间释放内存。
//获取 数组 base 内存地址
public native int arrayBaseOffset(Class<?> var1);
//返回 数组中元素与元素之间的偏移地址的增量
public native int arrayIndexScale(Class<?> var1);
系统相关
//获取 本地指针的大小(单位是byte),通常值为4或者8。常量ADDRESS_SIZE就是调用此方法。
public native int addressSize();
public native int pageSize(); 内存页的大小,此值为2的幂次方。
源码解读 java8
package sun.misc;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.ProtectionDomain;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
public final class Unsafe {
private static final Unsafe theUnsafe; //单例 对象
public static final int INVALID_FIELD_OFFSET = -1;
public static final int ARRAY_BOOLEAN_BASE_OFFSET;
public static final int ARRAY_BYTE_BASE_OFFSET;
public static final int ARRAY_SHORT_BASE_OFFSET;
public static final int ARRAY_CHAR_BASE_OFFSET;
public static final int ARRAY_INT_BASE_OFFSET;
public static final int ARRAY_LONG_BASE_OFFSET;
public static final int ARRAY_FLOAT_BASE_OFFSET;
public static final int ARRAY_DOUBLE_BASE_OFFSET;
public static final int ARRAY_OBJECT_BASE_OFFSET;
public static final int ARRAY_BOOLEAN_INDEX_SCALE;
public static final int ARRAY_BYTE_INDEX_SCALE;
public static final int ARRAY_SHORT_INDEX_SCALE;
public static final int ARRAY_CHAR_INDEX_SCALE;
public static final int ARRAY_INT_INDEX_SCALE;
public static final int ARRAY_LONG_INDEX_SCALE;
public static final int ARRAY_FLOAT_INDEX_SCALE;
public static final int ARRAY_DOUBLE_INDEX_SCALE;
public static final int ARRAY_OBJECT_INDEX_SCALE;
public static final int ADDRESS_SIZE;
//私有的构造方法
private Unsafe() {
}
private static native void registerNatives(); //注册natives 方法,使得 Unsafe 类 可以操作 C 语言
static {
registerNatives();
Reflection.registerMethodsToFilter(Unsafe.class, new String[]{"getUnsafe"}); //给 Unsafe 注册 getUnsafe 方法
theUnsafe = new Unsafe(); //实例化 theUnsafe 对象
ARRAY_BOOLEAN_BASE_OFFSET = theUnsafe.arrayBaseOffset(boolean[].class);
ARRAY_BYTE_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class);
ARRAY_SHORT_BASE_OFFSET = theUnsafe.arrayBaseOffset(short[].class);
ARRAY_CHAR_BASE_OFFSET = theUnsafe.arrayBaseOffset(char[].class);
ARRAY_INT_BASE_OFFSET = theUnsafe.arrayBaseOffset(int[].class);
ARRAY_LONG_BASE_OFFSET = theUnsafe.arrayBaseOffset(long[].class);
ARRAY_FLOAT_BASE_OFFSET = theUnsafe.arrayBaseOffset(float[].class);
ARRAY_DOUBLE_BASE_OFFSET = theUnsafe.arrayBaseOffset(double[].class);
ARRAY_OBJECT_BASE_OFFSET = theUnsafe.arrayBaseOffset(Object[].class);
ARRAY_BOOLEAN_INDEX_SCALE = theUnsafe.arrayIndexScale(boolean[].class);
ARRAY_BYTE_INDEX_SCALE = theUnsafe.arrayIndexScale(byte[].class);
ARRAY_SHORT_INDEX_SCALE = theUnsafe.arrayIndexScale(short[].class);
ARRAY_CHAR_INDEX_SCALE = theUnsafe.arrayIndexScale(char[].class);
ARRAY_INT_INDEX_SCALE = theUnsafe.arrayIndexScale(int[].class);
ARRAY_LONG_INDEX_SCALE = theUnsafe.arrayIndexScale(long[].class);
ARRAY_FLOAT_INDEX_SCALE = theUnsafe.arrayIndexScale(float[].class);
ARRAY_DOUBLE_INDEX_SCALE = theUnsafe.arrayIndexScale(double[].class);
ARRAY_OBJECT_INDEX_SCALE = theUnsafe.arrayIndexScale(Object[].class);
ADDRESS_SIZE = theUnsafe.addressSize();
}
//获取 unsafe 实例,只有由主类加载器加载的类才能调用这个方法
@CallerSensitive
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}
//数组操作
//获取 数组 base 内存地址
public native int arrayBaseOffset(Class<?> var1);
//返回 数组中元素与元素之间的偏移地址的增量
public native int arrayIndexScale(Class<?> var1);
//对象属性 读写 的操作方法
public native int getInt(Object var1, long var2);
public native void putInt(Object var1, long var2, int var4);
public native Object getObject(Object var1, long var2);
public native void putObject(Object var1, long var2, Object var4);
public native boolean getBoolean(Object var1, long var2);
public native void putBoolean(Object var1, long var2, boolean var4);
public native byte getByte(Object var1, long var2);
public native void putByte(Object var1, long var2, byte var4);
public native short getShort(Object var1, long var2);
public native void putShort(Object var1, long var2, short var4);
public native char getChar(Object var1, long var2);
public native void putChar(Object var1, long var2, char var4);
public native long getLong(Object var1, long var2);
public native void putLong(Object var1, long var2, long var4);
public native float getFloat(Object var1, long var2);
public native void putFloat(Object var1, long var2, float var4);
public native double getDouble(Object var1, long var2);
public native void putDouble(Object var1, long var2, double var4);
// volatile 对象属性 读写 的操作方法
public native Object getObjectVolatile(Object var1, long var2);
public native void putObjectVolatile(Object var1, long var2, Object var4);
public native int getIntVolatile(Object var1, long var2);
public native void putIntVolatile(Object var1, long var2, int var4);
public native boolean getBooleanVolatile(Object var1, long var2);
public native void putBooleanVolatile(Object var1, long var2, boolean var4);
public native byte getByteVolatile(Object var1, long var2);
public native void putByteVolatile(Object var1, long var2, byte var4);
public native short getShortVolatile(Object var1, long var2);
public native void putShortVolatile(Object var1, long var2, short var4);
public native char getCharVolatile(Object var1, long var2);
public native void putCharVolatile(Object var1, long var2, char var4);
public native long getLongVolatile(Object var1, long var2);
public native void putLongVolatile(Object var1, long var2, long var4);
public native float getFloatVolatile(Object var1, long var2);
public native void putFloatVolatile(Object var1, long var2, float var4);
public native double getDoubleVolatile(Object var1, long var2);
public native void putDoubleVolatile(Object var1, long var2, double var4);
//对象属性 有序写入 的操作方法
public native void putOrderedObject(Object var1, long var2, Object var4);
public native void putOrderedInt(Object var1, long var2, int var4);
public native void putOrderedLong(Object var1, long var2, long var4);
//内存管理和操作
public native long allocateMemory(long var1); //申请内存
public native long reallocateMemory(long var1, long var3); //调整内存
public native void setMemory(Object var1, long var2, long var4, byte var6);
public void setMemory(long var1, long var3, byte var5) { //将给定内存块中的所有字节设置为固定值(通常是0)。
this.setMemory((Object)null, var1, var3, var5);
}
public native void copyMemory(Object var1, long var2, Object var4, long var5, long var7); //内存复制
public void copyMemory(long var1, long var3, long var5) { 内存复制
this.copyMemory((Object)null, var1, (Object)null, var3, var5);
}
public native void freeMemory(long var1); //释放内存
//cas 操作
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
// 偏移量 操作 方法
/** @deprecated */
@Deprecated
public int fieldOffset(Field var1) {
return Modifier.isStatic(var1.getModifiers()) ? (int)this.staticFieldOffset(var1) : (int)this.objectFieldOffset(var1);
}
/** @deprecated */
@Deprecated
public Object staticFieldBase(Class<?> var1) {
Field[] var2 = var1.getDeclaredFields();
for(int var3 = 0; var3 < var2.length; ++var3) {
if (Modifier.isStatic(var2[var3].getModifiers())) {
return this.staticFieldBase(var2[var3]);
}
}
return null;
}
public native long staticFieldOffset(Field var1); //获取静态属性Field在对象中的偏移量,读写静态属性时必须获取其偏移量
public native long objectFieldOffset(Field var1); //获取非静态属性Field在对象实例中的偏移量,读写对象的非静态属性时会用到这个偏移量
public native Object staticFieldBase(Field var1); //返回Field所在的对象
// 线程调度
public native void unpark(Object var1); //唤醒线程
public native void park(boolean var1, long var2); //挂起线程 ;park(false,0) 表示永不到期,一直挂起,直至被唤醒
//park的参数,表示挂起的到期时间,第一个如果是true,表示绝对时间,则var2为绝对时间值,单位是毫秒。第一个参数如果是false,表示相对时间,则var2为相对时间值,单位是纳秒。
//类加载
public native boolean shouldBeInitialized(Class<?> var1); //判断是否需要初始化一个类
public native void ensureClassInitialized(Class<?> var1); //保证已经初始化过一个类
public native Class<?> defineClass(String var1, byte[] var2, int var3, int var4, ClassLoader var5, ProtectionDomain var6); //方法定义一个类,用于动态地创建类
public native Class<?> defineAnonymousClass(Class<?> var1, byte[] var2, Object[] var3); //动态的创建一个匿名内部类
public native Object allocateInstance(Class<?> var1) throws InstantiationException; //实例化一个 类实例 (非常规对象实例化)
//内存屏障
public native void loadFence(); //保证在这个屏障之前的所有读操作都已经完成
public native void storeFence(); //保证在这个屏障之前的所有写操作都已经完成
public native void fullFence(); //保证在这个屏障之前的所有读写操作都已经完成
//两个系统相关的方法:
//获取 本地指针的大小(单位是byte),通常值为4或者8。常量ADDRESS_SIZE就是调用此方法。
public native int addressSize();
public native int pageSize(); 内存页的大小,此值为2的幂次方。
//采集系统 负载数据
public native int getLoadAverage(double[] var1, int var2);
// Atomic 类实现相关
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
public final long getAndAddLong(Object var1, long var2, long var4) {
long var6;
do {
var6 = this.getLongVolatile(var1, var2);
} while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4));
return var6;
}
public final int getAndSetInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var4));
return var5;
}
public final long getAndSetLong(Object var1, long var2, long var4) {
long var6;
do {
var6 = this.getLongVolatile(var1, var2);
} while(!this.compareAndSwapLong(var1, var2, var6, var4));
return var6;
}
public final Object getAndSetObject(Object var1, long var2, Object var4) {
Object var5;
do {
var5 = this.getObjectVolatile(var1, var2);
} while(!this.compareAndSwapObject(var1, var2, var5, var4));
return var5;
}
}
LockSupport
使用例子
LockSupport.park() //挂起线程;表示永不到期,一直挂起,直至被其它线程唤醒
LockSupport.park(blocker) //被 blocker 挂起线程;表示永不到期,一直挂起,直至被其它线程唤醒
LockSupport.unpark(thread) //唤醒 thread
LockSupport.parkUntil(blocker, long deadline) //被 blocker 挂起直到 deadline 时间戳,后 自动唤醒
LockSupport.parkUntil(long deadline) //挂起直到 deadline 时间戳,后 自动唤醒
LockSupport.parkNanos(blocker, long nanos) //被 blocker 挂起直到 nanos 毫秒,后 自动唤醒
LockSupport.parkNanos(long nanos) //挂起直到 nanos 毫秒,后 自动唤醒
源码阅读
基本的线程锁
package java.util.concurrent.locks;
import sun.misc.Unsafe;
public class LockSupport {
private LockSupport() {} //私有的构造方法,不能被外部实例化
private static final sun.misc.Unsafe UNSAFE;
private static final long parkBlockerOffset; //Thread class parkBlocker 字段 内存地址;用于记录线程被谁阻塞的,用于线程监控和分析工具来定位原因的
private static final long SEED; //Thread class threadLocalRandomSeed 字段 内存地址
private static final long PROBE; //Thread class threadLocalRandomProbe 字段 内存地址
private static final long SECONDARY; //Thread class threadLocalRandomSecondarySeed 字段 内存地址
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> tk = Thread.class;
parkBlockerOffset = UNSAFE.objectFieldOffset
(tk.getDeclaredField("parkBlocker")); //获取 Thread class parkBlocker 字段 内存地址
SEED = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomSeed")); //获取 Thread class threadLocalRandomSeed 字段 内存地址
PROBE = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomProbe")); //获取 Thread class threadLocalRandomProbe 字段 内存地址
SECONDARY = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomSecondarySeed")); //获取 Thread class threadLocalRandomSecondarySeed 字段 内存地址
} catch (Exception ex) { throw new Error(ex); }
}
// 设置 线程t parkBlocker 字段为 arg ;这里只是记录 线程是被谁 阻塞的
private static void setBlocker(Thread t, Object arg) {
// Even though volatile, hotspot doesn't need a write barrier here.
UNSAFE.putObject(t, parkBlockerOffset, arg);
}
// 唤醒 thread 线程
public static void unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}
// 记录被阻塞者,并一直阻塞 本线程, 清除 被阻塞者信息
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker); //设置这个线程 被谁阻塞
UNSAFE.park(false, 0L); //一直阻塞这个线程
setBlocker(t, null); //设置这个线程 被阻塞者是 null;即清楚 被阻塞者
}
//记录被阻塞者,并阻塞 本线程 nanos 毫秒, 清除 被阻塞者信息
public static void parkNanos(Object blocker, long nanos) {
if (nanos > 0) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(false, nanos);
setBlocker(t, null);
}
}
//记录被阻塞者,并阻塞 本线程 直到 deadline时间戳, 清除 被阻塞者信息
public static void parkUntil(Object blocker, long deadline) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
UNSAFE.park(true, deadline);
setBlocker(t, null);
}
//或者 thread 被谁阻塞
public static Object getBlocker(Thread t) {
if (t == null)
throw new NullPointerException();
return UNSAFE.getObjectVolatile(t, parkBlockerOffset);
}
//一直阻塞 本线程
public static void park() {
UNSAFE.park(false, 0L);
}
//阻塞 本线程 nanos 毫秒
public static void parkNanos(long nanos) {
if (nanos > 0)
UNSAFE.park(false, nanos);
}
//阻塞本线程,直到 deadline 时间戳
public static void parkUntil(long deadline) {
UNSAFE.park(true, deadline);
}
//产生本线程的 SecondarySeed 随机数 种子;为下一次生成随机数的因子
static final int nextSecondarySeed() {
int r;
Thread t = Thread.currentThread();
if ((r = UNSAFE.getInt(t, SECONDARY)) != 0) {
r ^= r << 13; // xorshift
r ^= r >>> 17;
r ^= r << 5;
}
else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0)
r = 1; // avoid zero
UNSAFE.putInt(t, SECONDARY, r);
return r;
}
}
Atomic
基本类型
AtomicBoolean
AtomicInteger
package java.util.concurrent.atomic;
import java.util.function.IntUnaryOperator;
import java.util.function.IntBinaryOperator;
import sun.misc.Unsafe;
public class AtomicInteger extends Number implements java.io.Serializable {
private static final Unsafe unsafe = Unsafe.getUnsafe(); //获取 unsafe 实例
private volatile int value; //注意 需要用 volatile 修饰;有序性和可见性
private static final long valueOffset; // 上面 value 在 内部布局中的 内存偏移量;用于原子操作
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value")); //设置 value 在 内部布局中的 内存偏移量
} catch (Exception ex) { throw new Error(ex); }
}
//无参构造方法
public AtomicInteger() {
}
//有初始值构造方法
public AtomicInteger(int initialValue) {
value = initialValue;
}
//设置 value 值
public final void set(int newValue) {
value = newValue;
}
//获取 当前 value 值
public final int get() {
return value;
}
//有序性 设置 value 值
public final void lazySet(int newValue) {
unsafe.putOrderedInt(this, valueOffset, newValue);
}
//原子性 设置新值,返回 旧值
public final int getAndSet(int newValue) {
return unsafe.getAndSetInt(this, valueOffset, newValue);
}
//原子性 当 value是 expect时,设置为 update
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
//原子性 + 1 操作,返回旧值
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
//原子性 -1 操作,返回旧值
public final int getAndDecrement() {
return unsafe.getAndAddInt(this, valueOffset, -1);
}
//原子性 +delta 操作,返回旧值
public final int getAndAdd(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta);
}
//原子性 + 1 操作,返回 新值
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
//原子性 -1 操作,返回 新值
public final int decrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
}
//原子性 +delta 操作,返回 新值
public final int addAndGet(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
}
//原子性 使用 updateFunction 值 更新 value 当前值,返回 更新前的值 ;需要注意的是,提供的方法应该无副作用(side-effect-free),即两次执行结果相同,原因是如果由于线程争用导致更新失败会尝试再次执行该方法。
public final int getAndUpdate(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return prev;
}
//原子性 使用 updateFunction 值 更新 value 当前值,返回 更新后的值 ;需要注意的是,提供的方法应该无副作用(side-effect-free),即两次执行结果相同,原因是如果由于线程争用导致更新失败会尝试再次执行该方法。
public final int updateAndGet(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return next;
}
//原子性 使用 updateFunction 值 更新 value 当前值,返回 更新前的值 ;需要注意的是,提供的方法应该无副作用(side-effect-free),即两次执行结果相同,原因是如果由于线程争用导致更新失败会尝试再次执行该方法。
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;
}
//原子性 使用 updateFunction 值 更新 value 当前值,返回 更新后的值 ;需要注意的是,提供的方法应该无副作用(side-effect-free),即两次执行结果相同,原因是如果由于线程争用导致更新失败会尝试再次执行该方法。
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;
}
}
AtomicLong
引用类型
AtomicReference 原子更新引用类型,有ABA问题
AtomicStampedReference 原子更新引用类型(带时间戳,避免ABA问题)
AtomicReferenceFieldUpdater 原子更新引用类型的字段
AtomicMarkableReferce 原子更新带有标记位的引用类型 有ABA问题
数组类型
AtomicIntegerArray
AtomicLongArray
AtomicReferenceArray
字段类型
AtomicIntegerFieldUpdater
AtomicLongFieldUpdater
AtomicStampedFieldUpdater
JDK8新增原子类简介
DoubleAccumulator
LongAccumulator
DoubleAdder
LongAdder
总结
最后,简单总结下几种解决方案之间的区别:
特性 | Atomic变量 | volatile关键字 | Lock接口 | synchronized关键字 |
---|---|---|---|---|
原子性 | 可以保障 | 无法保障 | 可以保障 | 可以保障 |
可见性 | 可以保障 | 可以保障 | 可以保障 | 可以保障 |
有序性 | 无法保障 | 一定程度保障 | 可以保障 | 可以保障 |