Unsafe-java class magic atomic operation -AtomicInteger

Unsafe-java magic class

Unsafe Introduction

Unsafe source: http: //www.docjar.com/html/api/sun/misc/Unsafe.java.html

Unsafe class fully qualified name is sun.misc.Unsafe, as the name suggests is not safe.

In general, the preparation of the underlying JVM code or impact is difficult to achieve, of course, you can use JNI to achieve their goals, needs and C JNI deal.

In java platform through sun.misc.Unsafethe API, the underlying code may be performed, such as the address of the operation target object, directly modify the value of the address attribute field where use of this type of course ... more dangerous, so caution.

Unsafe widely used in the atomic class, by compareAndSwapXXcalling the underlying operating system which atomic instructions method to atomic operation.

Gets Unsafe object

Unsafe consider before you create an object, first look at the source code for this class:

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

Unsafe class has such features:

  1. final modified
  2. There is also the example of a static variable of type UnsafetheUnsafe
  3. Constructor private
  4. Static method getUnsafe () can get an Unsafe instance object theUnsafe, but check out the class loader (JVM only boot loader will be allowed, otherwise it throws SecurityExceptionan exception)
  5. Examples of the static code block variable theUnsafe

Unsafe then we want to create an instance of an object, how to do it?

Targeted solutions for the above characteristics. The following are two options.

Class added to the boot class loader BoostrapClassloader

We can use static methods Unsafe class getUnsafe (), but this method checks whether the class loader BoostrapClassloader.

So we can be appended to the current class path where the scan path BoostrapClassloader down.

Extended thing here: to get the path BoostrapClassloader loaded:

String property = System.getProperty("sun.boot.class.path");
for (String s : property.split(";")) {
    System.out.println(s);
}

Output:

C:\Program Files\Java\jdk1.8.0_211\jre\lib\resources.jar
C:\Program Files\Java\jdk1.8.0_211\jre\lib\rt.jar
C:\Program Files\Java\jdk1.8.0_211\jre\lib\sunrsasign.jar
C:\Program Files\Java\jdk1.8.0_211\jre\lib\jsse.jar
C:\Program Files\Java\jdk1.8.0_211\jre\lib\jce.jar
C:\Program Files\Java\jdk1.8.0_211\jre\lib\charsets.jar
C:\Program Files\Java\jdk1.8.0_211\jre\lib\jfr.jar
C:\Program Files\Java\jdk1.8.0_211\jre\classes

Extension: Extend path obtained class loader to load:

String property2 = System.getProperty("java.ext.dirs");
for (String s : property2.split(";")) {
    System.out.println(s);
}

Output:

C:\Program Files\Java\jdk1.8.0_211\jre\lib\ext
C:\Windows\Sun\Java\lib\ext

Xbootclasspath extension

Java command line provides a simple way of how to extend BoostrapClassloader.

  • -Xbootclasspath: 新的jar Jdk fully replace the Java class search path is not recommended;
  • -Xbootclasspath/a:追加的jar Java class added later in the search path jdk very practical (s jar separated by colons in unix, windows semicolon separated);
  • -Xbootclasspath/p:放在前面的jar Put in front of the search path jdk java class is not recommended; avoid unnecessary conflict.

So we can set jvm runtime parameters in the IDEA (add VM options):

-Xbootclasspath/a:D:\framework\concurrent\target\concurrent-1.0-SNAPSHOT.jar 

To run again. Note that you want to pack into a jar, to append

/*
运行时添加 VM options
-Xbootclasspath/a:D:\framework\concurrent\target\concurrent-1.0-SNAPSHOT.jar
*/
Unsafe unsafe0 = Unsafe.getUnsafe();
System.out.println("-Xbootclasspath/a:添加jar包:" + unsafe0);  // 可以获得Unsafe实例对象

Here Insert Picture Description

In this way too hard ... so we use the following second way.

Unsafe reflection Field Gets instance of an object [Recommended usage]

Unsafe features from the point of view, we know, there is one instance of a theUnsafe its internal variable is Unsafe:

private static final Unsafe theUnsafe;

Since the configuration is not used, we obtain the value of using direct reflection of the field:

// 所以,选择反射获取
// 因为内部存在一个单例实例:Unsafe theUnsafe;
Class clazz = Unsafe.class;
Field field = clazz.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe)field.get(null);   // 得到其内部的字段theUnsafe

Unsafe 的 API

Unsafe provides a number of API (more than 100 methods) to operate the bottom.

Divided into such categories:

Info access to information

The return of some of the underlying memory information.

  • addressSize: local pointer size, typically 4 or 8 value; storing the information determined by their content in the original block of this type.
  • pageSize: Returns the memory page size, in bytes, a value of 2 ^ n
// info
System.out.println(unsafe.pageSize());  // 4096
System.out.println(unsafe.addressSize());  // 8

Objects operation object

Providing an object and a method of its operation fields.

  • allocateInstance: assign an instance of an object, but does not call any of the constructor (not initialized variable value)

    • public native Object allocateInstance(Class cls) 
      

Example, is very interesting:

@Data
public class UnsafeDemo {
    private String name = "zs";
    private int age = 18;
}

// 运行以下代码的结果:
UnsafeDemo unsafeDemo3 = (UnsafeDemo)unsafe.allocateInstance(UnsafeDemo.class);
System.out.println(unsafeDemo3);  // UnsafeDemo(name=null, age=0)
UnsafeDemo unsafeDemo1 = new UnsafeDemo();
System.out.println(unsafeDemo1);   // UnsafeDemo(name=zs, age=18)
  • objectFieldOffset: obtaining a field of a class in memory offset

    • public native long objectFieldOffset(Field f);
      

