Java Language
sun.misc.Unsafe
サーチ…
備考
Unsafeクラスは、プログラムがJavaコンパイラで許可されていない処理を行うことを許可します。通常のプログラムでは、 Unsafeを使わないでください。
警告
UnsafeAPIを使用して間違えた場合、アプリケーションはJVMをクラッシュさせたり、診断しにくい症状を呈したりする可能性があります。UnsafeAPIは予告なしに変更されることがあります。コードで使用する場合は、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()メソッドは、コードがプライマリクラスローダでロードされていることを確認するためにクラスローダのチェックで保護されています。したがって、インスタンスを読み込む1つの方法は、反射を使用して静的フィールドを取得することです。
bootclasspath経由でsun.misc.Unsafeをインスタンス化する
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()使用できます。
不安全のインスタンスを取得する
安全でないのは、直接アクセスできないプライベートフィールドとして格納されます。コンストラクタはprivateであり、 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* |
メソッドのgetおよびputファミリは、指定されたオブジェクトに関連しています。オブジェクトが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`を