Java Language
sun.misc.Unsafe
Szukaj…
Uwagi
Klasa Unsafe
umożliwia programowi wykonywanie czynności, które nie są dozwolone przez kompilator Java. Normalne programy powinny unikać korzystania z Unsafe
.
OSTRZEŻENIA
Jeśli popełnisz błąd przy użyciu
Unsafe
interfejsów API, Twoje aplikacje mogą spowodować awarię JVM i / lub objawy trudne do zdiagnozowania.Unsafe
interfejs API może ulec zmianie bez powiadomienia. Jeśli użyjesz go w kodzie, może być konieczne przepisanie kodu podczas zmiany wersji Java.
Tworzenie instancji sun.misc.Unsafe przez odbicie
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
ma konstruktora prywatnego, a statyczna getUnsafe()
jest chroniona przez sprawdzenie modułu ładującego klasy, aby upewnić się, że kod został załadowany za pomocą głównego modułu ładującego klasy. Dlatego jedną z metod ładowania instancji jest użycie odbicia w celu uzyskania pola statycznego.
Tworzenie instancji sun.misc.Unsafe przez bootclasspath
public class UnsafeLoader {
public static Unsafe loadUnsafe() {
return Unsafe.getUnsafe();
}
}
Chociaż ten przykład się skompiluje, prawdopodobnie zakończy się niepowodzeniem w czasie wykonywania, chyba że klasa niebezpieczna została załadowana za pomocą podstawowego modułu ładującego klasy. Aby mieć pewność, że tak się stanie, do maszyny JVM należy załadować odpowiednie argumenty, takie jak:
java -Xbootclasspath:$JAVA_HOME/jre/lib/rt.jar:./UnsafeLoader.jar foo.bar.MyApp
Klasa foo.bar.MyApp
może następnie użyć UnsafeLoader.loadUnsafe()
.
Uzyskiwanie wystąpienia niebezpiecznego
Niebezpieczne są przechowywane jako prywatne pola, do których nie można uzyskać bezpośredniego dostępu. Konstruktor jest prywatny i jedyną metodą dostępu do public static Unsafe getUnsafe()
ma uprzywilejowany dostęp. Dzięki zastosowaniu refleksji można obejść problem, aby udostępnić pola prywatne:
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;
}
Zastosowania niebezpieczne
Niektóre zastosowania niebezpieczne są następujące:
Posługiwać się | API |
---|---|
Przydział pamięci / bezpośrednie przydzielanie, realokacja i dezalokacja | allocateMemory(bytes) , reallocateMemory(address, bytes) i freeMemory(address) |
Ogrodzenia pamięci | loadFence() , storeFence() , fullFence() |
Prąd bieżący parkowania | park(isAbsolute, time) , unpark(thread) |
Bezpośredni dostęp do pola i / lub pamięci | get* i put* rodzinę metod |
Zgłaszanie niezaznaczonych wyjątków | throwException(e) |
CAS i operacje atomowe | rodzina metod compareAndSwap* |
Określanie pamięci | setMemory |
Lotne lub równoległe operacje | get*Volatile , put*Volatile , putOrdered* |
Rodzina metod get i put odnosi się do danego obiektu. Jeśli obiekt ma wartość NULL, to jest traktowany jako adres bezwzględny.
// 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);
Niektóre metody są zdefiniowane tylko dla int i longs. Tych metod można używać na floatToRawIntBits
intBitsToFloat,
i podwójnych za pomocą floatToRawIntBits
, intBitsToFloat,
doubleToRawLongBits ,
longBitsToDouble`