Java Language
sun.misc.Unsafe
Recherche…
Remarques
La classe Unsafe
permet à un programme de faire des choses qui ne sont pas autorisées par le compilateur Java. Les programmes normaux devraient éviter d'utiliser Unsafe
.
AVERTISSEMENTS
Si vous commettez une erreur en utilisant les API
Unsafe
, vos applications risquent de provoquer le blocage de la JVM et / ou de présenter des symptômes difficiles à diagnostiquer.L'API
Unsafe
est sujet à modification sans préavis. Si vous l'utilisez dans votre code, vous devrez peut-être réécrire le code lors de la modification des versions de Java.
Instanciation de sun.misc.Unsafe via la réflexion
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
possède un constructeur Private et la getUnsafe()
statique getUnsafe()
est protégée par une vérification du chargeur de classe pour garantir que le code a été chargé avec le chargeur de classe principal. Par conséquent, une méthode de chargement de l'instance consiste à utiliser la réflexion pour obtenir le champ statique.
Instanciation de sun.misc.Unsafe via bootclasspath
public class UnsafeLoader {
public static Unsafe loadUnsafe() {
return Unsafe.getUnsafe();
}
}
Bien que cet exemple compile, il est probable qu'il échoue à l'exécution à moins que la classe Unsafe ne soit chargée avec le chargeur de classe principal. Pour que cela se produise, la JVM doit être chargée avec les arguments appropriés, tels que:
java -Xbootclasspath:$JAVA_HOME/jre/lib/rt.jar:./UnsafeLoader.jar foo.bar.MyApp
La classe foo.bar.MyApp
peut alors utiliser UnsafeLoader.loadUnsafe()
.
Obtenir l'instance de Unsafe
Unsafe est stocké dans un champ privé auquel on ne peut pas accéder directement. Le constructeur est privé et la seule méthode pour accéder à public static Unsafe getUnsafe()
a un accès privilégié. En utilisant la réflexion, il existe un moyen de contourner les domaines privés:
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;
}
Utilisations de Unsafe
Voici quelques utilisations de unsafe:
Utilisation | API |
---|---|
Allocation de mémoire / mémoire directe, réaffectation et désallocation | allocateMemory(bytes) , reallocateMemory(address, bytes) et freeMemory(address) |
Clôtures à mémoire | loadFence() , storeFence() , fullFence() |
Fil de stationnement actuel | park(isAbsolute, time) , unpark(thread) |
Accès direct au champ et / ou à la mémoire | get* et put* famille de méthodes |
Lancer des exceptions non vérifiées | throwException(e) |
CAS et opérations atomiques | Famille de méthodes compareAndSwap* |
Mise en mémoire | setMemory |
Opérations volatiles ou simultanées | get*Volatile , put*Volatile , putOrdered* |
La famille de méthodes get et put est relative à un objet donné. Si l'objet est nul, il est traité comme une adresse absolue.
// 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);
Certaines méthodes ne sont définies que pour int et longs. Vous pouvez utiliser ces méthodes sur floats et doubles en utilisant floatToRawIntBits
, intBitsToFloat,
doubleToRawLongBits ,
longBitsToDouble`