java unsafe 原子操作_sun.misc.Unsafe类 (内存操作/对象字段操作/原子操作/线程操作)...

一. 关于sun.misc.Unsafe类

sun.misc.Unsafe类的描述如下:

/**

* A collection of methods for performing low-level, unsafe operations.

* Although the class and all methods are public, use of this class is

* limited because only trusted code can obtain instances of it.

*/

简单来说, Unsafe类提供了一些比较底层的不安全的操作. 因此此类只有那些可以被信任的代码才能调用. 此类只能通过其静态方法getUnsafe()获得其实例. Unsafe类的这些底层操作非常有用, 因此非常多的库或应用都使用了Unsafe的相关功能, 从此文中可窥一斑 => Removal of sun.misc.Unsafe in Java 9 - A disaster in the making. 大家不用担心, Java9中Unsafe还是可用的 => Using sun.misc.Unsafe in Java 9

public final class Unsafe {

private Unsafe() {}

private static final Unsafe theUnsafe = new Unsafe();

@CallerSensitive

public static Unsafe getUnsafe() {

Class> caller = Reflection.getCallerClass();

if (!VM.isSystemDomainLoader(caller.getClassLoader()))

throw new SecurityException("Unsafe");

return theUnsafe;

}

//其余部分省略 ...

}

可以看到, Unsafe类是一个单例类, 通过静态的getUnsafe()方法获取实例. getUnsafe()方法中有一个权限检查的逻辑, 即: 如果不是系统域下的类调用getUnsafe()方法将抛出SecurityException异常.

因此, 非系统类库要获取Unsafe的实例就不能直接调用getUnsafe()方法. 从上面可以看到, Unsafe类有一个类型为其本身的静态常量theUnsafe, 因此我们可以用反射来获取其实例. 代码如下:

