This package provides a set of atomic variable classes. The basic feature is that in a multithreaded environment, when there are multiple threads executing the methods contained by instances of these classes at the same time, there is exclusivity, that is, when a thread enters the method and executes the instruction, it is not interrupted by another thread, and the other thread is like a spin lock until the method executes. It is only a logical understanding that the JVM chooses a second thread from the waiting queue to enter. It is actually implemented with hardware-related instructions that do not block threads (or simply block at the hardware level). You can manipulate basic data, basic data in an array, and basic data in a class. The atomic variable class is equivalent to a generalized volatile variable that supports both atomic and conditional read-write operations.
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
The first group of atomicboolean,atomicinteger,atomiclong,atomicreference these four basic types is used to deal with Boolean, Integer, Long Integer, object four kinds of data, its internal implementation is not simple to use synchronized, It is a more efficient way of CAS (compare and swap) + volatile and native methods, which avoids the high overhead of synchronized and greatly improves execution efficiency. The implementation fragments such as Atomicinteger are:
Java Code Collection Code
private static final unsafe Unsafe = unsafe.getunsafe (); private volatile int value; public final int get () { return Value; } public final void set (Int newvalue) { value = newvalue; } public final boolean compareandset (int expect, int update) { return unsafe.compareandswapint (this, valueoffset, expect, update); }
Constructors (two constructors)
default constructor: The initialized data is False,0,0,null
with parameter constructor: Data with parameters initialized
Set () and Get () method: You can set and get atomic data atomically. Similar to volatile, the data is guaranteed to be set or read in main memory
Void set () and void Lazyset (): Set to the given value, modify the original value directly, Lazyset delay sets the value of the variable, which is equivalent to the set () method, However, because the field is volatile, this method can be useful if you do not want to immediately read the new value of the setting, because the modification of this field will have a slight performance delay (albeit negligible) than the normal field (non-volatile field). The
Getandset () method
Atomically Sets the variable to the new data, returning the previous old data
which is essentially a get () operation, and then doing the set () operation. Although these 2 operations are atomic, they are not atomic when they are merged together. At the level of Java's source program, it is not possible to do this without relying on the synchronized mechanism. You can only rely on the native method.
Java Code favorites code
public final int getandset (int NewValue) { for (;;) { int current = get (); if (Compareandset (current, newvalue)) return current; } }
The
Compareandset () and Weakcompareandset () methods
are both methods of conditional modifier. These 2 methods accept 2 parameters, one is the expected data (expected), the other is the new data, and if the data in the atomic is consistent with the expected data, the new data is set to the atomic data, which returns true to indicate success, otherwise it is not set and returns false. The JSR specification reads and conditionally writes a variable without creating any happen-before ordering, and therefore does not provide any guarantees relating to previous or subsequent read or write operations other than the Weakcompareandset target. The main idea is that when calling Weakcompareandset, there is no guarantee that no happen-before will occur (that is, there may be a command reordering that causes this operation to fail). However, from the Java source, in fact, this method does not implement the requirements of the JSR specification, the final effect and compareandset are equivalent, all call the Unsafe.compareandswapint () to complete the operation.
Java Code favorites code
public final boolean compareandset ( Int expect, int update) { return Unsafe.compareandswapint (this, valueoffset, expect, update); } public final boolean weakcompareandset (int expect, int update) { return unsafe.compareandswapint (This, valueoffset, expect, update) ; }
also provides some special methods for Atomicinteger, Atomiclong.
Getandincrement (): atomically increases the current value by 1, which is equivalent to a thread-safe i++ operation.
Incrementandget (): atomically increases the current value by 1, which is equivalent to a thread-safe ++i operation.
Getanddecrement (): atomically minimizes the current value by 1, which is equivalent to a thread-safe i--operation.
Decrementandget (): atomically minimizes the current value by 1, which is equivalent to a thread-safe-I operation.
Addandget (): atomically adds the given value to the current value, which is actually equal to the thread-safe i =i+delta operation.
Getandadd (): atomically adds the given value to the current value, which is equivalent to a thread-safe t=i;i+=delta;return t;
to implement some addition, subtract atomic operations. (Note that the-I, ++i is not an atomic operation, it contains 3 steps: The first step, read I; second step, add 1 or minus 1; step three: Write back memory)
Create a thread-safe stack using atomicreference
Java code favorites code
Package thread; import java.util.concurrent.atomic.atomicreference; public class ConcurrentStack<T> { private Atomicreference<node<t>> stacks = new atomicreference <Node<T>> (); public t push (t e) { Node<T> oldNode, newNode; for (;;) { // The handling here is very special and must be the case. oldNode = Stacks.get (); newnode = new node<t> (E, oldnode); if (Stacks.compareandset(Oldnode, newnode)) { return e; } } } public t pop () { Node<T> oldNode, newNode; for (;;) { oldnode = stacks.get (); newnode = oldNode.next; if (Stacks.compareandset (oldnode, newnode)) &NBSP;{&NBSP;&NBSP;&NBSP;&Nbsp; return oldnode.object; } } } private static final class Node<T> { private T object; private node<t> next; private node (T object, node<t> next) { this.object = object; this.next = next; } } }
Although the scalar class of atoms extends the number class, it does not extend some basic types of wrapper classes, such as Integer or long, and in fact they cannot extend: The wrapper class of the basic type is not modifiable, and the atomic variable class can be modified. The hashcode or Equals method is not redefined in the atomic variable class, and each instance is different, and they should not be used as a key value based on a hash container. The
second group Atomicintegerarray,atomiclongarray and the Atomicreferencearray class further extend the atomic operation, Provides support for these types of arrays. These classes are also noticeable in providing volatile access semantics for their array elements, which is not supported for normal arrays.
They do not internally maintain a valatile variable like Atomicinteger, but are all implemented by the native method, as follows
Atomicintegerarray implementation fragment:
Java code favorite code
private static final unsafe Unsafe = unsafe.getunsafe (); private static final int base = unsafe.arraybaseoffset (Int[].class); private static final int scale = unsafe.arrayindexscale (Int[].class); private final int[] array; Public final int get (int i) { return unsafe.getintvolatile (Array, rawindex (i)); } public final void set (Int i, int newvalue) { unsafe.putintvolatile (Array, rawindex (i), newvalue); }
The third group of Atomiclongfieldupdater,atomicintegerfieldupdater,atomicreferencefieldupdater reflection-based utilities, The specified volatile field of the specified class can be atomically updated. The API is simple, but there are constraints: the
(1) field must be of type volatile (2) the description type of the field (modifier public/protected/default/private) is consistent with the caller's relationship to the operand field. That is, the caller is able to manipulate the object field directly, then the atomic operation can be reflected. However, for a field of the parent class, the subclass cannot be manipulated directly, although the subclass can access the fields of the parent class.
(3) can only be an instance variable, not a class variable, that is, the static keyword cannot be added.
(4) can only be a modifiable variable, not a final variable, because final semantics are not modifiable. There is actually a conflict between final semantics and volatile, and these two keywords cannot exist at the same time.
(5) for Atomicintegerfieldupdater and Atomiclongfieldupdater only fields of type Int/long can be modified, their wrapper type (Integer/long) cannot be modified. If you want to modify the wrapper type, you need to use Atomicreferencefieldupdater. The total number of bytes sent by the class Channeloutboundbuffer in the
netty5.0, which is not satisfied with the volatile variable, is implemented using Atomicintegerfieldupdater. Look at the following code:
Java code favorites code
Definition private static final AtomicLongFieldUpdater< channeloutboundbuffer> total_pending_size_updater = atomiclongfieldupdater.newupdater (ChannelOutboundBuffer.class, "Totalpendingsize"); private volatile long totalpendingsize; //Use long oldValue = totalPendingSize; long newWriteBufferSize = oldValue + size; while (! Total_pending_size_updater.compareandset (this, oldvalue, newwritebuffersize)) { oldvalue = totalpendingsize; newwritebuffersize = oldvalue + size; }
Java.util.concurrent.atomic Atomic Operation Class Pack