Example: class obtained UnsafeDemo age field offset in memory

long ageOffset =
                unsafe.objectFieldOffset(UnsafeDemo.class.getDeclaredField("age"));
System.out.println(ageOffset); // 12

Classes operation class object

Provide operating class object, the method of the static field.

  • staticFieldOffset: obtaining a static field offset

    • public native long staticFieldOffset(Field f);
      

Example:

@Data
public class UnsafeDemo {
    private String name = "zs";
    private int age = 18;
    private static int status = 1;
}

// staticFieldOffset:获得静态字段的偏移量
Field status = UnsafeDemo.class.getDeclaredField("status");
long statusOffset = unsafe.staticFieldOffset(status);
System.out.println(statusOffset);  // 104
  • defineClass: inform JVM definition of a class, but do not do security checks; By default, the class loader and protection domain from Class caller.

    • public native Class defineClass(String name, byte[] b, int off, int len,
      									ClassLoader loader,
      									ProtectionDomain protectionDomain);
      
  • defineAnonymousClass: not perceived definition of a class loader, class system.

    • /**
      * @params hostClass 链接的上下文,访问控制,类加载器
      * @params data      字节码文件的字节数组形式
      * @params cpPatches 如果存在非空数据,则替换data中的
        829        */
      */
      public native Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches);
      
  • ensureClassInitialized: ensure that a given class has been initialized, which usually requires a combination of static field of class libraries get.

    • public native void ensureClassInitialized(Class c);
      

Arrays Array Operation

Encapsulation of the array.

  • arrayBaseOffset: offset of the first element of the array of objects

    • public native int arrayBaseOffset(Class arrayClass)
      

Example:

int arrayBaseOffset =
                unsafe.arrayBaseOffset(new byte[]{1, 2, 3}.getClass());
System.out.println(arrayBaseOffset); // 16
  • arrayIndexScale: Addressing factor

    • public native int arrayIndexScale(Class arrayClass);
      

Synchronization operations sync word

Some of the synchronization operation of the bottom package.

  • monitorEnter: lock an object must monitorExitrelease the lock.

    • public native void monitorEnter(Object o);
      
  • tryMonitorEnter: try to get a lock

    • public native boolean tryMonitorEnter(Object o);
      
  • monitorExit: release the lock

    • public native void monitorExit(Object o);
      
  • compareAndSwapInt : CAS is a very practical method, AtomicInteger, AtomicBoolean atoms atoms such classes are implemented by operation of Unsafe CAP method.

    • /**
      原子操作:修改java变量的值为x;
      如果对象o的偏移量offset(其实就是该对象的某个字段)表示的变量的值,目前是期望值expected,则将其修改为x,返回true;
      如果目前是期望值不是expected,则不操作,返回false。
      */
      public final native boolean compareAndSwapInt(Object o, long offset,
                                                  int expected,
                                                  int x);
      

Example AtomicInteger # incrementAndGet logic implementation of the method:

java.util.concurrent.atomic.AtomicInteger#incrementAndGet

public final int incrementAndGet() {
    return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}

sun.misc.Unsafe#getAndAddInt

public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5;
    do {
        var5 = this.getIntVolatile(var1, var2);
        // 自旋+CAS
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

    return var5;
}
  • putIntVolatile: putIntThe Volatile version

    • public native void    putIntVolatile(Object o, long offset, int x);
      
  • putOrderedInt: putIntVolatileordered \ inert version

    • public native void    putOrderedInt(Object o, long offset, int x);
      

Memory Operation Memory

Direct memory access method.

  • allocateMemory: allocate memory space, and returns the offset

    • public native long allocateMemory(long bytes);
      
  • copyMemory: copy memory

    • // @since 1.7
      public native void copyMemory(Object srcBase, long srcOffset,
          Object destBase, long destOffset,
          long bytes);
      
      public void copyMemory(long srcAddress, long destAddress, long bytes) {
      	copyMemory(null, srcAddress, null, destAddress, bytes);
      }
      
  • freeMemory: free up memory space

    • public native void freeMemory(long address);
      
  • getAddress: get the memory address of an unsigned long integer

    • public native long getAddress(long address);
      
  • getInt: obtaining values ​​of the variables specified offset

    • public native int getInt(Object o, long offset);
      
  • putInt : you can modify the value of a variable

    • /**
      参数一:对象
      参数二:字段偏移量
      参数三:要设置的值
      */
      public native void putInt(Object o, long offset, int x);
      

Example:

//通过魔法类修改对象实例的属性值
UnsafeDemo unsafeDemo = new UnsafeDemo();
long ageOffset =
                unsafe.objectFieldOffset(UnsafeDemo.class.getDeclaredField("age"));
unsafe.putInt(unsafeDemo, ageOffset, 30);  // 将字段age的值改为30

Unsafe implement CAS

Case: AtomicInteger of atomic operations

Example AtomicInteger # incrementAndGet logic implementation of the method:

java.util.concurrent.atomic.AtomicInteger#incrementAndGet

public final int incrementAndGet() {
    return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}

sun.misc.Unsafe#getAndAddInt

public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5;
    do {
        var5 = this.getIntVolatile(var1, var2);
        // 自旋+CAS
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

    return var5;
}

Here are some of the common share of API, Unsafe there are many other similar methods, are not enumerated.

Published 260 original articles · won praise 301 · Views 1.29 million +

Guess you like

Origin blog.csdn.net/zixiao217/article/details/105086109