cool hit counter Principle of Unsafe class in Conccrent and the Atomic class AutomicXX and use of Unsafe class_Intefrankly

Principle of Unsafe class in Conccrent and the Atomic class AutomicXX and use of Unsafe class


Introduction to the Unsafe class

Java is based on the operating system level atomic operations class sun.misc.Unsafe, which is the most basic class in Java for most locking mechanism implementations. Please note that the methods available in the sun.misc.Unsafe class have changed significantly between JDK 1.8 and previous versions of the JDK, and this article is based on JDK 1.8. The sun.misc.Unsafe class provides atomic operations based on operating system operations directly on the CPU, and the following methods are in turn frequently used in the sun.misc.Unsafe class.

java does not have direct access to the OS underlay, but rather through native methods. The Unsafe class provides atomic operations at the hardware level, primarily providing the following functionality.

1, get the Unsafe object instance

The Unsafe class is a singleton, called by the method getUnsafe(), and there is a judgment step in the function that gets the instance that checks if the CallerClass is loaded by the system class loaderBootstrapClassLoader Loading, we know that bootstrapClass is the highest level loader, the bottom level is implemented by C++, there is no parent class loader, all classes loaded by this system class loader call getClassLoader() will return null, so to check if the class is loaded by bootstrap loader just check if the method returns null.

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

The top side gets theUnsafe The object isjava Internally used, owing toJDK The source code places strict restrictions on this class, We can't go through the routinenew way to get an instance of the class, Nor can it passUnsafe.getUnsafe acquireUnsafe Object Example;

So how do we get an instance of that object, and here's where the powerful reflection mechanism comes with a brute force access buff: the

There is a private member variable in the Unsafe classtheUnsafe , so we can set the accessibility of the private singleton instance to true via reflection, and then get it via the get method of Field, as follows.

Field f = Unsafe.class.getDeclaredField("theUnsafe"); // Get the name theUnsafe  particular property  Even for private  equal access
f.setAccessible(true);
 Unsafe unsafe = (Unsafe) f.get(null);   //If static, the get parameter is null.

2. memory can be allocated and memory can be freed through the Unsafe class.

The three local methods allocateMemory, reallocateMemory, and freeMemory provided in the class are used to allocate memory, expand memory, and free memory, respectively, corresponding to the three methods in C: malloc(), realloc(), and free() [directly open memory, free memory, and manipulate processing using pointers]; (a) It is not described here.

public native long allocateMemory(long l);
public native long reallocateMemory(long l, long l1);
public native void freeMemory(long l);

3. the possibility of locating the memory location of a field of an object, and the possibility of modifying the value of a field of an object, even if it is private.

   Positioning of fields.

Offset position of the object's fields in main memory.ObjectFieldOffSet staticFieldOffset

Positioning of fields of objects in JAVA may be achieved through the staticFieldOffset method, which returns the memory address offset of the given field, a value that is unique and fixed for the given filed.

Offset location in main memory of the object's integer or double-precision floating-point type.getIntVolatile, getLong

The getIntVolatile method gets the value of the integer field corresponding to the offset address in the object, and supports the volatile load semantics.

The getLong method gets the value of the long type field corresponding to the offset address in the object

Positioning of array elements of an object.arrayBaseOffset,arrayIndexScale

The Unsafe class has many constants ending in BASE_OFFSET, such as ARRAY_INT_BASE_OFFSET, ARRAY_BYTE_BASE_OFFSET, etc. The values of these constants are obtained by the arrayBaseOffset method. The arrayBaseOffset method is a local method that gets the offset address of the first element of the array. The Unsafe class also has many constants ending in INDEX_SCALE, such as ARRAY_INT_INDEX_SCALE , ARRAY_BYTE_INDEX_SCALE , etc. The values of these constants are obtained by the arrayIndexScale method. The arrayIndexScale method is also a local method that gets the conversion factor of the array, which is the incremental address of the elements in the array. Use arrayBaseOffset in conjunction with arrayIndexScale to locate the position in memory of each element in an array.

public final class Unsafe {
    public static final int ARRAY_INT_BASE_OFFSET;
    public static final int ARRAY_INT_INDEX_SCALE;

