수색…


비고

Unsafe 클래스는 프로그램이 Java 컴파일러에서 허용하지 않는 작업을 수행 할 수있게합니다. 일반 프로그램은 Unsafe 사용을 피해야합니다.

경고

  1. Unsafe API를 사용하여 실수를하면 응용 프로그램에서 JVM이 충돌하거나 진단하기 어려운 증상을 나타낼 수 있습니다.

  2. Unsafe API는 사전 통보없이 변경 될 수 있습니다. 코드에서 사용하는 경우 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 에는 Private 생성자가 있으며 정적 getUnsafe() 메서드는 클래스 로더를 검사하여 코드가 기본 클래스 로더와 함께로드되었는지 확인합니다. 따라서 인스턴스를로드하는 한 가지 방법은 리플렉션을 사용하여 정적 필드를 가져 오는 것입니다.

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 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 및 long에 대해서만 정의됩니다. floatToRawIntBits , intBitsToFloat, doubleToRawLongBits , longBitsToDouble`을 사용하여 float 및 double에서이 메서드를 사용할 수 있습니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow