Atomic package usage guide in Java

Reprint: http://ifeve.com/java-atomic/
Java has provided the java.util.concurrent.atomic package since JDK1.5, which is convenient for programmers to perform atomic operations without locks in a multi-threaded environment. The bottom layer of atomic variables uses the atomic instructions provided by the processor,
However, different CPU architectures may provide different atomic instructions, and may also require some form of internal lock, so this method cannot absolutely guarantee that the thread will not be blocked.

Atomic package introduction
There are a total of 12 classes in the Atomic package, and four atomic update methods, namely atomic update basic type, atomic update array, atomic update reference and atomic update field. The classes in the Atomic package are basically wrapper classes implemented using Unsafe.

Atomic update base type class

For updating primitive types atomically, the Atomic package provides the following three classes:

AtomicBoolean: Atomic update boolean type.
AtomicInteger: Atomic update integer.
AtomicLong: Atomic update long.
Common methods of AtomicInteger are as follows:

int addAndGet(int delta) : Atomically adds the input value to the value in the instance (value in AtomicInteger) and returns the result
boolean compareAndSet(int expect, int update) : Atomically sets the value of the input to the value of the input if it is equal to the expected value.
int getAndIncrement(): Atomically increments the current value by 1. Note: The value returned here is the value before the auto-increment.
void lazySet(int newValue): It will eventually be set to newValue. After using lazySet to set the value, other threads may still be able to read the old value for a short period of time.
For more information about this method, please refer to the article "How does AtomicLong.lazySet work?" 
int getAndSet(int newValue): Atomically sets the value of newValue and returns the old value.
The AtomicInteger example code is as follows:


import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntegerTest {

    static AtomicInteger ai = new AtomicInteger(1);
    public static void main(String[] args) {
        System.out.println(ai.getAndIncrement());
        System.out.println(ai.get());
    }
}
output

1
2
dessert

The Atomic package provides atomic updates for three basic types, but Java's basic types also include char, float, and double. So the question is, how to atomically update other basic types?
The classes in the Atomic package are basically implemented using Unsafe. Let's take a look at the source code of Unsafe and find that Unsafe only provides three CAS methods, compareAndSwapObject, compareAndSwapInt and compareAndSwapLong,
Looking at the AtomicBoolean source code, I found that it first converts the Boolean to an integer, and then uses compareAndSwapInt for CAS, so the atomic update double can also be implemented with a similar idea.

Atomic update array class
By atomically updating an element in an array, the Atomic package provides the following three classes:

AtomicIntegerArray: Atomic updates elements in an integer array.
AtomicLongArray: Atomic updates elements in an array of long integers.
AtomicReferenceArray: Atomic updates elements in an array of reference types.
The AtomicIntegerArray class mainly provides an atomic way to update the integers in the array. Its common methods are as follows

int addAndGet(int i, int delta): Atomically adds the input value to the element at index i in the array.
boolean compareAndSet(int i, int expect, int update): Atomically sets the element at array position i to the update value if the current value is equal to the expected value.
The example code is as follows:


public class AtomicIntegerArrayTest {
    static int[] value = new int[] { 1, 2 };
    static AtomicIntegerArray ai = new AtomicIntegerArray(value);
    public static void main(String[] args) {
        ai.getAndSet(0, 3);
        System.out.println(ai.get(0));
        System.out.println(value[0]);
    }
}
output

3
1
The AtomicIntegerArray class should note that the array value is passed in through the constructor, and then AtomicIntegerArray will copy the current array, so when AtomicIntegerArray modifies the internal array elements, it will not affect the incoming array.

Atomic update reference type
Atomic Integer of basic type can be updated atomically, only one variable can be updated. If you want to update multiple variables atomically, you need to use this atom to update the class provided by the reference type. The Atomic package provides the following three classes:

AtomicReference: Atomic update reference type.
AtomicReferenceFieldUpdater: Atomic updates fields in reference types.
AtomicMarkableReference: Atomic update of a reference type with marker bits. It is possible to atomically update flag bits and reference types of a boolean type. The constructor is AtomicMarkableReference(V initialRef, boolean initialMark)
The example code for using AtomicReference is as follows:


public class AtomicReferenceTest {

    public static AtomicReference<user> atomicUserRef = new AtomicReference</user><user>();
    public static void main(String[] args) {
        User user = new User("conan", 15);
        atomicUserRef.set(user);
        User updateUser = new User("Shinichi", 17);
        atomicUserRef.compareAndSet(user, updateUser);
        System.out.println(atomicUserRef.get().getName());
        System.out.println(atomicUserRef.get().getOld());

    }
    static class User {
        private String name;
        private int old;
        public User(String name, int old) {
            this.name = name;
            this.old = old;
        }

        public String getName() {
            return name;
        }
        public int getOld() {
            return old;
        }
    }
}
output

Shinichi
17
Atomic update field class
If we only need a field in a class, then we need to use the atomic update field class. The Atomic package provides the following three classes:

AtomicIntegerFieldUpdater: Atomic updater for fields that update integers.
AtomicLongFieldUpdater: An updater that atomically updates long fields.
AtomicStampedReference: Atomic updates a reference type with a version number. This class associates integer values ​​with references, which can be used for atomic update data and data version numbers, and can solve the ABA problem that may occur when using CAS for atomic updates.
Atomic update field classes are abstract classes, and each time they are used, an updater must be created using the static method newUpdater. Atomically updating fields of a class must use the public volatile modifier. The example code of AtomicIntegerFieldUpdater is as follows:


public class AtomicIntegerFieldUpdaterTest {
    private static AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater.newUpdater(User.class, "old");

    public static void main(String[] args) {
    User conan = new User("conan", 10);
    System.out.println(a.getAndIncrement(conan));
    System.out.println(a.get(conan));
    }

    public static class User {
        private String name;
        public volatile int old;
        public User(String name, int old) {
            this.name = name;
            this.old = old;
        }
        public String getName() {
	     return name;
        }
        public int getOld() {
            return old;
        }
    }
}
output

10
11

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326225516&siteId=291194637