    public native long staticFieldOffset(Field field);
    public native int getIntVolatile(Object obj, long l);
    public native long getLong(Object obj, long l);
    public native int arrayBaseOffset(Class class1);
    public native int arrayIndexScale(Class class1);

    static 
    {
        ARRAY_INT_BASE_OFFSET = theUnsafe.arrayBaseOffset([I);
        ARRAY_INT_INDEX_SCALE = theUnsafe.arrayIndexScale([I);
    }
}

4、CAS Operation-Compare And Swap

Unsafe has a similar method, staticFieldOffset(Field), in addition to the method objectFieldOffset(Field). These two methods are used to return the offset set in the main memory for a property in the class definition. Please see the following code.

//  Note that the code in thisunsafe object is the same as the previous code get of

 // Start using the unsafe object to find the memory address offsets of the child and name attributes in the UserPojo object, respectively
 // First is the child property in the UserPojo class, set in memory at the offset position
Field field = UserPojo.class.getDeclaredField("child");
 // This is where the property will be offset in memory once the class is instantiated
long offset = unsafe.objectFieldOffset(field);
System.out.println("child offset = " + offset);

 // Then there is the name property in the UserPojo class, set in memory at the offset
Field fieldName = UserPojo.class.getDeclaredField("name");
long nameOffset = unsafe.objectFieldOffset(fieldName);
System.out.println("name offset = " + nameOffset);

The test results are Print the offset position of the corresponding individual object property in the main memory; the specific results are not posted.

In addition to the method compareAndSwapObject, Unsafe has two similar methods: unsafe.compareAndSwapInt and unsafe.compareAndSwapLong. What these methods do is compare and replace attributes (the proverbial CAS process - Compare And Swap). When the value of the specified property in the given object matches the expectation, the value is replaced with a new value and true is returned; otherwise, the replacement operation is ignored and false is returned.

Unsafe class provides the most important feature besides getting memory offsets - because many features in Java based on the "no-synchronous locking" approach are based on the CAS process.

   Method example: CompareAndSwapInt()

/**
 * Compares the value in the memory location at the offset of obj with the expected value, and updates it if it is the same. This update is non-interruptible.
* 
 * @param obj The object to be updated
 * @param offset offset of integer field in obj
 * @param expect value that you want to be present in the field
 * @param update If the expected value expect is the same as the current value of field, set the value of filed to this new value
 * @return Returns true if the value of the field was changed
*/
public native boolean compareAndSwapInt(Object obj, long offset, int expect, int update);

Specific examples of code applications are.

UserPojo user = new UserPojo();
user.setName("yinwenjie");
user.setSex(11);
user.setUserId("userid");

 // Get the memory address offset of the sex attribute 
Field field = UserPojo.class.getDeclaredField("sex");
long sexOffset = unsafe.objectFieldOffset(field);

/* 
  * Compare and modify values
* 1、The object to be modified
  * 2. the memory offset of the property to be changed
  * 3. Expected value
  * 4. New values set
 * */
 // Why is it an Object and not an int? Because the sex property is of type Integer, not int.
if(unsafe.compareAndSwapObject(user, sexOffset, 11, 13)) {
    System.out.println(" Change successful!");
} else {
    System.out.println(" Failed to change!");
}

First create an instance object of the UserPojo class that has three properties name, sex and userId. Next we find the offset sexOffset set by the sex property in the main memory and perform a CAS operation. Note the four values of the compareAndSwapObject method: the first value indicates the object user to be operated on, the second parameter tells the method which property in the user object is to be compared, via the previously obtained main memory offset sexOffset, the third parameter is the current value of the property as expected by the technician, and the fourth parameter is the new value to be replaced with.

Then apply the method to the above compareAndSwapObject execution: if the current user object has a sex property of 11, replace the value of this sex property with 13 and return true; otherwise do not replace the value of the sex property and return false.

Unsafe.getAndAddInt(Object, long, int) and similar methods

Similar methods are getAndAddLong(Object, long, long), which serve to take advantage of Unsafe's atomic operability by returning the current value of a property to the caller and adding a new value to that property immediately afterwards. In the java.util.concurrent.atomic code package, there is a class AtomicInteger which is used to perform thread-safe counting operations based on atomic operations and this class has been substantially modified in the JDK1.8+ version. The following code example shows a fragment of the implementation in the getAndIncrement() method of this class.

public class AtomicInteger extends Number implements java.io.Serializable {
    ……
    private volatile int value;
    ……
    private static final long valueOffset;
    ……
    //  getvalue Memory offset of the attributevalueOffset
    static {
        try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }
    ……
    /**
     *  this isJDK1.8 Implementation in
     * Atomically increments by one the current value.
     * @return the previous value
     */
    public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }

As you can see by the demonstration of the above code,AtomicInteger class defines avalue properties, and throughunsafe.objectFieldOffset approach get The offset set by this attribute in the main memoryvalueOffset。 Then it's time to add thegetAndIncrement method directly using theunsafe.getAndAddInt approximation, By offsetvalueOffset willvalue attribute plus the value of the“1”。 But the method is implemented in theJDK1.8 In the previous version, The implementation code instead looks like this:

// The code to get the offset valueOffset is similar and will not be shown here
……
public final int getAndIncrement() {
     // keep looping until
    for (;;) 
  {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            return current;
    }
}
……
public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

Here the For loop for atomicinteger operations; later pages will write java spin lock and a specific implementation of spin lock "optimistic lock", will also analyze the "optimistic lock" suitable for use scenarios.

In the above code, the getAndIncrement method will keep looping internally until the unsafe.compareAndSwapInt method executes successfully. However, in most cases, the loop will only be executed once, as the case of multiple threads forcing the same object property does not occur all the time.

What if there are multiple threads accessing the code of this for loop What if the result is guaranteed to be accurate, e.g. 100 threads performing the self-increment operation of atomicinteger.

The following is illustrated by combining a figure.

We see that if three threads come to access this optimistic lock-based code, First the threads3 lead if destination Make a determination at this pointcurrent the value of10, this time alternate threads2 threads3 All stuck inget Where the method get The value of the object property10

At this point if the thread3 The process of making judgments based on expected values reveals current values together with Object propertiesvalue The values are the same for At this point it will be performed CAS operations, The object's value Set the current next happen to that is 11; Then the thread3 End of implementation If at this point

threads2 Obtaining executive authority Continue down the line. At this point the thread1 of current happen to or for 10 next the value of11 arriveif The place to judge this time Because the properties of the objectvalue The value of11 vs. expected value current unequal So no.CAS operations; Then continue with a new round of

for cycle this time continuedget obtain current values be 11 next The value of my 12 this time proceedif The expected value of the test and the object'svalue The values are the same Then perform the update operation; At this time the objectvalue is updated with the value of12 threads2 Implementation complete, Then it's down to the threads 1 The thread is executed with the thread2

is the same as when it was executed, a new for loop is required to achieve the update worth operation.

As you can see from the process above, three threads can complete three update worthy operations and no synchronous locks are added.

Unsafe has a number of other useful atomic manipulation methods in JDK 1.8.

  • PutXXXXX(Object, long, short) Similar methods include: putInt(Object, long, int), putBoolean(Object, long, boolean), putShort(Object, long, short), putChar(Object, long, char), putDouble(Object, long, double), etc. These are all direct settings for the value of the property at the offset in the specified object. These operations occur in the CPU Level 1 (L1) or Level 2 (L2) cache, but these methods do not guarantee that threads working on other cores will "immediately see" the latest property values.
  • putXXXXXVolatile(Object, long, byte) Similar methods include: putByteVolatile(Object, long, byte), putShortVolatile(Object, long, short), putFloatVolatile(Object, long, float), putDoubleVolatile(Object, long, double), etc. While the main purpose of these methods is to change the value of a property in a given object directly against an offset, they ensure that threads working on other cores see the latest property value "immediately" - that is, they satisfy the volatile semantics (more on how volatile works in a subsequent article)

To sum up.

Unsafe class summary has been written, based on the class used in many classes, in addition to AtomicXXX, there is LockSupport class and in the thread pool ThreadPool class is also used in this class, later write these two classes specifically.


Recommended>>
1、Columnar storage format for big data Parquet
2、Chinas heavyduty mining vehicles are also among the L4 autopilot is it a gimmick or a real use
3、Summary DataResearch and AnalysisLatest Report
4、Technology is changing lives so many fun smart devices which one is your favorite
5、Get started with the first lesson gnawing down the blockchain Bible

    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号