introduction
Java provides the java.util.concurrent.atomic package since JDK1.5, which facilitates programmers to perform atomic operations without locks in a multi-threaded environment. The underlying layer of atomic variables uses atomic instructions provided by the processor, but different CPU architectures may provide different atomic instructions, and may also require some form of internal lock, so this method cannot absolutely ensure that the thread is not blocked.
Atomic package introduction
There are 12 classes in the Atomic package, and four atomic update methods are: atomic update basic types, atomic update arrays, atomic update references and atomic update fields. The classes in the Atomic package are basically wrapped classes implemented using Unsafe.
Atomic update basic type class
For updating basic types through atomic methods, the Atomic package provides the following three classes:
AtomicBoolean: Atomic updates the boolean type.
AtomicInteger: Atomic update integer.
AtomicLong: Atomic update long integer.
Common methods of AtomicInteger are as follows:
int addAndGet(int delta): adds the input value to the value in the instance (value in AtomicInteger) in atomic manner and returns the result
boolean compareAndSet(int expect, int update): If the input value is equal to the expected value, set the value to the input value atomically.
int getAndIncrement(): adds the current value to 1 atomically. Note: The returned value here is the value before the autoincrement.
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 int getAndSet(int newValue): It is set to the value of newValue in atomic manner 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
12
After-dinner dessert
The Atomic package provides three basic types of atomic updates, but Java basic types include char, float, and double. So the question is, how to update other basic types of atoms? The classes in the Atomic package are basically implemented using Unsafe. Let's take a look at the source code of Unsafe. We found that Unsafe only provides three CAS methods, compareAndSwapObject, compareAndSwapInt and compareAndSwapLong. Then look at the AtomicBoolean source code. We found that it first converts Boolean into an integer, and then uses compareAndSwapInt for CAS, so atomic update double can also be implemented using similar ideas.
Atomic update array class
The Atomic package provides the following three classes:
AtomicIntegerArray: Atomically updates elements in an integer array.
AtomicLongArray: Atomic updates elements in long arrays.
AtomicReferenceArray: Atomic updates elements in the reference type array.
The AtomicIntegerArray class mainly provides atomic to update the integers in the array. The commonly used methods are as follows
int addAndGet(int i, int delta): adds the input value atomically to the element index i in the array.
boolean compareAndSet(int i, int expect, int update): If the current value is equal to the expected value, the element at the array position i is atomically set to the update 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
31
What you need to note in the AtomicIntegerArray class is that the array value is passed in through the constructor method, and then AtomicIntegerArray will copy the current array a copy, so when AtomicIntegerArray modifys the internal array elements, it will not affect the passed array.
Atomic update reference type
AtomicInteger, which is a basic type, can only update one variable. 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 updates the reference type.
AtomicReferenceFieldUpdater: Atomic updates fields in the reference type.
AtomicMarkableReference: Atomic updates the reference type with marker bits. You can atomically update a Boolean type tag bit and reference type. The construction method is AtomicMarkableReference(V initialRef, boolean initialMark)
The 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
Shinichi17
Atomic update field class
If we only need a certain field in a certain class, we need to use atomic to update the field class. The Atomic package provides the following three classes:
AtomicIntegerFieldUpdater: An updater for fields that atomically update integers.
AtomicLongFieldUpdater: An updater for atomic updates long integer fields.
AtomicStampedReference: Atomic updates the reference type with a version number. This class associates integer values with references and can be used for atomic more data and version numbers, which can solve the ABA problems that may arise when using CAS for atomic updates.
Atomic update field classes are abstract classes, and each time they are used, they must use the static method newUpdater to create an updater. The public volatile modifier must be used for fields of the atomic update class.
The first step is that because the atomic update field classes are abstract classes, each time you use the static method AtomicIntegerFieldUpdater.newUpdater, you must create an updater, and you need to set the classes and properties you want to update. The second step is to update the fields (properties) of the class must use the public volatile modifier (private volatile int old)
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
1011
Summarize
The above is the entire content of this article about the introduction and usage of Java multi-threaded atomic package. I hope it will be helpful to everyone. Interested friends can continue to refer to this site:
Introduction to the method of writing production consumer model under different conditions in Java multithreading
Java multithreaded programming synchronizer Future and FutureTask parsing and code examples
A detailed explanation of Java multi-threaded display lock and built-in lock
If there are any shortcomings, please leave a message to point it out.