Source code analysis of jdk1.8 AtomicInteger and AtomicStampedReference

AtomicInteger

AtomicInteger can ensure correct increase and decrease in multithreaded environment
The bottom layer is implemented by cas, volatile and unsafe

Important attribute

// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;

static {
    try {
    	// Get the offset of the specified attribute through unsafe
        valueOffset = unsafe.objectFieldOffset
            (AtomicInteger.class.getDeclaredField("value"));
    } catch (Exception ex) { throw new Error(ex); }
}
// Declaring value as volatile guarantees visibility, but not atomicity
// That is to say, if a thread successfully modifies the value of variable modified by volatile, it will invalidate the copy of the variable in the working memory of other threads, so that other threads will read the latest value from memory when reading the variable value again
// If we do not use the volatile decoration, then one thread modifies the value of the variable, only the value in the working memory, not the value in the main memory, so other variables read the old value in the working memory
private volatile int value;

Constructor

Constructor is very simple, that is, simple assignment

public AtomicInteger(int initialValue) {
    value = initialValue;
}

Modify operation

public final int addAndGet(int delta) {
	// this represents the address of the current atomicinter, and valuesofffset represents the offset of the value attribute
	// Update with cas
    return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
}
public final int getAndAddInt(Object var1, long var2, int var4) {
 int var5;
 do {
     var5 = this.getIntVolatile(var1, var2);
 } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

 return var5;
}

AtomicStampedReference

AtomicStampedReference is mainly used to solve ABA problems
The so-called ABA problem refers to that when thread A performs cas operation, it first reads the variable value as 0, and then runs out of time slices. Thread B successfully changes the variable from 0 to 1 through cas, and then changes the variable from 1 to 0 through cas. Thread B runs out of time slices, and thread A obtains time slices. At this time, it reads the variable value as 0 again, so thread A judges that the variable has not changed, that is, it has not changed The thread operates on the variable, and then thread A modifies the value of the variable
The solution is to use another version number. When determining whether a variable is modified, we need to determine not only whether the value of the variable has changed, but also whether the version number has changed. Only if both of them have not changed, can our task variables not be changed by other threads

attribute

The most important attribute at the bottom of AtomicStampedReference is a Pair class object

private static class Pair<T> {
	// Referenced objects
    final T reference;
    // Version number
    final int stamp;
    private Pair(T reference, int stamp) {
        this.reference = reference;
        this.stamp = stamp;
    }
    static <T> Pair<T> of(T reference, int stamp) {
        return new Pair<T>(reference, stamp);
    }
}
private volatile Pair<V> pair;

modify

public boolean compareAndSet(V   expectedReference,
                                 V   newReference,
                                 int expectedStamp,
                                 int newStamp) {
    Pair<V> current = pair;
    // The current reference is the same as the expected reference, and the version number is the same
    // No other thread to modify variables
    // Next try set
   	// If the new reference is the same as the existing reference and the new version number is the same as the existing version number, then there is no need to set again
   	// If not, try to use cas to modify the variable value in memory
    return
        expectedReference == current.reference &&
        expectedStamp == current.stamp &&
        ((newReference == current.reference &&
          newStamp == current.stamp) ||
         casPair(current, Pair.of(newReference, newStamp)));
}
```java
 private boolean casPair(Pair<V> cmp, Pair<V> val) {
    return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
}

Keywords: Attribute Java

Added by anoopd on Wed, 04 Dec 2019 19:22:20 +0200