Java Language
sun.misc.Unsafe
Ricerca…
Osservazioni
La classe Unsafe
consente a un programma di eseguire operazioni che non sono consentite dal compilatore Java. I programmi normali dovrebbero evitare l'uso di Unsafe
.
AVVERTENZE
Se commetti un errore utilizzando le API non
Unsafe
, le tue applicazioni potrebbero causare l'arresto anomalo della JVM e / o mostrare sintomi difficili da diagnosticare.L'API
Unsafe
è soggetta a modifiche senza preavviso. Se lo si utilizza nel codice, potrebbe essere necessario riscrivere il codice quando si cambiano le versioni di Java.
Instantiating sun.misc.Unsafe tramite riflessione
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
ha un costruttore privato e il metodo statico getUnsafe()
è protetto con un controllo del classloader per garantire che il codice sia stato caricato con il programma di caricamento di classe primario. Pertanto, un metodo per caricare l'istanza è utilizzare la riflessione per ottenere il campo statico.
Istanziazione di sun.misc.Unsafe tramite bootclasspath
public class UnsafeLoader {
public static Unsafe loadUnsafe() {
return Unsafe.getUnsafe();
}
}
Mentre questo esempio verrà compilato, è probabile che fallisca in fase di esecuzione a meno che la classe Unsafe non sia stata caricata con il classloader primario. Per garantire che ciò accada, la JVM dovrebbe essere caricata con gli argomenti appropriati, come:
java -Xbootclasspath:$JAVA_HOME/jre/lib/rt.jar:./UnsafeLoader.jar foo.bar.MyApp
La classe foo.bar.MyApp
può quindi utilizzare UnsafeLoader.loadUnsafe()
.
Ottenere istanza di non sicuro
Unsafe è memorizzato come campo privato a cui non è possibile accedere direttamente. Il costruttore è privato e l'unico metodo per accedere al public static Unsafe getUnsafe()
ha accesso privilegiato. Con l'uso della riflessione, c'è un work-around per rendere accessibili i campi privati:
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;
}
Usi di non sicuro
Alcuni usi non sicuri sono i seguenti:
Uso | API |
---|---|
Off heap / allocazione diretta della memoria, riallocazione e deallocazione | allocateMemory(bytes) , reallocateMemory(address, bytes) e freeMemory(address) |
Recinti di memoria | loadFence() , storeFence() , fullFence() |
Filo di corrente di parcheggio | park(isAbsolute, time) , unpark(thread) |
Campo diretto e / o accesso alla memoria | get* e put* famiglia di metodi |
Lancio di eccezioni non controllate | throwException(e) |
CAS e operazioni atomiche | compareAndSwap* famiglia di metodi |
Impostazione della memoria | setMemory |
Operazioni volatili o concorrenti | get*Volatile , put*Volatile , putOrdered* |
La famiglia di metodi get e put è relativa a un determinato oggetto. Se l'oggetto è nullo, viene trattato come un indirizzo assoluto.
// 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);
Alcuni metodi sono definiti solo per int e long. Puoi usare questi metodi su float e doubles usando floatToRawIntBits
, intBitsToFloat,
doubleToRawLongBits ,
longBitsToDouble`