Java Language
sun.misc.Unsafe
Поиск…
замечания
Класс Unsafe
позволяет программе выполнять действия, которые не допускаются компилятором Java. Обычным программам следует избегать использования Unsafe
.
ПРЕДУПРЕЖДЕНИЯ
Если вы ошиблись, используя
Unsafe
API, ваши приложения могут привести к сбою и / или выявлению симптомов, которые трудно диагностировать.Unsafe
API может быть изменен без предварительного уведомления. Если вы используете его в своем коде, вам может потребоваться переписать код при изменении версий Java.
Выполнение sun.misc.Unsafe через отражение
public static Unsafe getUnsafe() {
try {
Field unsafe = Unsafe.class.getDeclaredField("theUnsafe");
unsafe.setAccessible(true);
return (Unsafe) unsafe.get(null);
} catch (IllegalAccessException e) {
// Handle
} catch (IllegalArgumentException e) {
// Handle
} catch (NoSuchFieldException e) {
// Handle
} catch (SecurityException e) {
// Handle
}
}
sun.misc.Unsafe
имеет частный конструктор, а статический getUnsafe()
проверкой загрузчика классов, чтобы обеспечить загрузку кода с помощью загрузчика основного класса. Поэтому одним из способов загрузки экземпляра является использование отражения для получения статического поля.
Выполнение sun.misc.Unsafe через bootclasspath
public class UnsafeLoader {
public static Unsafe loadUnsafe() {
return Unsafe.getUnsafe();
}
}
Хотя этот пример будет скомпилирован, он, скорее всего, потерпит неудачу во время выполнения, если класс Unsafe не будет загружен с помощью основного загрузчика классов. Чтобы убедиться, что JVM должен быть загружен с соответствующими аргументами, например:
java -Xbootclasspath:$JAVA_HOME/jre/lib/rt.jar:./UnsafeLoader.jar foo.bar.MyApp
Затем класс foo.bar.MyApp
может использовать UnsafeLoader.loadUnsafe()
.
Получение экземпляра небезопасного
Небезопасно хранится как частное поле, к которому невозможно получить доступ напрямую. Конструктор является закрытым и единственным способом доступа к public static Unsafe getUnsafe()
имеет привилегированный доступ. Используя рефлексию, можно сделать доступными частные поля:
public static final Unsafe UNSAFE;
static {
Unsafe unsafe = null;
try {
final PrivilegedExceptionAction<Unsafe> action = () -> {
final Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
return (Unsafe) f.get(null);
};
unsafe = AccessController.doPrivileged(action);
} catch (final Throwable t) {
throw new RuntimeException("Exception accessing Unsafe", t);
}
UNSAFE = unsafe;
}
Использование небезопасных
Ниже перечислены некоторые виды использования небезопасных:
использование | API |
---|---|
Отключение кучи / прямой памяти, перераспределение и освобождение памяти | allocateMemory(bytes) , reallocateMemory(address, bytes) и freeMemory(address) |
Запонки памяти | loadFence() , storeFence() , fullFence() |
Стоянка тока | park(isAbsolute, time) , unpark(thread) |
Прямой доступ к полю и памяти | get* и put* семейство методов |
Выброс исключенных исключений | throwException(e) |
CAS и атомные операции | compareAndSwap* семейство методов |
Настройка памяти | setMemory |
Неустойчивые или параллельные операции | get*Volatile , put*Volatile , putOrdered* |
Получаемое семейство методов относится к данному объекту. Если объект имеет значение null, он рассматривается как абсолютный адрес.
// Putting a value to a field
protected static long fieldOffset = UNSAFE.objectFieldOffset(getClass().getField("theField"));
UNSAFE.putLong(this, fieldOffset , newValue);
// Puting an absolute value
UNSAFE.putLong(null, address, newValue);
UNSAFE.putLong(address, newValue);
Некоторые методы определены только для int и longs. Вы можете использовать эти методы для поплавков и удвоений, используя floatToRawIntBits
, intBitsToFloat,
doubleToRawLongBits ,
longBitsToDouble`