preface

Atomic classes inherit from Number interface, vest in Java. The util. Concurrent. The atomic package, The main purpose of the atomic class is to solve the problem that synchronized consumes too much resources to handle atomic operations. The CAS implementation of the atomic class is based on the Unsafe implementation.

A brief description of the atomic class

1.1 Application Scenarios of Atoms

Atomic classes are suitable for utility classes that are equivalent to volatile and CAS when atomic operations are needed to reduce resource consumption.

1.2 Types of atomic classes

Base types: Update base types atomically

  • AtomicInteger: Shaping the atom class
  • AtomicLong: long integer atomic class
  • AtomicBoolean: Boolean atomic class

Array type: Atomically updates an element of an array

  • AtomicIntegerArray: An integer array atomic class
  • AtomicLongArray: Long integer array atomic class
  • AtomicReferenceArray: Reference type array atom class

Reference types

  • AtomicReference: Indicates the atomic class of the reference type
  • AtomicStampedRerence: Field atomic class in an atomic update reference type
  • AtomicMarkableReference: atomic updates with mark a reference type

Object property modification type

  • AtomicIntegerFieldUpdater: atomic updates plastic field updater
  • AtomicLongFieldUpdater: AtomicLongFieldUpdater is an updater for atomically updating long shaping fields
  • AtomicStampedReference: AtomicStampedReference updates a reference type with a version number.
    • This class associates an integer value with a reference
    • Update data that can be used to resolve atoms and the version number of the data
    • Can resolve ABA problems that may occur when atomic updates are performed using CAS.

1.3. Common methods of the AtomicInteger class

  • public final int get(): Gets the current value Java
  • public final int getAndSet(int newValue) : Gets the current value and sets the new value
  • public final int getAndIncrement(): Gets the current value and increments it
  • public final int getAndDecrement(): Gets the current value and decrement it
  • public final int getAndAdd(int delta): Gets the current value and adds the expected value
  • boolean compareAndSet(int expect, int update): Atomically sets the value to the input value if it is equal to the expected value (update)
  • public final void lazySet(int newValue): is finally set to newValue, and using lazySet may cause other threads to read the old value for a short period of time.
  • public final int incrementAndGet(): Atomically adds 1 to the current value and gets a new value
  • public final int decrementAndGet(): Atomically subtracts 1 from the current value and gets a new value
  • public final int addAndGet(int delta): Atomically adds delta to the current value and gets a new value
  • public final boolean compareAndSet(int expect, int update): CAS comparison method

The principle of the atomic class

2.1 Principle

Atomic operations are operations that cannot be interrupted by thread scheduling; Once started, this operation runs until the end without any contextswitch to another thread, and is called an atomic variable because it contains methods that implement the combined operation atomically

Review CAS: The idea behind CAS is to compare an expected value to an original value and update it to a new value if the value is the same

Atomic class mainly through CAS (compare and swap) + volatile and native methods to ensure atomic operation!

// Example: AtomicInteger

// Its main internal members are:
private volatile intvalue; Notice that it is declared withvolatileThis is required to ensure memory visibility.// Most of its update methods are implemented similarly. Let's look at a method incrementAndGet with the code:
public final int incrementAndGet(a) {
    for (;;) {
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next))
            returnnext; }}/ / key points:
1.value is onevolatileVariables are visible in memory, so the JVM can guarantee that any thread at any time will always have the latest value for that variable2The objectFieldOffset() method of the.unsafe class is a local method. This method is used to retrieve the memory address of the "original value" and return valueOffsetCopy the code
  1. Get the current value “current” and calculate the expected value “next”
  2. The CAS method is then called to update and return the new value if the current value has not changed, otherwise the loop continues until the update is successful

2.2 AtomicInteger In-depth principles

Taking a look at the source code that we had previously overlooked, this class can represent most of the basic types


// Node 1: Atomic class supports serialization
implements java.io.Serializable

----------------------> 

// Node 2: the CAS object is Unsafe. Unsafe was mentioned earlier, and there are many Native faults
 private static final Unsafe unsafe = Unsafe.getUnsafe();

----------------------> 

// Node 3: offset valueOffset
private static final long valueOffset;
static {
    try {
        valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
    } catch (Exception ex) { throw newError(ex); }}// objectFieldOffset() : obtain the offset of a field relative to the "start address" of the Java object
GetDeclaredField () : returns a field object that reflects the specified declared field of the class or interface represented by this class object

----------------------> 

// Node 4: indicates the core Value
private volatile int value;

----------------------> 

// Node 5: Operation method. You can see that valueOffset is in effect
 public final int incrementAndGet(a) {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1; } -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- >// Node 6: value conversion. AtomicInteger provides the following four inherent conversion methods
public int intValue(a) ;
public long longValue(a) ;
public float floatValue(a);
public double doubleValue(a);

Copy the code

2.3 AtomicReference in-depth

