Atomic class
Java provides the Java.util.concurrent.atomic package (hereinafter referred to as the atomic package) from JDK 1.5, in this package
Atomic manipulation classes provide a simple, efficient, and thread-safe way to update a variable.
Since there are many types of variables, there are 13 classes available in the atomic package, and 4 types of atoms are more
The new methods are atomic update primitives, Atomic update arrays, atomic update references, and Atomic update properties (fields).
The class in the atomic package is basically a wrapper class implemented using unsafe
The classes in Java.util.concurrent.atomic can be divided into 4 groups:
- Scalar class (scalar): atomicboolean,atomicinteger,atomiclong,atomicreference
- Array class: Atomicintegerarray,atomiclongarray,atomicreferencearray
- Updater class: Atomiclongfieldupdater,atomicintegerfieldupdater,atomicreferencefieldupdater
- Compound Variable class: Atomicmarkablereference,atomicstampedreference
Cas
The CAS (COMPARE-AND-SWAP) algorithm guarantees the atomicity of data operations.
The CAS algorithm is a hardware support for sharing data with concurrent operations.
The CAS consists of three operands:
Memory Value V
Pre-estimate A
Update Value B
When and only if v = = A, V is assigned a value of B, otherwise the loop continues to determine whether V and a are equal.
CAS is all called Compare-and-swap, is a CPU atomic instructions, its role is to let the CPU after the atomic update of the value of a location, after investigation found that the implementation is based on the hardware platform assembly instructions, that is, CAS is hardware implementation, the JVM just encapsulates the assembly call , those Atomicinteger classes are using these encapsulated interfaces.
The atomic package uses this scheme under the atomic package. For example Atomicinteger's getandincrement self-increment +1 method, after viewing the source code as follows:
Public Final intgetandincrement () { for (;;) {intCurrent =get ();intNext = current + 1;if(Compareandset (current, next))returnCurrent ;}} Public Final BooleanCompareandset (intExpectintupdate) {returnUnsafe.compareandswapint ( This, Valueoffset, expect, update);}
The first step of the source for the loop body to obtain the value stored in the Atomicinteger, the second step to the current value of Atomicinteger 1 operation, the key third step calls the Compareandset method to perform atomic update operations, This method first checks whether the current value is equal to present, which means that the value of Atomicinteger is not modified by another thread, then the current value of Atomicinteger is updated to the value of next, if the unequal Compareandset method returns false , the program goes into the for loop to re-compareandset the operation
Unsafe only provides 3 CAs methods: Compareandswapobject, Compare-andswapint, and Compareandswaplong, which are implemented using the native method.
/*** If the current value is expected, the atom updates the Java variable to x*@returnreturns True if the update succeeds*/ Public Final native Booleancompareandswapobject (Object o,Longoffset,object expected,object x); Public Final native BooleanCompareandswapint (Object o,LongOffset,intexpected,intx); Public Final native BooleanCompareandswaplong (Object o,LongOffset,Longexpected,Longx);
The native keyword indicates that its modification is a primitive method, and the corresponding implementation of the method is not in the current file, but in a file implemented in other languages, such as C and C + +. The Java language itself cannot access and manipulate the underlying operating system, but other languages can be invoked through the JNI interface to enable access to the underlying.
JNI is a Java Native interface (Java Native Interface) and is a native programming interface that is part of the Java Software Development Toolkit (Java Software Development kit,sdk). JNI allows Java code to use code and code libraries written in other languages. The invocation API (part of the JNI) can be used to embed a Java Virtual machine (JVM) into a native application, allowing programmers to invoke Java code from within native code.
Scalar class
- Atomicboolean: Atom Update Boolean variable
- Atomicinteger: Atomic Update integer variable
- Atomiclong: Atomic update Long Integer variable
- Atomicreference: Atomic Update Reference type
Specific to each class of source code, the method is basically the same, here to Atomicinteger as an example to illustrate, Atomicinteger source code The main method is as follows, the principle is mainly to use the CAS, here no longer described.
Public classAtomicintegerextendsNumberImplementsjava.io.Serializable { PublicAtomicinteger (intInitialValue) {Value=InitialValue; } //returns the current value Public Final intget () {returnvalue; } //will eventually be set to a new value Public Final voidSetintnewvalue) {Value=NewValue; } Public Final voidLazyset (intnewvalue) {Unsafe.putorderedint ( This, Valueoffset, NewValue); } //Atomic update to new value and return old value Public Final intGetandset (intnewvalue) { for (;;) { intCurrent =get (); if(Compareandset (current, newvalue))returnCurrent ; } } //atomically updates to the new value if the value entered equals the expected value Public Final BooleanCompareandset (intExpectintupdate) { returnUnsafe.compareandswapint ( This, Valueoffset, expect, update); } //Atomic self-increment Public Final intgetandincrement () { for (;;) { intCurrent =get (); intNext = current + 1; if(Compareandset (current, next))returnCurrent ; } }//atomically adds the current value to the input value and returns the result Public Final intGetandadd (intDelta) { for (;;) { intCurrent =get (); intNext = current +Delta; if(Compareandset (current, next))returnCurrent ; } } }
Array class
- Atomicintegerarray: Atom updates An element of an integer array
- Atomiclongarray: Atom updates An element of an array of long integers
- Atomicreferencearray: Atom updates An element of an array of reference types
The Atomicintegerarray class primarily provides an atomic way to update an integral type in an array, which is commonly used in the following ways.
- int addandget (int i,int delta): atomically adds the input value to the element of index i in the array.
- Boolean compareandset (int i,int expect,int update): atomically sets the element of the array position I to the update value if the current value equals the expected value.
The above classes provide almost the same approach, so here's an example of Atomicintegerarray.
Public classAtomicintegerarrayImplementsjava.io.Serializable {Private Static Final LongSerialversionuid = 2862133569453604235L; Private Static Finalunsafe unsafe =Unsafe.getunsafe (); Private Static Final intBase = Unsafe.arraybaseoffset (int[].class); Private Static Final intshift; Private Final int[] array; Private LongCheckedbyteoffset (inti) {if(I < 0 | | I >=array.length)Throw NewIndexoutofboundsexception ("index" +i); returnByteoffset (i); } Private Static LongByteoffset (inti) {return((Long) I << shift) +Base; } PublicAtomicintegerarray (intlength) {Array=New int[length]; } Public Final intGetinti) {returnGetraw (Checkedbyteoffset (i)); } Private intGetraw (Longoffset) { returnunsafe.getintvolatile (array, offset); } Public Final voidSetintIintnewvalue) {unsafe.putintvolatile (array, Checkedbyteoffset (i), newvalue); } Public Final voidLazyset (intIintnewvalue) {unsafe.putorderedint (array, Checkedbyteoffset (i), newvalue); } Public Final intGetandset (intIintnewvalue) { Longoffset =Checkedbyteoffset (i); while(true) { intCurrent =Getraw (offset); if(Compareandsetraw (offset, current, newvalue))returnCurrent ; } } Public Final BooleanCompareandset (intIintExpectintupdate) { returnCompareandsetraw (Checkedbyteoffset (i), expect, update); } Private BooleanCompareandsetraw (LongOffsetintExpectintupdate) { returnunsafe.compareandswapint (array, offset, expect, update); } }
The key implementation here is also the use of CAS strategy, specifically through the unsafe native method to achieve
Atom Update Field Class
If you want to atomically update a field in a class, you need to update the field class with atoms, and the atomic package provides
The following 3 classes are updated with atomic fields.
- Atomicintegerfieldupdater: An update to the field of an atomic update integer.
- Atomiclongfieldupdater: atomically updates the updater of the long field.
- Atomicstampedreference: Atom updates A reference type with a version number. This class associates an integer value with a reference
, the version number of the update data and data that can be used for the atom, which resolves what might occur when using CAs for atomic updates
ABA problem.
It takes two steps to update the field class atomically. The first step, because the Atomic Update field classes are abstract classes, each time you use the
You must create an update using the static method Newupdater (), and you need to set the classes and properties that you want to update. The
Two steps, the field (property) of the update class must use the public volatile modifier
Public classAtomicintegerfieldupdatertest {//Create an Atomic updater and set the properties of the object classes and objects that need to be updatedPrivate StaticAtomicintegerfieldupdater<user> A =Atomicintegerfieldupdater.newupdater (User.class, "old"); Public Static voidMain (string[] args) {//set Conan's age to be 10 years oldUser Conan =NewUser ("Conan", 10);//Conan grew one year old, but still output old age .System.out.println (A.getandincrement (Conan));//output Conan's age nowSystem.out.println (A.get (Conan));} Public Static classUser {PrivateString name; Public volatile intOld ; PublicUser (String name,intOld ) { This. Name =name; This. Old =Old ;} PublicString GetName () {returnname;} Public intGetold () {returnOld ; }}}
After the code executes, the output is as follows.
1011
Reprinted from:
Java concurrent Programming-atomic class and Concurrency tool class
Java Learning Notes-multithreading (Atomic class, Java.util.concurrent.atomic package, reprint)