Unsafe learning

Unsafe

Unfase provides us with access to the underlying mechanism, which is only used by the java core class library.

Therefore, ordinary user programs cannot directly obtain their instances, and the unsafe construction method is private, but we can obtain them through reflection.

1. Get unsafe

Unsafe has a getUnsafe () method to get an instance:

 @CallerSensitive
    public static Unsafe getUnsafe() {
        Class var0 = Reflection.getCallerClass();
        if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
            throw new SecurityException("Unsafe");
        } else {
            return theUnsafe;
        }
    }

It returns thUnsafe, private static final Unsafe theUnsafe;so we can get this instance by reflection:

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Unsafe unsafe = getUnsafe();
        System.out.println(unsafe);
    }

    /**
     * 获取Unsafe实例
     * @return
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static Unsafe getUnsafe() throws NoSuchFieldException,IllegalAccessException {
        Field field = Unsafe.class.getDeclaredField("theUnsafe");
        field.setAccessible(true);
        return (Unsafe)field.get(null);
    }

2. Unsafe create object

public class UnSafeDemo {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        //2.创建对象
        newInstance();
    }


    public static void newInstance() throws NoSuchFieldException, IllegalAccessException, InstantiationException {
        Unsafe unsafe = getUnsafe();
        Book book = (Book) unsafe.allocateInstance(Book.class);
        System.out.println(book.getName()+"\t"+book.getPrice());
    }
}
class Book {
    private String name;
    private Integer price;

    public Book() {
        name="三国演义";
        price=77;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getPrice() {
        return price;
    }

    public void setPrice(Integer price) {
        this.price = price;
    }
}

The print result is null null because:

The allocateInstance method is used to create an instance of a class, but the constructor of this instance is not called. If the class has not been initialized, then initialize the class.

3. Direct memory operation

// 分配内存(堆外)
public native long allocateMemory(long var1);
// 重新分配内存
public native long reallocateMemory(long var1, long var3);
// 内存初始化
public native void setMemory(long var1, long var3, byte var5);
// 内存复制
public native void copyMemory(Object var1, long var2, Object var4, long var5, long var7);
// 清除内存
public native void freeMemory(long var1);

We can call a allocateMemorymethod to allocate local memory outside the heap for the process, but because this part of the memory is not under the jurisdiction of the JVM, we need a freeMemorymethod to recycle

4. CAS operation

A lot of CAS operations are used in JUC. CAS operations are the basis of the juc package. Unsafe provides int, long and CAS, namely Compare and Swap, which is a lock-free algorithm. If it is a lock, it is an optimistic lock. It will only be updated when the data is manipulated. , Is more efficient than pessimistic lock processing.

Parameter 1: The object to be modified

Parameter 2: Offset

Parameter 3: Expected value oldValue

Parameter 4: The updated value newValue

public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);

public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);

5. Exception thrown

ThrowException using Unsafe does not need to be thrown on the method:

unsafe.throwException(new IllegalArgumentException());

6. Thread related

public native void unpark(Object var1);

public native void park(boolean var1, long var2);

public native void monitorEnter(Object var1);

public native void monitorExit(Object var1);

public native boolean tryMonitorEnter(Object var1);

Park and unpark are used in LockSupport:

 public static void park(Object blocker) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        UNSAFE.park(false, 0L);
        setBlocker(t, null);
    }

When the thread needs to block, call the park () method. When the thread needs to continue running, call the unpark () method
monitorEnter: to
lock the object, which must monitorExitbe unlocked by the method. Reentrant.
Added synchronizedcode segment key generated bytecode files will be more monitorenterand monitorexittwo instructions

7. putXXX 和getXXX

Take int as an example:

  • getInt

    • The first parameter: read the object
    • The second parameter: memory offset address
  • putInt

    • The first parameter: modify the object
    • The second parameter: memory offset address
    • The third parameter: the new value to be modified
public native int getInt(Object var1, long var2);

public native void putInt(Object var1, long var2, int var4);
 public static void getAndPut() throws InstantiationException, NoSuchFieldException {
        Unsafe unsafe = getUnsafe();
        Book book =new Book();
        Field field = book.getClass().getDeclaredField("name");
        unsafe.putObject(book,unsafe.objectFieldOffset(field),"新三国演义");
        System.out.println(book.getName());//新三国演义
    }

unsafe.objectFieldOffset (field): Get the memory offset address of the corresponding field

8. volatile related

getXXXVolatile : Read the value of the object with memory offset address var2 in the form of volatile.

putXXXVolatile : modify the value of the object with memory offset address var2 in the form of volatile

Since volatile is used, it means that the operation guarantees order and visibility.

public native Object getObjectVolatile(Object var1, long var2);

public native void putObjectVolatile(Object var1, long var2, Object var4);

9.order related

 public native void putOrderedObject(Object var1, long var2, Object var4);

    public native void putOrderedInt(Object var1, long var2, int var4);

    public native void putOrderedLong(Object var1, long var2, long var4);

Ensure orderly writing and modification. Only order is guaranteed. Therefore, visibility and atomicity are not guaranteed.

Published 75 original articles · won praise 13 · views 8369

Guess you like

Origin blog.csdn.net/weixin_43696529/article/details/105060172