Unsafe is the cornerstone of Java lock-free operation, and they are indispensable in lock-free concurrency classes. For example, ConcurrentHashMap and ConcurrentLinkedQueue are all implemented by the Unsafe class. Compared with locks in Java, it has basically no overhead and will wait in place. This article mainly introduces the main operations in Unsafe.
1 compareAndSwap
/*** Compare the value in the memory location at the offset of obj and the expected value, and update if the same. This update is not interruptible. * * @param obj Object that needs to be updated* @param offset The offset of the integer field in obj* @param expect The value that is expected in the field* @param update If the expected value expect is the same as the current value of the field, set the value of filed to this new value* @return If the value of field is changed, return true*/public native boolean compareAndSwapInt(Object obj, long offset, int expect, int update);
This is the famous CAS operation, which is divided into three steps
The CAS family also includes compareAndSwapObject(), compareAndSwapLong(), compareAndSwapInt(), etc.
Use a classic example from AtomicInteger to illustrate:
public final int getAndAdd(int delta) { return unsafe.getAndAddInt(this, valueOffset, delta);}//unsafe.getAndAddIntpublic final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { /**get the original value*/ var5 = this.getIntVolatile(var1, var2); /**Confirm that the original value has not been modified by other threads, then perform the update var5+var4 operation*/ } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5;}2 putOrder
/*** * Sets the value of the integer field at the specified offset in the * supplied object to the given value. This is an ordered or lazy * version of <code>putIntVolatile(Object,long,int)</code>, which * doesn't guarantee the immediate visibility of the change to other * threads. It is only really useful where the integer field is * <code>volatile</code>, and is thus expected to change unexpectedly. * * @param obj the object containing the field to modify. * @param offset the offset of the integer field within <code>obj</code>. * @param value the new value of the field. * @see #putIntVolatile(Object,long,int) */ public native void putOrderedInt(Object obj, long offset, int value);
Modify the position where the offset of the obj object is offset to value, because there is no memory operation in Java, and this operation of Unsafe just supplements the insufficient memory operation. It can also be used for array operations, such as ConcurrentHashMap for a large number of use
Segment<K,V> s0 = new Segment<K,V>(loadFactor, (int)(cap * loadFactor), (HashEntry<K,V>[])new HashEntry[cap]); Segment<K,V>[] ss = (Segment<K,V>[])new Segment[ssize]; // Write s0 to the position where the array is subscripted to 0: ss[0]=s0 UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0]
It should be noted that obj needs to be set to Volatile, otherwise it will be invisible to other threads.
3 putXxxVolatile
/*** * Sets the value of the integer field at the specified offset in the * supplied object to the given value, with volatile store semantics. * * @param obj the object containing the field to modify. * @param offset the offset of the integer field within <code>obj</code>. * @param value the new value of the field. */ public native void putIntVolatile(Object obj, long offset, int value);
It feels the same as putOrderInt, because it must be set to Volatile, otherwise what's the use?
The above is all the knowledge points I shared with you this time. Thank you for your support to Wulin.com.