JDK的rt.jar包中的Unsafe類提供了硬件級別的原子性操作,Unsafe類中的方法都是native方法,
它們使用JNI的方式訪問本地C++ 實現庫。
錯誤代碼示範:
public class TestUnSafe {
/*********
* 直接下面這種方式會報錯:原因是我們自己寫的類是由AppClassLoader類加載器加載;
* 而UnSafe類的getUnsafe()爲了保證rt包的安全;Unsafe類可以直接操作內存;
* 不讓開發人員在正規渠道使用Unsafe類,而是在rt.jar包裏面的核心類中使用Unsafe功能。
@CallerSensitive
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}
* 改爲後面的反射方式獲取theUnsafe成員變量
* java.lang.ExceptionInInitializerError
* Caused by: java.lang.SecurityException: Unsafe
* at sun.misc.Unsafe.getUnsafe(Unsafe.java:90)
* at com.liang.unsafe.TestUnSafe.<clinit>(TestUnSafe.java:12)
* Exception in thread "main"
*******/
//獲取Unsafe的實例
static final Unsafe unsafe = Unsafe.getUnsafe();
//記錄變量state在類TestUnSafe中的偏移值
static final long stateOffset;
private volatile long state = 0;
static {
try {
System.out.println(TestUnSafe.class.getClassLoader());
stateOffset = unsafe.objectFieldOffset(TestUnSafe.class.getDeclaredField("state"));
} catch (NoSuchFieldException e) {
System.out.println(e.getCause());
throw new Error(e);
}
}
public static void main(String[] args) {
// 創建實例,並設置state值爲1
TestUnSafe testUnSafe = new TestUnSafe();
Boolean success = unsafe.compareAndSwapLong(testUnSafe,stateOffset,0,1);
System.out.println(success);
}
}
正確代碼示範:
public class TestUnSafe {
//獲取Unsafe的實例
static Unsafe unsafe;
//記錄變量state在類TestUnSafe中的偏移值
static long stateOffset;
private volatile long state = 0;
static {
try {
// 使用反射獲取Unsafe的成員變量theUnsafe
Field field = Unsafe.class.getDeclaredField("theUnsafe");
//設置爲可讀取
field.setAccessible(true);
unsafe = (Unsafe) field.get(null);
// 獲取state 在 TestUnSafe中的偏移量
stateOffset = unsafe.objectFieldOffset(TestUnSafe.class.getDeclaredField("state"));
} catch (NoSuchFieldException e) {
System.out.println(e.getCause());
throw new Error(e);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
System.out.println(TestUnSafe.class.getClassLoader());
// 創建實例,並設置state值爲1
TestUnSafe testUnSafe = new TestUnSafe();
Boolean success = unsafe.compareAndSwapLong(testUnSafe,stateOffset,0,1);
System.out.println(success);
// 返回指定的變量在所屬類中的內存偏移地址,該偏移地址僅僅在該Unsafe函數中訪問指定字段時使用。
System.out.println(unsafe.objectFieldOffset((AtomicLong.class.getDeclaredField("value"))));
}
}