Java Language
sun.misc.Unsafe
Buscar..
Observaciones
La clase Unsafe
permite que un programa haga cosas que no están permitidas por el compilador de Java. Los programas normales deben evitar el uso Unsafe
.
ADVERTENCIAS
Si comete un error al utilizar las API no
Unsafe
, es probable que sus aplicaciones causen que la JVM se bloquee y / o muestre síntomas que son difíciles de diagnosticar.La API
Unsafe
está sujeta a cambios sin previo aviso. Si lo usa en su código, es posible que deba volver a escribir el código al cambiar las versiones de Java.
Instalar sun.misc.Unsafe a través de la reflexión
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
tiene un constructor privado, y el getUnsafe()
estático getUnsafe()
con una comprobación del cargador de clases para garantizar que el código se haya cargado con el cargador de clases principal. Por lo tanto, un método para cargar la instancia es usar la reflexión para obtener el campo estático.
Creación de una instancia de sun.misc.Unsafe a través de bootclasspath
public class UnsafeLoader {
public static Unsafe loadUnsafe() {
return Unsafe.getUnsafe();
}
}
Si bien este ejemplo se compilará, es probable que falle en tiempo de ejecución a menos que la clase Insegura se haya cargado con el cargador de clases primario. Para asegurarse de que esto suceda, la JVM debe cargarse con los argumentos apropiados, como:
java -Xbootclasspath:$JAVA_HOME/jre/lib/rt.jar:./UnsafeLoader.jar foo.bar.MyApp
La clase foo.bar.MyApp
puede usar UnsafeLoader.loadUnsafe()
.
Obtención de instancia de inseguro
Inseguro se almacena como un campo privado al que no se puede acceder directamente. El constructor es privado y el único método para acceder a public static Unsafe getUnsafe()
tiene acceso privilegiado. Mediante el uso de la reflexión, hay una solución alternativa para que los campos privados sean accesibles:
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;
}
Usos de inseguros
Algunos usos de inseguros son los siguientes:
Utilizar | API |
---|---|
Asignación, reasignación y desasignación fuera de almacenamiento / memoria directa | allocateMemory(bytes) , reallocateMemory(address, bytes) y freeMemory(address) |
Vallas de memoria | loadFence() , storeFence() , fullFence() |
Hilo de corriente de estacionamiento | park(isAbsolute, time) , unpark(thread) |
Campo directo y / o acceso a memoria. | get* y put* familia de métodos. |
Lanzar excepciones sin marcar | throwException(e) |
CAS y operaciones atómicas | Familia de métodos compareAndSwap* |
Configuración de la memoria | setMemory |
Operaciones volátiles o concurrentes. | get*Volatile , put*Volatile , putOrdered* |
La familia de métodos get y put son relativos a un objeto dado. Si el objeto es nulo, se trata como una dirección absoluta.
// 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);
Algunos métodos solo se definen para int y longs. Puedes usar estos métodos en flotantes y dobles usando floatToRawIntBits
, intBitsToFloat,
doubleToRawLongBits ,
longBitsToDouble`