private static void init() {

try {

unsafeClass = Class.forName("sun.misc.Unsafe");

Field theUnsafeField = unsafeClass.getDeclaredField("theUnsafe");

boolean orignialAccessible = theUnsafeField.isAccessible();

theUnsafeField.setAccessible(true);

unsafeInstance = theUnsafeField.get(null); //unsafeInstance就是Unsafe的实例

theUnsafeField.setAccessible(orignialAccessible);

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (NoSuchFieldException e) {

e.printStackTrace();

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

Unsafe的相关功能如下:

1. 通过一个Class对象创建一个实例 (不经过构造函数直接生成对象, 这个非常厉害, 具体原理有待研究!)

Object allocateInstance(Class> cls)

不通过构造方法就实例化出一个对象.

此功能的运用

一些常见的JSON库一般都需要一个无参构造方法来实例化一个POJO对象, 有了Unsafe类的这个功能, 就算没有构造方法, 这些JSON库也可以实例化对象了. Gson库就使用了该功能,

详情见: com.google.gson.internal.UnsafeAllocator. 有一个专门用来创建对象 (绕开构造方法) 的库Objenesis底层也有此功能的运用.

2. 管理和操作内存

内存管理:

long allocateMemory(long bytes)

开辟一块内存. 参数为要开辟内存的大小, 多少字节; 返回值是一个native pointer, 就是内存地址.

void freeMemory(long address)

释放一块内存. 参数为内存地址. 即allocateMemory()方法的返回值.

long reallocateMemory(long address, long bytes)

重新分配 (扩展) 一块内存 (之前分配内存当然会被GC回收掉). 第一个参数为原内存地址, 第二个参数为重新分配的内存的大小 (要超过前一块内存的大小), 返回新的内存地址. 原内存中的内容会迁移到新开辟的内存中.

内存操作 (往内存中存数据 或 从内存中取数据):

void putType(long address, type data) 、type getType(long address, long offset)

i. type 为原始数据类型: boolean, byte、char、short、int、long、float、double

ii. 第一个参数address, 为内存地址(参考allocateMemory())

iii. 第二个参数offset, 字段的偏移量, 用下列方法获取:

long objectFieldOffset(Field field) - 获取实例字段的偏移量

long staticFieldOffset(Field field) - 获取静态字段的偏移量

3. 操作对象字段的值 (无视可见性)

void putType(Object o, long offset, type data) 和 type getType(Object o, long offset)

i. type为原始数据类型和Object

ii. 第一个参数o, 为要操作的对象 (如果是静态字段, 则第一个参数传Class>对象)

iii. 第二个参数offset, 为字段的偏移量, 其获取方式同内存操作中涉及的offset的获取一样

iiii. 字段操作还有volatile版的, 如: putObjectVolatile()、 getIntVolatile() 等

4. 原子操作

CAS操作

compareAndSwapXxx(Object o, long offset, Object expected, Object newValue) - 对象字段的CAS操作

tips: CAS操作有3个操作数,内存值M,预期值E,新值U,如果M==E,则将内存值修改为B,否则啥都不做。

JDK1.8: getAndAddInt()、getAndSetInt()、getAndAddLong()、getAndSetLong()、getAndAddObject()、getAndSetObject() - 原子操作 => 值操作: 获取 和 更新

5. 线程操作

void unpark(Object thread) - 取消挂起

void park(boolean isAbsolute, long time) - 挂起

将一个线程进行挂起是通过park方法实现的,调用park()后,线程将一直阻塞直到超时或者中断等条件出现。unpark()可以终止一个挂起的线程,使其恢复正常。整个并发框架中对线程的挂起操作被封装在 LockSupport类中,LockSupport类中有各种版本pack()方法,但最终都调用了Unsafe.park()方法。

6. 数组元素定位

int arrayIndexScale(Class> arrayClass)

int arrayBaseOffset(Class> arrayClass)

Unsafe类中有很多以BASE_OFFSET结尾的常量,如ARRAY_INT_BASE_OFFSET,ARRAY_BYTE_BASE_OFFSET等,这些常量值是通过arrayBaseOffset()方法得到的。arrayBaseOffset()方法是一个本地方法,可以获取数组第一个元素的偏移地址。Unsafe类中还有很多以INDEX_SCALE结尾的常量,如 ARRAY_INT_INDEX_SCALE , ARRAY_BYTE_INDEX_SCALE等,这些常量值是通过arrayIndexScale()方法得到的。arrayIndexScale()方法也是一个本地方法,可以获取数组的转换因子,也就是数组中元素的增量地址。将arrayBaseOffset()与arrayIndexScale()配合使用,可以定位数组中每个元素在内存中的位置。

6. 其他 (略)

setMemory()、copyMemory()、addressSize()、pageSize()、defineClass()、defineAnonymousClass()

Java8: loadFence()、 storeFence()、fullFence()

Java9: invokeCleaner()

......

二. 为了不在代码中出现sun.misc.Unsafe相关API的直接调用 (避免直接依赖, 必要时可以更换具体实现) , 我使用反射对sun.misc.Unsafe进行了封装 (不常用的方法省略), 封装类UnsafeWrapper

下面是封装类UnsafeWrapper的一个使用Demo (具体说明, 请看其中的注释, UnsafeWrapper类的源码在Demo之后) :

package com;

import com.stone.UnsafeWrapper;

import java.io.UnsupportedEncodingException;

//http://hg.openjdk.java.net/jdk9/client/jdk/file/adc00ab4ac58/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java

//http://hg.openjdk.java.net/jdk9/client/jdk/file/65464a307408/src/java.base/share/classes/jdk/internal/misc/Unsafe.java

public class Demo {

private int fieldA = 2;

private static String fieldB = "Unknown";

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, UnsupportedEncodingException {

demo0();

demo1();

demo2();

}

//创建对象, 而不经过构造方法

private static void demo0() {

Demo t2 = UnsafeWrapper.allocateInstance(Demo.class);

System.out.println("demo0: Test2 = " + t2);

System.out.println("demo0: fieldA = " + t2.fieldA);

System.out.println("demo0: fieldB = " + Demo.fieldB);

}

//操作一个对象的属性 (private修饰的属性也可以操作)

static void demo1() throws NoSuchFieldException {

/**

try {

//不能直接调用Unsafe.getUnsafe()方法: Exception in thread "main" java.lang.SecurityException: Unsafe

//Unsafe unsafe = Unsafe.getUnsafe();

//使用反射获取Unsafe的实例, 绕过安全检查

Unsafe unsafe = getUnsafe();

Test2 t = new Test2();

Field aField = Test2.class.getDeclaredField("fieldA");

int aValue = unsafe.getInt(t, unsafe.objectFieldOffset(aField));

System.out.println("fieldA = " + aValue);

unsafe.putInt(t, unsafe.objectFieldOffset(aField), 102);

aValue = unsafe.getInt(t, unsafe.objectFieldOffset(aField));

System.out.println("fieldA = " + aValue);

} catch(Exception e) {

e.printStackTrace();

}*/

///操作实例属性/

Demo t = new Demo();

System.out.println("primitive type: ");

int fieldA = UnsafeWrapper.getInt(t, UnsafeWrapper.objectFieldOffset(Demo.class.getDeclaredField("fieldA")));

System.out.println("fieldA value (before change) = " + fieldA);

UnsafeWrapper.putInt(t, UnsafeWrapper.objectFieldOffset(Demo.class.getDeclaredField("fieldA")), 5023);

fieldA = UnsafeWrapper.getInt(t, UnsafeWrapper.objectFieldOffset(Demo.class.getDeclaredField("fieldA")));

System.out.println("fieldA value (after change) = " + fieldA);

///操作静态属性/

System.out.println("reference type: ");

String fieldB = (String) UnsafeWrapper.getObject(Demo.class, UnsafeWrapper.staticFieldOffset(Demo.class.getDeclaredField("fieldB")));

System.out.println("fieldB value: " + fieldB);

UnsafeWrapper.putObject(Demo.class, UnsafeWrapper.staticFieldOffset(Demo.class.getDeclaredField("fieldB")), "呵呵呵呵");

fieldB = (String) UnsafeWrapper.getObject(Demo.class, UnsafeWrapper.staticFieldOffset(Demo.class.getDeclaredField("fieldB")));

System.out.println("fieldB value: " + fieldB);

}

//管理和操作内存

static void demo2() throws UnsupportedEncodingException {

//开辟一块内存

long initMemorySize = 20;

long address = UnsafeWrapper.allocateMemory(initMemorySize);

System.out.println("original memory address: " + address);

String greeting = "Hello world !";

byte[] bytes = greeting.getBytes("utf-8");

//将byte[]放入手动开辟的内存块中

UnsafeWrapper.putByteArray(address, bytes);

//从内指定的内存块中取出数据

byte[] readedBytes = UnsafeWrapper.readByteArray(address, bytes.length);

System.out.println("content in original memory: " + new String(readedBytes, "utf-8"));

//扩展内存大小

long extMemorySize = 1024; //扩展的内存大小必须比之前分配的内存大

address = UnsafeWrapper.reallocateMemory(address, extMemorySize);

System.out.println("reallocate memory address: " + address);

readedBytes = UnsafeWrapper.readByteArray(address, bytes.length);

System.out.println("content in reallocate memory: " + new String(readedBytes, "utf-8"));

//释放内存

UnsafeWrapper.freeMemory(address);

}

}

UnsafeWrapper类源码如下:

import java.lang.reflect.Field;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

public final class UnsafeWrapper {

private static Class unsafeClass;

private static Object unsafeInstance;

private UnsafeWrapper() {

//no instance

}

/** ==============================================*/

/** ====================内存块操作==================*/

/** ==============================================*/

/**

* Allocates a new block of native memory, of the given size in bytes. The

* contents of the memory are uninitialized; they will generally be

* garbage. The resulting native pointer will never be zero, and will be

* aligned for all value types. Dispose of this memory by calling {@link

* #freeMemory}, or resize it with {@link #reallocateMemory}.

*

* Note: It is the resposibility of the caller to make

* sure arguments are checked before the methods are called. While

* some rudimentary checks are performed on the input, the checks

* are best effort and when performance is an overriding priority,

* as when methods of this class are optimized by the runtime

* compiler, some or all checks (if any) may be elided. Hence, the

* caller must not rely on the checks and corresponding

* exceptions!

*

* @throws RuntimeException if the size is negative or too large

* for the native size_t type

*

* @throws OutOfMemoryError if the allocation is refused by the system

*

* @see #getByte(long)

* @see #putByte(long, byte)

*/

public static long allocateMemory(long bytes) {

long address = 0;

try {

Method allocateMemoryMethod = unsafeClass().getDeclaredMethod("allocateMemory", long.class);

address = (long) allocateMemoryMethod.invoke(unsafeInstance(), bytes);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return address;

}

/**

* Resizes a new block of native memory, to the given size in bytes. The

* contents of the new block past the size of the old block are

* uninitialized; they will generally be garbage. The resulting native

* pointer will be zero if and only if the requested size is zero. The

* resulting native pointer will be aligned for all value types. Dispose

* of this memory by calling {@link #freeMemory}, or resize it with {@link

* #reallocateMemory}. The address passed to this method may be null, in

* which case an allocation will be performed.

*

* Note: It is the resposibility of the caller to make

* sure arguments are checked before the methods are called. While

* some rudimentary checks are performed on the input, the checks

* are best effort and when performance is an overriding priority,

* as when methods of this class are optimized by the runtime

* compiler, some or all checks (if any) may be elided. Hence, the

* caller must not rely on the checks and corresponding

* exceptions!

*

* @throws RuntimeException if the size is negative or too large

* for the native size_t type

*

* @throws OutOfMemoryError if the allocation is refused by the system

*

* @see #allocateMemory

*/

public static long reallocateMemory(long address, long bytes) {

long result = 0;

try {

Method allocateMemoryMethod = unsafeClass().getDeclaredMethod("reallocateMemory", long.class, long.class);

result = (long) allocateMemoryMethod.invoke(unsafeInstance(), address, bytes);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/**

* Disposes of a block of native memory, as obtained from {@link

* #allocateMemory} or {@link #reallocateMemory}. The address passed to

* this method may be null, in which case no action is taken.

*

* Note: It is the resposibility of the caller to make

* sure arguments are checked before the methods are called. While

* some rudimentary checks are performed on the input, the checks

* are best effort and when performance is an overriding priority,

* as when methods of this class are optimized by the runtime

* compiler, some or all checks (if any) may be elided. Hence, the

* caller must not rely on the checks and corresponding

* exceptions!

*

* @throws RuntimeException if any of the arguments is invalid

*

* @see #allocateMemory

*/

public static void freeMemory(long address) {

try {

Method freeMemoryMethod = unsafeClass().getDeclaredMethod("freeMemory", long.class);

freeMemoryMethod.invoke(unsafeInstance(), address);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

/**

* Fetches a value from a given memory address. If the address is zero, or

* does not point into a block obtained from {@link #allocateMemory}, the

* results are undefined.

*

* @see #allocateMemory

*/

public static byte getByte(long address) {

byte result = 0;

try {

Method allocateMemoryMethod = unsafeClass().getDeclaredMethod("getByte", long.class);

result = (byte) allocateMemoryMethod.invoke(unsafeInstance(), address);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/**

* Stores a value into a given memory address. If the address is zero, or

* does not point into a block obtained from {@link #allocateMemory}, the

* results are undefined.

*

* @see #getByte(long)

*/

public static void putByte(long address, byte x) {

try {

Method allocateMemoryMethod = unsafeClass().getDeclaredMethod("putByte", long.class, byte.class);

allocateMemoryMethod.invoke(unsafeInstance(), address, x);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

/**

* 从内存中读取一个数组

*

* @param startAddress 内存起始地址

* @param len 要读取的数组的长度

* @return 返回从内存中读取到的数组

*/

public static byte[] readByteArray(long startAddress, int len) {

byte[] bytes = new byte[len];

long currentAddress = startAddress;

long lastAddress = startAddress + len;

while(currentAddress < lastAddress) {

int currentIndex = (int) (currentAddress - startAddress);

bytes[currentIndex] = getByte(currentAddress);

currentAddress++;

}

return bytes;

}

/**

* 把一个byte[]放到指定的内存块中

*

* @param startAddress 内存块的起始位置

* @param bytes 要被存放的内存

*/

public static void putByteArray(long startAddress, byte[] bytes) {

long currentAddress = startAddress;

long lastAddress = startAddress + bytes.length;

while(currentAddress < lastAddress) {

int currentIndex = (int) (currentAddress - startAddress);

putByte(currentAddress, bytes[currentIndex]);

currentAddress++;

}

}

/** @see #getByte(long) */

public static short getShort(long address) {

short result = 0;

try {

Method method = unsafeClass().getDeclaredMethod("getShort", long.class);

result = (short) method.invoke(unsafeInstance(), address);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/** @see #putByte(long, byte) */

public static void putShort(long address, short x) {

try {

Method method = unsafeClass().getDeclaredMethod("putShort", long.class, short.class);

method.invoke(unsafeInstance(), address, x);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

/** @see #getByte(long) */

public static char getChar(long address) {

char result = 0;

try {

Method method = unsafeClass().getDeclaredMethod("getChar", long.class);

result = (char) method.invoke(unsafeInstance(), address);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/** @see #putByte(long, byte) */

public static void putChar(long address, char x) {

try {

Method method = unsafeClass().getDeclaredMethod("putChar", long.class, char.class);

method.invoke(unsafeInstance(), address, x);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

/** @see #getByte(long) */

public static int getInt(long address) {

int result = 0;

try {

Method method = unsafeClass().getDeclaredMethod("getInt", long.class);

result = (int) method.invoke(unsafeInstance(), address);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/** @see #putByte(long, byte) */

public static void putInt(long address, int x) {

try {

Method method = unsafeClass().getDeclaredMethod("putInt", long.class, int.class);

method.invoke(unsafeInstance(), address, x);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

/** @see #getByte(long) */

public static long getLong(long address) {

long result = 0;

try {

Method method = unsafeClass().getDeclaredMethod("getLong", long.class);

result = (long) method.invoke(unsafeInstance(), address);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/** @see #putByte(long, byte) */

public static void putLong(long address, long x) {

try {

Method method = unsafeClass().getDeclaredMethod("putLong", long.class, long.class);

method.invoke(unsafeInstance(), address, x);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

/** @see #getByte(long) */

public static float getFloat(long address) {

float result = 0;

try {

Method method = unsafeClass().getDeclaredMethod("getFloat", long.class);

result = (float) method.invoke(unsafeInstance(), address);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/** @see #putByte(long, byte) */

public static void putFloat(long address, float x) {

try {

Method method = unsafeClass().getDeclaredMethod("putFloat", long.class, float.class);

method.invoke(unsafeInstance(), address, x);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

/** @see #getByte(long) */

public static double getDouble(long address) {

double result = 0;

try {

Method method = unsafeClass().getDeclaredMethod("getDouble", long.class);

result = (double) method.invoke(unsafeInstance(), address);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/** @see #putByte(long, byte) */

public static void putDouble(long address, double x) {

try {

Method method = unsafeClass().getDeclaredMethod("putDouble", long.class, double.class);

method.invoke(unsafeInstance(), address, x);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

/** ==============================================*/

/** ====================对象操作====================*/

/** ==============================================*/

/**

* Allocates an instance but does not run any constructor.

* Initializes the class if it has not yet been.

*/

public static T allocateInstance(Class klass) {

T result = null;

try {

Method allocateInstanceMethod = unsafeClass().getDeclaredMethod("allocateInstance", Class.class);

result = (T) allocateInstanceMethod.invoke(unsafeInstance(), klass);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

}

return result;

}

/** @see #getInt(Object, long) */

public static byte getByte(Object o, long offset) {

byte result = 0;

try {

Method method = unsafeClass().getDeclaredMethod("getByte", Object.class, long.class);

result = (byte) method.invoke(unsafeInstance(), o, offset);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/** @see #putInt(Object, long, int) */

public static void putByte(Object o, long offset, byte x) {

try {

Method method = unsafeClass().getDeclaredMethod("putByte", Object.class, long.class, byte.class);

method.invoke(unsafeInstance(), o, offset, x);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

/**

* Fetches a value from a given Java variable.

* More specifically, fetches a field or array element within the given

* object {@code o} at the given offset, or (if {@code o} is null)

* from the memory address whose numerical value is the given offset.

*

* The results are undefined unless one of the following cases is true:

*

*

The offset was obtained from {@link #objectFieldOffset} on

* the {@link java.lang.reflect.Field} of some Java field and the object

* referred to by {@code o} is of a class compatible with that

* field's class.

*

*

The offset and object reference {@code o} (either null or

* non-null) were both obtained via {@link #staticFieldOffset}

* and {@link #staticFieldBase} (respectively) from the

* reflective {@link Field} representation of some Java field.

*

*

The object referred to by {@code o} is an array, and the offset

* is an integer of the form {@code B+N*S}, where {@code N} is

* a valid index into the array, and {@code B} and {@code S} are

* the values obtained by {@link #arrayBaseOffset} and {@link

* #arrayIndexScale} (respectively) from the array's class. The value

* referred to is the {@code N}th element of the array.

*

*

*

* If one of the above cases is true, the call references a specific Java

* variable (field or array element). However, the results are undefined

* if that variable is not in fact of the type returned by this method.

*

* This method refers to a variable by means of two parameters, and so

* it provides (in effect) a double-register addressing mode

* for Java variables. When the object reference is null, this method

* uses its offset as an absolute address. This is similar in operation

* to methods such as {@link #getInt(long)}, which provide (in effect) a

* single-register addressing mode for non-Java variables.

* However, because Java variables may have a different layout in memory

* from non-Java variables, programmers should not assume that these

* two addressing modes are ever equivalent. Also, programmers should

* remember that offsets from the double-register addressing mode cannot

* be portably confused with longs used in the single-register addressing

* mode.

*

* @param o Java heap object in which the variable resides, if any, else

* null

* @param offset indication of where the variable resides in a Java heap

* object, if any, else a memory address locating the variable

* statically

* @return the value fetched from the indicated Java variable

* @throws RuntimeException No defined exceptions are thrown, not even

* {@link NullPointerException}

*/

public static int getInt(Object o, long offset) {

int result = 0;

try {

Method method = unsafeClass().getDeclaredMethod("getInt", Object.class, long.class);

result = (int) method.invoke(unsafeInstance(), o, offset);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/**

* Stores a value into a given Java variable.

*

* The first two parameters are interpreted exactly as with

* {@link #getInt(Object, long)} to refer to a specific

* Java variable (field or array element). The given value

* is stored into that variable.

*

* The variable must be of the same type as the method

* parameter {@code x}.

*

* @param o Java heap object in which the variable resides, if any, else

* null

* @param offset indication of where the variable resides in a Java heap

* object, if any, else a memory address locating the variable

* statically

* @param x the value to store into the indicated Java variable

* @throws RuntimeException No defined exceptions are thrown, not even

* {@link NullPointerException}

*/

public static void putInt(Object o, long offset, int x) {

try {

Method method = unsafeClass().getDeclaredMethod("putInt", Object.class, long.class, int.class);

method.invoke(unsafeInstance(), o, offset, x);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

/**

* Fetches a reference value from a given Java variable.

* @see #getInt(Object, long)

*/

public static Object getObject(Object o, long offset) {

Object result = null;

try {

Method method = unsafeClass().getDeclaredMethod("getObject", Object.class, long.class);

result = method.invoke(unsafeInstance(), o, offset);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/**

* Stores a reference value into a given Java variable.

*

* Unless the reference {@code x} being stored is either null

* or matches the field type, the results are undefined.

* If the reference {@code o} is non-null, card marks or

* other store barriers for that object (if the VM requires them)

* are updated.

* @see #putInt(Object, long, int)

*/

public static void putObject(Object o, long offset, Object x) {

try {

Method method = unsafeClass().getDeclaredMethod("putObject", Object.class, long.class, Object.class);

method.invoke(unsafeInstance(), o, offset, x);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

/** @see #getInt(Object, long) */

public static boolean getBoolean(Object o, long offset) {

boolean result = false;

try {

Method method = unsafeClass().getDeclaredMethod("getBoolean", Object.class, long.class);

result = (boolean) method.invoke(unsafeInstance(), o, offset);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/** @see #putInt(Object, long, int) */

public static void putBoolean(Object o, long offset, boolean x) {

try {

Method method = unsafeClass().getDeclaredMethod("putBoolean", Object.class, long.class, boolean.class);

method.invoke(unsafeInstance(), o, offset, x);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

/** @see #getInt(Object, long) */

public static short getShort(Object o, long offset) {

short result = 0;

try {

Method method = unsafeClass().getDeclaredMethod("getShort", Object.class, long.class);

result = (short) method.invoke(unsafeInstance(), o, offset);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/** @see #putInt(Object, long, int) */

public static void putShort(Object o, long offset, short x) {

try {

Method method = unsafeClass().getDeclaredMethod("putShort", Object.class, long.class, short.class);

method.invoke(unsafeInstance(), o, offset, x);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

/** @see #getInt(Object, long) */

public static char getChar(Object o, long offset) {

char result = 0;

try {

Method method = unsafeClass().getDeclaredMethod("getChar", Object.class, long.class);

result = (char) method.invoke(unsafeInstance(), o, offset);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/** @see #putInt(Object, long, int) */

public static void putChar(Object o, long offset, char x) {

try {

Method method = unsafeClass().getDeclaredMethod("putChar", Object.class, long.class, char.class);

method.invoke(unsafeInstance(), o, offset, x);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

/** @see #getInt(Object, long) */

public static long getLong(Object o, long offset) {

long result = 0;

try {

Method method = unsafeClass().getDeclaredMethod("getLong", Object.class, long.class);

result = (long) method.invoke(unsafeInstance(), o, offset);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/** @see #putInt(Object, long, int) */

public static void putLong(Object o, long offset, long x) {

try {

Method method = unsafeClass().getDeclaredMethod("putLong", Object.class, long.class, long.class);

method.invoke(unsafeInstance(), o, offset, x);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

/** @see #getInt(Object, long) */

public static float getFloat(Object o, long offset) {

float result = 0f;

try {

Method method = unsafeClass().getDeclaredMethod("getFloat", Object.class, long.class);

result = (float) method.invoke(unsafeInstance(), o, offset);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/** @see #putInt(Object, long, int) */

public static void putFloat(Object o, long offset, float x) {

try {

Method method = unsafeClass().getDeclaredMethod("putFloat", Object.class, long.class, float.class);

method.invoke(unsafeInstance(), o, offset, x);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

/** @see #getInt(Object, long) */

public static double getDouble(Object o, long offset) {

double result = 0;

try {

Method method = unsafeClass().getDeclaredMethod("getDouble", Object.class, long.class);

result = (double) method.invoke(unsafeInstance(), o, offset);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/** @see #putInt(Object, long, int) */

public static void putDouble(Object o, long offset, double x) {

try {

Method method = unsafeClass().getDeclaredMethod("putDouble", Object.class, long.class, double.class);

method.invoke(unsafeInstance(), o, offset, x);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

/** ==============================================*/

/** ================偏移量操作======================*/

/** ==============================================*/

/**

* Reports the location of a given field in the storage allocation of its

* class. Do not expect to perform any sort of arithmetic on this offset;

* it is just a cookie which is passed to the unsafe heap memory accessors.

*

*

Any given field will always have the same offset and base, and no

* two distinct fields of the same class will ever have the same offset

* and base.

*

*

As of 1.4.1, offsets for fields are represented as long values,

* although the Sun JVM does not use the most significant 32 bits.

* However, JVM implementations which store static fields at absolute

* addresses can use long offsets and null base pointers to express

* the field locations in a form usable by {@link #getInt(Object,long)}.

* Therefore, code which will be ported to such JVMs on 64-bit platforms

* must preserve all bits of static field offsets.

* @see #getInt(Object, long)

*/

public static long objectFieldOffset(Field field) {

long result = 0;

try {

Method method = unsafeClass().getDeclaredMethod("objectFieldOffset", Field.class);

result = (long) method.invoke(unsafeInstance(), field);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/**

* Reports the location of a given static field, in conjunction with {@link

* #staticFieldBase}.

*

Do not expect to perform any sort of arithmetic on this offset;

* it is just a cookie which is passed to the unsafe heap memory accessors.

*

*

Any given field will always have the same offset, and no two distinct

* fields of the same class will ever have the same offset.

*

*

As of 1.4.1, offsets for fields are represented as long values,

* although the Sun JVM does not use the most significant 32 bits.

* It is hard to imagine a JVM technology which needs more than

* a few bits to encode an offset within a non-array object,

* However, for consistency with other methods in this class,

* this method reports its result as a long value.

* @see #getInt(Object, long)

*/

public static long staticFieldOffset(Field field) {

long result = 0;

try {

Method method = unsafeClass().getDeclaredMethod("staticFieldOffset", Field.class);

result = (long) method.invoke(unsafeInstance(), field);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/**

* Reports the location of a given static field, in conjunction with {@link

* #staticFieldOffset}.

*

Fetch the base "Object", if any, with which static fields of the

* given class can be accessed via methods like {@link #getInt(Object,

* long)}. This value may be null. This value may refer to an object

* which is a "cookie", not guaranteed to be a real Object, and it should

* not be used in any way except as argument to the get and put routines in

* this class.

*/

public static Object staticFieldBase(Field field) {

Object result = false;

try {

Method method = unsafeClass().getDeclaredMethod("staticFieldBase", Field.class);

result = method.invoke(unsafeInstance(), field);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/**

* Reports the offset of the first element in the storage allocation of a

* given array class. If {@link #arrayIndexScale} returns a non-zero value

* for the same class, you may use that scale factor, together with this

* base offset, to form new offsets to access elements of arrays of the

* given class.

*

* @see #getInt(Object, long)

* @see #putInt(Object, long, int)

*/

public static int arrayBaseOffset(Class> arrayClass) {

int result = 0;

try {

Method method = unsafeClass().getDeclaredMethod("arrayBaseOffset", Class.class);

result = (int) method.invoke(unsafeInstance(), arrayClass);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/**

* Reports the scale factor for addressing elements in the storage

* allocation of a given array class. However, arrays of "narrow" types

* will generally not work properly with accessors like {@link

* #getByte(Object, long)}, so the scale factor for such classes is reported

* as zero.

*

* @see #arrayBaseOffset

* @see #getInt(Object, long)

* @see #putInt(Object, long, int)

*/

public static int arrayIndexScale(Class> arrayClass) {

int result = 0;

try {

Method method = unsafeClass().getDeclaredMethod("arrayIndexScale", Class.class);

result = (int) method.invoke(unsafeInstance(), arrayClass);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/** ==============================================*/

/** ==================CAS操作======================*/

/** ==============================================*/

/**

* Atomically updates Java variable to {@code x} if it is currently

* holding {@code expected}.

*

*

This operation has memory semantics of a {@code volatile} read

* and write. Corresponds to C11 atomic_compare_exchange_strong.

*

* @return {@code true} if successful

*/

public static boolean compareAndSwapObject(Object o, long offset, Object expected, Object x) {

boolean result = false;

try {

Method method = unsafeClass().getDeclaredMethod("compareAndSwapObject", Object.class, long.class, Object.class, Object.class);

result = (boolean) method.invoke(unsafeInstance(), o, offset, expected, x);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/**

* Atomically updates Java variable to {@code x} if it is currently

* holding {@code expected}.

*

*

This operation has memory semantics of a {@code volatile} read

* and write. Corresponds to C11 atomic_compare_exchange_strong.

*

* @return {@code true} if successful

*/

public static boolean compareAndSwapInt(Object o, long offset, int expected, int x) {

boolean result = false;

try {

Method method = unsafeClass().getDeclaredMethod("compareAndSwapInt", Object.class, long.class, int.class, int.class);

result = (boolean) method.invoke(unsafeInstance(), o, offset, expected, x);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/**

* Atomically updates Java variable to {@code x} if it is currently

* holding {@code expected}.

*

*

This operation has memory semantics of a {@code volatile} read

* and write. Corresponds to C11 atomic_compare_exchange_strong.

*

* @return {@code true} if successful

*/

public static boolean compareAndSwapLong(Object o, long offset, long expected, long x) {

boolean result = false;

try {

Method method = unsafeClass().getDeclaredMethod("compareAndSwapLong", Object.class, long.class, long.class, long.class);

result = (boolean) method.invoke(unsafeInstance(), o, offset, expected, x);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

return result;

}

/**

* Unblocks the given thread blocked on {@code park}, or, if it is

* not blocked, causes the subsequent call to {@code park} not to

* block. Note: this operation is "unsafe" solely because the

* caller must somehow ensure that the thread has not been

* destroyed. Nothing special is usually required to ensure this

* when called from Java (in which there will ordinarily be a live

* reference to the thread) but this is not nearly-automatically

* so when calling from native code.

*

* @param thread the thread to unpark.

*/

public void unpark(Object thread) {

try {

Method method = unsafeClass().getDeclaredMethod("park", Object.class);

method.invoke(unsafeInstance(), thread);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

/**

* Blocks current thread, returning when a balancing

* {@code unpark} occurs, or a balancing {@code unpark} has

* already occurred, or the thread is interrupted, or, if not

* absolute and time is not zero, the given time nanoseconds have

* elapsed, or if absolute, the given deadline in milliseconds

* since Epoch has passed, or spuriously (i.e., returning for no

* "reason"). Note: This operation is in the Unsafe class only

* because {@code unpark} is, so it would be strange to place it

* elsewhere.

*/

public void park(boolean isAbsolute, long time) {

try {

Method method = unsafeClass().getDeclaredMethod("park", boolean.class, long.class);

method.invoke(unsafeInstance(), isAbsolute, time);

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

private static void init() {

try {

unsafeClass = Class.forName("sun.misc.Unsafe");

Field theUnsafeField = unsafeClass.getDeclaredField("theUnsafe");

boolean orignialAccessible = theUnsafeField.isAccessible();

theUnsafeField.setAccessible(true);

unsafeInstance = theUnsafeField.get(null);

theUnsafeField.setAccessible(orignialAccessible);

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (NoSuchFieldException e) {

e.printStackTrace();

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

}

private static Object unsafeInstance() {

if(unsafeInstance == null) init();

return unsafeInstance;

}

private static Class unsafeClass() {

if(unsafeClass == null) init();

return unsafeClass;

}

}

References:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值