Now what’s special about an AtomicReference


// Node 1: no longer inherits the Number interface

// Node 2: Uses generic methods
public class AtomicReference<V> implements java.io.Serializable
private volatile V value;

// Node 3: use putOrderedObject for comparison
return unsafe.compareAndSwapObject(this, valueOffset, expect, update);

Copy the code

2.4 AtomicIntegerArray in-depth

AtomicIntegerArray has more variations than that, and everything else is pretty much the same


// Node 1: the array element offset is recorded, not the "value" offset
private static final int base = unsafe.arrayBaseOffset(int[].class);
private static final int shift;
private final int[] array;

// Node 2: comparison uses getAndSetInt
unsafe.getAndSetInt(array, checkedByteOffset(i), newValue)

Copy the code

Atomic operations

3.1 Common cases of atoms

AtomicInteger integer = new AtomicInteger();

logger.info("------> 1 > Get atomic variable :[{}] <-------", integer.get());

// Step 2: Set parameters
integer.set(999);

logger.info("------> 2 > Get atomic variable :[{}] <-------", integer.get());


logger.info([{}] <-------", integer.compareAndSet(0.998));
logger.info("------> 3 > Get atomic variable :[{}] <-------", integer.get());

logger.info([{}] <-------", integer.compareAndSet(999.998));
logger.info("------> 4 > Get atomic variable :[{}] <-------", integer.get());


// Step 3: Get the current value and set the new value
logger.info([{}] <-------", integer.getAndSet(888));
logger.info("------> 5 > Get atomic variable :[{}] <-------", integer.get());


// Step 4: Get the current value and set the new value
logger.info([{}] <-------", integer.getAndIncrement());
logger.info("------> 6 > Get atomic variable :[{}] <-------", integer.get());

// Atomically add 1 to the current value and get the new value
logger.info([{}] <-------", integer.incrementAndGet());
logger.info("------> 6-1 > Get atomic variable :[{}] <-------", integer.get());

// Step 5: Get the current value and set the new value
logger.info([{}] <-------", integer.getAndDecrement());
logger.info("------> 7 > Get atomic variable :[{}] <-------", integer.get());

// Atomically subtract 1 from the current value and get the new value
logger.info([{}] <-------", integer.decrementAndGet());
logger.info("------> 7 > Get atomic variable :[{}] <-------", integer.get());

// Step 6: Get the current value and set the new value
logger.info([{}] <-------", integer.getAndAdd(99));
logger.info("------> 8 > Get atomic variable :[{}] <-------", integer.get());

// Atomically add delta to the current value and get the new value
logger.info([{}] <-------", integer.addAndGet(99));
logger.info("------> 8 > Get atomic variable :[{}] <-------", integer.get());
}

Copy the code

3.2 Atomic test multithreading

 /** * Test multithreading */
    public void testThead(a) throws Exception {
    
        InnerTO innerTO = new InnerTO();
        MyThread[] threadDSS = new MyThread[1000];

        for (int i = 0; i < 1000; i++) {
            threadDSS[i] = new MyThread(innerTO);
        }
        for (int i = 0; i < 1000; i++) {
            threadDSS[i].start();
        }

        logger.info("------> Atomic thread Start complete :{} <-------", innerTO.getInteger().get());
        for (int i = 0; i < 1000; i++) {
            if (i % 100= =0) {
                Thread.sleep(1);
                logger.info("------> Test the atom class :{} <-------", innerTO.getInteger().get()); }}}/** * contains the atomic class object ** */
    class InnerTO {
        AtomicInteger integer = new AtomicInteger();
        public AtomicInteger getInteger(a) {
            return integer;
        }
        
        public void setInteger(AtomicInteger integer) {
            this.integer = integer; }}/** * Run thread class ** */
    class MyThread extends Thread {

        public InnerTO innerTO = new InnerTO();

        public MyThread(InnerTO innerTO) {
            this.innerTO = innerTO;
        }

        @Override
        public void run(a) {
            int i = innerTO.getInteger().getAndIncrement();
            if (i == 999) {
                logger.info("------> Thread execution completed <-------"); }}}// You can see that in the absence of locks, the data is guaranteed atomicity------> Atomic thread Start complete:876<------- ------> Test the atomic class:918<------- ------> Test the atomic class:950<------- ------> Test the atomic class:973<------- ------> Test the atomic class:989The <------- ------> thread executes the <------- ------> test atomic class:1000<------- ------> Test the atomic class:1000<------- ------> Test the atomic class:1000<------- ------> Test the atomic class:1000<------- ------> Test the atomic class:1000<------- ------> Test the atomic class:1000 <-------    

Copy the code

Welcome to my related documentsMultithreaded set

Reference documentation

[source](HTTP://www.iocoder.cn/JUC/sike/aqs-3/)[Deadknock Series](HTTP://cmsblogs.com/?cat=151)

Copy the code