17.java.util.concurrent.atomic Atomic operation class package

16.Java Multithreading -java.util.concurrent.atomic Interpretation of the package principle

15.JDK1.8 Of Java.util.concurrent.atomic Summary of Bao

14.Java in Atomic Principle and analysis of package

11.java The atomicity of concurrency 、 visibility 、 Orderliness  

=====

17.java.util.concurrent.atomic Atomic operation class package

This package provides a set of atomic variable classes . Its basic characteristic is in multithreading environment , When there are multiple threads executing the methods contained in the instances of these classes at the same time , Be exclusive , That is, when a thread enters a method , When executing the instructions , Will not be interrupted by other threads , And other threads are like spinlocks , Wait until the method execution is complete , Only by JVM Select another thread from the waiting queue to enter , It's just a logical understanding . In fact, it is realized by the related instructions of hardware , Will not block threads ( Or it's just blocking at the hardware level ). It can be used for basic data 、 The basic data in the array 、 Operate on the basic data in the class . An atomic variable class is equivalent to a generalized volatile Variable , Able to support atomic and conditional reading - Change - Write operations .

java.util.concurrent.atomic The classes in can be divided into 4 Group :

  • 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 AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference These four basic types are used to deal with Boolean , Integers , long integer , Object four kinds of data , Its internal implementation is not a simple use synchronized, It's a more efficient way CAS (compare and swap) + volatile and native Method , Thus avoiding synchronized The high cost of , Greatly improved execution efficiency .

Such as AtomicInteger The implementation fragment of is :

  1. private static final Unsafe unsafe = Unsafe.getUnsafe();
  2. private volatile int value;
  3. public final int get() {
  4. return value;
  5. }
  6. public final void set(int newValue) {
  7. value = newValue;
  8. }
  9. public final boolean compareAndSet(int expect, int update) {
  10. return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
  11. }
  • Constructors ( Two constructors )

    • default constructor : The initialization data are false,0,0,null
    • Constructor with parameters : The parameter is the initialized data
  • set( ) and get( ) Method : It can be set and acquired atomically atomic The data of . Be similar to volatile, Make sure the data is set or read in main memory
  • void set() and void lazySet():set Set to the given value , Modify the original value directly ; lazySet Delay setting variable values , This is equivalent to set() Method , But because the field is volatile Type of , Therefore, the modification of secondary field will be better than that of ordinary field ( Not volatile Field ) There's a slight performance delay ( Although it can be ignored ), So if you don't want to read the new value immediately , Allow in “ backstage ” Modified value , So this method is very useful .
  • getAndSet( ) Method
    • Atomic set variables as new data , At the same time, return the previous old data
    • Its essence is get( ) operation , Then I do set( ) operation . Although this 2 All operations are atomic, But when they merge , It's not atomic. stay Java At the source level of , If you don't rely on synchronized To complete this work , It's impossible . Only rely on native The method can .
    1. public final int getAndSet(int newValue) {
    2. for (;;) {
    3. int current = get();
    4. if (compareAndSet(current, newValue))
    5. return current;
    6. }
    7. }
  • compareAndSet( ) and weakCompareAndSet( ) Method
    • this Both methods are conditional modifier Method . this 2 There are two ways to accept 2 Parameters , One is expected data (expected), One is new data (new); If atomic The data in it is the same as the expected data Cause , Set the new data to atomic The data of , return true, Show success ; Otherwise, it will not be set , And back to false.JSR The standard says : Read and conditionally write variables atomically, but No   Create any happen-before Sort , Therefore, it is not provided with  weakCompareAndSet  Any guarantee relating to previous or subsequent read or write operations on any variable other than the target . The main idea is to call weakCompareAndSet There's no guarantee that it doesn't exist happen-  before Happen ( That is, there may be instruction reordering that causes this operation to fail ). But from Java Look at the source code , In fact, this method is not implemented JSR Specification requirements , The final effect and compareAndSet It's equivalent , They all called. unsafe.compareAndSwapInt() To complete the operation .
    1. public final boolean compareAndSet(int expect, int update) {
    2. return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    3. }
    4. public final boolean weakCompareAndSet(int expect, int update) {
    5. return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    6. }
  • about AtomicInteger、AtomicLong There are also some special methods .
    getAndIncrement( ): Adds the current value atomically 1, Equivalent to thread safe i++ operation . 
    incrementAndGet( ): Adds the current value atomically 1, Equivalent to thread safe ++i operation .
    getAndDecrement( ): Atomic subtraction of the current value 1, Equivalent to thread safe i-- operation .
    decrementAndGet ( ): Atomic subtraction of the current value 1, Equivalent to thread safe --i operation . 
    addAndGet( ): Add the given value to the current value atomically , It's actually equal to thread safe i =i+delta operation .
    getAndAdd( ): Add the given value to the current value atomically , Equivalent to thread safe t=i; i+=delta; return t; operation .
    To achieve some addition , Subtraction atomic operation .( Be careful --i、++i It's not an atomic operation , It includes 3 There are two steps : First step , Read i; The second step , Add 1 Or minus 1; The third step : Write back to memory )

Use AtomicReference Create a thread safe stack

  1. import java.util.concurrent.atomic.AtomicReference;
  2. public class ConcurrentStack<T> {
  3. private AtomicReference<Node<T>>    stacks  = new AtomicReference<Node<T>>();
  4. public T push(T e) {
  5. Node<T> oldNode, newNode;
  6. for (;;) { //  The treatment here is very special , It has to be the same .
  7. oldNode = stacks.get();
  8. newNode = new Node<T>(e, oldNode);
  9. if (stacks.compareAndSet(oldNode, newNode)) {
  10. return e;
  11. }
  12. }
  13. }
  14. public T pop() {
  15. Node<T> oldNode, newNode;
  16. for (;;) {
  17. oldNode = stacks.get();
  18. newNode = oldNode.next;
  19. if (stacks.compareAndSet(oldNode, newNode)) {
  20. return oldNode.object;
  21. }
  22. }
  23. }
  24. private static final class Node<T> {
  25. private T       object;
  26. private Node<T>   next;
  27. private Node(T object, Node<T> next) {
  28. this.object = object;
  29. this.next = next;
  30. }
  31. }
  32. }

Although the scalar class of atoms extends Number class , But it does not extend some basic types of wrapper classes , Such as Integer or Long, In fact, they can't expand either : The packing class of basic type cannot be modified , Atomic variable classes are modifiable . There is no redefinition in the atomic variable class hashCode or equals Method , Each instance is different , They are also not suitable for hash container based key values .

The second group AtomicIntegerArray,AtomicLongArray also AtomicReferenceArray Class further extends atomic operations , Support for these types of arrays . These classes are providing  volatile  The semantic aspect of access is also remarkable , This is not supported for normal arrays .

They're not like inside AtomicInteger Keep one as well valatile Variable , It's all made up of native Method realization , as follows
AtomicIntegerArray Implementation fragment of :

  1. private static final Unsafe unsafe = Unsafe.getUnsafe();
  2. private static final int base = unsafe.arrayBaseOffset(int[].class);
  3. private static final int scale = unsafe.arrayIndexScale(int[].class);
  4. private final int[] array;
  5. public final int get(int i) {
  6. return unsafe.getIntVolatile(array, rawIndex(i));
  7. }
  8. public final void set(int i, int newValue) {
  9. unsafe.putIntVolatile(array, rawIndex(i), newValue);
  10. }

The third group AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater Reflection based utility , You can specify  volatile  Field for atom update .API It's simple , But there are also some constraints :

(1) Field must be volatile Type of

(2) The description type of the field ( Modifier public/protected/default/private) Is consistent with the relationship between the caller and the operation object field . in other words Callers can directly manipulate object fields , Then you can do atomic manipulation by reflection . But for fields of the parent class , Subclasses can't be manipulated directly , Although the subclass can access the fields of the parent class .

(3) Only instance variables , Can't be a class variable , That is to say, we can't add static keyword .

(4) Only modifiable variables , Can't make final Variable , because final The semantics of is immutable . actually final And volatile There is a conflict , These two keywords cannot exist at the same time .

(5) about AtomicIntegerFieldUpdater  and AtomicLongFieldUpdater  It can only be modified int/long Type field , You can't modify its packing type (Integer/Long). If you want to change the packaging type, you need to use AtomicReferenceFieldUpdater .

netty5.0 Middle class ChannelOutboundBuffer Count the total number of bytes sent , Due to the use volatile Variables can no longer satisfy , So use AtomicIntegerFieldUpdater  To achieve , Look at the code below :

  1. private static final AtomicLongFieldUpdater<ChannelOutboundBuffer> TOTAL_PENDING_SIZE_UPDATER =
  2. AtomicLongFieldUpdater.newUpdater(ChannelOutboundBuffer.class, "totalPendingSize");
  3. private volatile long totalPendingSize;
  4. // Use
  5. long oldValue = totalPendingSize;
  6. long newWriteBufferSize = oldValue + size;
  7. while (!TOTAL_PENDING_SIZE_UPDATER.compareAndSet(this, oldValue, newWriteBufferSize)) {
  8. oldValue = totalPendingSize;
  9. newWriteBufferSize = oldValue + size;
  10. }

16.Java Multithreading -java.util.concurrent.atomic Interpretation of the package principle

Basic types of multithreading
AtomicReference
Atomic*
Atomic Bag is java.util.concurrent The other one under is specially designed for thread safety Java package , Contains multiple atomic operation classes , but Atomic How to achieve thread safety of ?
1、 Hardware synchronization strategy
Today's processors support multiprocessing , Of course, it also includes multiple processors sharing peripherals and memory , meanwhile , Enhanced instruction set to support some special requirements of multiprocessing .
In particular, almost all processors can block other processors to update shared variables
2、Compare and swap(CAS)
Current processors basically support CAS, It's just that the algorithms implemented by each manufacturer are different , every last CAS There are three operators in the operation : A memory address V,
A desired value A And a new value B, During operation, if the value stored in the address is equal to the expected value A, Then assign the value on the address to the new value B, Otherwise you don't do anything .
CAS The basic idea is , If the value on this address is equal to the expected value , Give it a new value , Otherwise I don't do anything , But to return what the original value is . Let's take an example ,
explain CAS Implementation process ( It's not true CAS Realization )

3、 Implementation of the core source code :
 /**
     * Atomically increments by one the current value.
     * @return the updated value
     */
    public final int incrementAndGet() {
        for (;;) {
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))
                return next;
        }
    }
    public final boolean compareAndSet(int expect, int update) {
        // Use unsafe Of native Method , Achieve an efficient hardware level CAS  
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
It's better than using the traditional java Locking mechanism ( Obstructed ) What are the benefits ?
The biggest advantage is that it can avoid priority inversion and deadlock of multithreading , Of course, it's also very important to improve the performance of high-tech enterprises

4、CAS Thread safety
Said along while , We're going back to the original question : How to achieve thread safety in this way ? Please think about it yourself , In fact, we don't do any synchronous operation at the language level ,
You can also see that there is no lock on the source code , But why is it thread safe ? This is it. Atomic Wrap up the secrets of these classes : No processing at the language level , We give it to the hardware —CPU And memory ,
utilize CPU More processing power , Implement hardware level blocking , Plus volatile Variable can realize thread safety based on atomic operation . So ,CAS It's not that there's no blocking ,
It's just blocking, not language 、 In terms of threads , But at the hardware level , So there is no doubt that this kind of operation will be faster and more efficient !

5 summary
Although based on CAS The thread safety mechanism is very good and efficient , But the point is , Not all thread safety can be achieved in this way , This is only suitable for some small particle sizes ,
Requirements such as counters work , Otherwise, there will be no lock .

15.JDK1.8 Of Java.util.concurrent.atomic Summary of Bao

Atomic It means atomic , JUC Package is and contract .

Atomic Characteristics :

① Multi-threaded environment , There's nothing to do with atomic operations . 
② There is no absolute guarantee that threads will not be blocked .( Because of different CPU The atomic instructions are different , Some form of internal locking may be required )

summary

J.U.C(java.util.concurrent) Atomic classification
According to the modified data type , Can be JUC The atomic operation classes in the package can be divided into 4 class .
1. Basic types : AtomicInteger, AtomicLong,  AtomicBoolean ;
2. An array type : AtomicIntegerArray, AtomicLongArray,  AtomicReferenceArray ;
3. Reference type : AtomicReference,  AtomicStampedRerence,  AtomicMarkableReference ;
4. Object's property modification type : AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, AtomicReferenceFieldUpdater .

JDK1.5 in :

Atomic update basic types : 
AtomicBoolean: Atomic updates Boolean types . 
AtomicInteger: Atomic update integer . 
AtomicLong: Atomic update long integer .

Atom update basic type array :

AtomicIntegerArray: An atom updates the elements of an integer array . 
AtomicLongArray: An atom updates the elements of a long integer array .

Update fields :

abstract class :AtomicIntegerFieldUpdater: Atom update integer field updater . 
abstract class :AtomicLongFieldUpdater: Atom update long field updater . 
abstract class :AtomicReferenceFieldUpdater: Atom updates the fields in the reference type .

Update reference type :

AtomicReference: Atomic update reference types .

AtomicMarkableReference The atom updates the reference type with the tag bit

AtomicStampedReference: Atomic update reference type with version number . This class associates integer values with references , More data available for atoms and version numbers of data ,

It can solve the problem of using CAS When you do an atomic update , Possible ABA problem .

Update reference type array : 
AtomicReferenceArray: An atom updates an element in an array of reference types .

JDK1.8 in :Striped64

JDK 8 Of java.util.concurrent.atomic There is a package local class Striped64 , It holds common representations and mechanisms , For class support dynamic striping To 64bit Value up .

strping: 
data striping It is to divide logically continuous data into multiple segments , Make the segments of this sequence stored on different physical devices . By spreading segments across multiple devices, access concurrency can be increased , So as to improve the overall throughput .

accumulator :

DoubleAccumulator

DoubleAdder

LongAccumulator

LongAdder

1.8 Medium Double and Long accumulator Will be the original

Such as Integer in

 do {
prev = get();
next = accumulatorFunction.applyAsInt(prev, x);
} while (!compareAndSet(prev, next));

do while system Turn into

 public void add(long x) {
Cell[] as; long b, v; int m; Cell a;
if ((as = cells) != null || !casBase(b = base, b + x)) {
boolean uncontended = true;
if (as == null || (m = as.length - 1) < 0 ||
(a = as[getProbe() & m]) == null ||
!(uncontended = a.cas(v = a.value, v + x)))
longAccumulate(x, null, uncontended);
}
}

Reference resources :http://www.cnblogs.com/davidwang456/p/4670777.html

1. 
In scalar terms Such as boolean,integer,long,reference. 
The bottom layer is CAS (compare and swap) + volatile and native Method , Thus avoiding synchronized The high cost of , Greatly improved execution efficiency

2. 
AtomicIntegerArray,AtomicLongArray also AtomicReferenceArray Class further extends atomic operations , Support for these types of arrays .

These classes are providing volatile The semantic aspect of access is also remarkable , This is not supported for normal arrays . They're not like inside AtomicInteger Keep one as well valatile Variable , It's all made up of native Method realization , as follows  AtomicIntegerArray Implementation fragment of

3. 
AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater Reflection based utility , You can specify volatile Field for atom update .API It's simple , But there are also some constraints :

(1) Field must be volatile Type of

(2) The description type of the field ( Modifier public/protected/default/private) Is consistent with the relationship between the caller and the operation object field . That is to say, the caller can directly manipulate the object field , Then you can do atomic manipulation by reflection . But for fields of the parent class , Subclasses can't be manipulated directly , Although the subclass can access the fields of the parent class .

(3) Only instance variables , Can't be a class variable , That is to say, we can't add static keyword .

(4) Only modifiable variables , Can't make final Variable , because final The semantics of is immutable . actually final And volatile There is a conflict , These two keywords cannot exist at the same time .

(5) about AtomicIntegerFieldUpdater and AtomicLongFieldUpdater It can only be modified int/long Type field , You can't modify its packing type (Integer/Long). If you want to change the packaging type, you need to use AtomicReferenceFieldUpdater .

netty5.0 Middle class ChannelOutboundBuffer Count the total number of bytes sent , Due to the use volatile Variables can no longer satisfy , So use AtomicIntegerFieldUpdater To achieve , Look at the code below :

Atomic What are the following classes

13 Implementation classes :

AtomicBoolean

@since 1.5
Self translation : One 、 It could be updated atomically .
Two 、 Can't be treated as Boolean substitute

AtomicInteger

 characteristic :
Self translation : One 、 It could be updated atomically .
Two 、 Can't be treated as Integer substitute
3、 ... and 、 Class inherits from Number, Allow to be numerical based classes file Use it as a tool class

AtomicIntegerArray

@since 1.5
characteristic :
Self translation : It could be updated atomically .
This class is usually used as

AtomicLong

 characteristic :
Self translation : One 、 It could be updated atomically .
Two 、 Can't be treated as Long substitute
3、 ... and 、 Class inherits from Number, Allow to be numerical based classes file Use it as a tool class

AtomicLongArray

 characteristic :
Self translation : It could be updated atomically . This class is usually used as

AtomicMarkableReference

 One 、 Maintain an object reference , Add a marker bit , Except for the tag bit , You can also do atomic updates .
Two 、 This is achieved by creating a representation “ Packing ”( quote 、 Boolean ) Keep tag references to internal objects of .

AtomicReference

@since 1.5
One 、 Object references that can be updated atomically

AtomicReferenceArray

@since 1.5
One 、 Object references that can be updated atomically

AtomicStampedReference

@since 1.5
One 、 Keep an object reference and an integer “ Stamp ”, It can be updated atomically .
Two 、 Implementation notes : This is achieved by creating a representation “ Packing ”( quote 、 Integers ) Maintain tag references to internal objects of .

DoubleAccumulator

@since 1.8
One or more variables , Jointly maintain a running {@ code double} value , Update... With the functions provided . When updated ( Method {@ link # The accumulation of }) When competing between threads , Variable sets can grow dynamically to reduce contention . Method {@ link # get}( perhaps , Fairly ,{@ link # doubleValue}) Returns the current value , To keep it up to date .
When multiple threads update a common value , This class is usually preferable to other methods , For example, summary statistics that are updated frequently but not read frequently .
The accumulator function provided should be side-effect free , Because when an attempt to update fails , Due to contention between threads , It could be reused . Function takes the current value as its first argument , And given update As the second parameter . for example , In order to maintain a running maximum , You can provide {@ code Double::max} and {@ code Double.NEGATIVE_INFINITY } The identity of the . There is no guarantee of order accumulated within or across threads . therefore , this
If numerical stability is needed , Class may not apply , Especially when a large number of different values are combined
Size . class {@ link DoubleAdder} Similar functions of this class are provided for common special cases of maintenance and maintenance . call {@ code new DoubleAdder()} amount to {@ code new double accumulator ((x,y)- > x + y,0.0)}.
This class extends {@ link Number}, however < em > No < /em > Defined such as {@ code =}、{@ code hashCode} and {@ code compareTo} Something like that , Because instances are expected to mutate , So it's not useful as a set key .

DoubleAdder

@since 1.8
One or more variables together maintain an initial zero {@ code double} sum. When updated ( Method {@ link # add}) When competing between threads , Variable sets can grow dynamically to reduce contention .
Method {@ link # sum}( perhaps , Equivalent {@ link # doubleValue}) Combine the current total on variables that maintain the total . There is no guarantee of order accumulated within or across threads .
therefore , If numerical stability is needed , This class may not apply , Especially when a large number of values of different orders of magnitude are combined .
When multiple threads update a common value , This class is usually preferable to other methods , For example, frequently updated but infrequently summarized statistical data
This class extends {@ link Number}, however < em > No < /em > Defined such as {@ code =}、{@ code hashCode} and {@ code compareTo} Something like that , Because instances are expected to mutate , So it's not useful as a set key .

LongAccumulator

LongAdder

4 An abstract class

AtomicIntegerFieldUpdater

AtomicLongFieldUpdater

AtomicReferenceFieldUpdater


Striped64

1.8 Added 

14.Java in Atomic Principle and analysis of package

Atomic brief introduction

Atomic Bag is Java.util.concurrent The other one under is specially designed for thread safety Java package , Contains multiple atomic operation classes . This package provides a set of atomic variable classes .

Its basic characteristic is in multithreading environment , When there are multiple threads executing the methods contained in the instances of these classes at the same time , Be exclusive , That is, when a thread enters a method , When executing the instructions , Will not be interrupted by other threads , And other threads are like spinlocks , Wait until the method execution is complete , Only by JVM Select another thread from the waiting queue to enter , It's just a logical understanding .

In fact, it is realized by the related instructions of hardware , Will not block threads ( Or it's just blocking at the hardware level ). It can be used for basic data 、 The basic data in the array 、 Operate on the basic data in the class .

An atomic variable class is equivalent to a generalized volatile Variable , Able to support atomic and conditional reading - Change - Write operations .——   To quote @chenzehe  The blog of .

The problem with traditional locks

Let's start with an example : Counter (Counter), use Java It's a convenient locking mechanism synchronized keyword , The initial code is as follows :

  1. class Counter {
  2. private int value;
  3. public synchronized int getValue() {
  4. return value;
  5. }
  6. public synchronized int increment() {
  7. return ++value;
  8. }
  9. public synchronized int decrement() {
  10. return --value;
  11. }
  12. }

In fact, a locking mechanism like this , There is no problem in meeting basic needs , But sometimes our needs are not so simple , We need to be more effective , More flexible mechanisms ,synchronized Keyword is based on blocking lock mechanism , That is, when a thread has a lock , Other threads accessing the same resource need to wait , Until the thread releases the lock , There will be some problems :

First , What if the priority of the blocked thread is very high and important ? secondly , What if the thread that gets the lock does not release the lock ?( This situation is very bad ).
There's another situation , If there are a lot of threads competing for resources , that CPU It will take a lot of time and resources to deal with the competition ( in fact CPU My main job is not that ),
meanwhile , There may also be some situations such as deadlock , Last , In fact, the locking mechanism is relatively rough , The mechanism of larger granularity , It's a bit cumbersome relative to requirements like counters ,
therefore , For this kind of demand, we expect a more suitable 、 More efficient thread safety mechanism .

Hardware synchronization strategy

Today's processors support multiprocessing , Of course, it also includes multiple processors sharing peripherals and memory , meanwhile , Enhanced instruction set to support some special requirements of multiprocessing . In particular, almost all processors can block other processors to update shared variables .

Compare and swap(CAS)

Current processors basically support CAS, It's just what every manufacturer has achieved Algorithm It's not the same , every last CAS There are three operators in the operation : A memory address V, A desired value A And a new value B, During operation, if the value stored in the address is equal to the expected value A, Then assign the value on the address to the new value B, Otherwise you don't do anything .

CAS The basic idea is , If the value on this address is equal to the expected value , Give it a new value , Otherwise I don't do anything , But to return what the original value is .

Let's take an example , explain CAS Implementation process ( It's not true CAS Realization ):

  1. class SimulatedCAS {
  2. private int value;
  3. public synchronized int getValue() {
  4. return value;
  5. }
  6. public synchronized int compareAndSwap(int expectedValue, int newValue) {
  7. int oldValue = value;
  8. if (value == expectedValue)
  9. value = newValue;
  10. return oldValue;
  11. }
  12. }

Here is a CAS Realized Counter

  1. public class CasCounter {
  2. private SimulatedCAS value;
  3. public int getValue() {
  4. return value.getValue();
  5. }
  6. public int increment() {
  7. int oldValue = value.getValue();
  8. while (value.compareAndSwap(oldValue, oldValue + 1) != oldValue)
  9. oldValue = value.getValue();
  10. return oldValue + 1;
  11. }
  12. }

Examples are as follows :

  1. public class Counter implements Runnable {
  2. private final AtomicInteger count = new AtomicInteger(0);
  3. public void run() {
  4. System.out.println(Thread.currentThread().getName()
  5. + ":" + count.incrementAndGet());
  6. }
  7. public static void main(String[] args){
  8. Counter counter = new Counter();
  9. Thread t1 = new Thread(counter);
  10. Thread t2 = new Thread(counter);
  11. Thread t3 = new Thread(counter);
  12. Thread t4 = new Thread(counter);
  13. t1.start();
  14. t2.start();
  15. t3.start();
  16. t4.start();
  17. }
  18. }

See how it's implemented in the source code

  1. private volatile int value;
  2. public AtomicInteger(int initialValue) {
  3. value = initialValue;
  4. }
  5. public final int incrementAndGet() {
  6. for (;;) {
  7. int current = get();
  8. int next = current + 1;
  9. if (compareAndSet(current, next))
  10. return next;
  11. }
  12. }
  13. public final boolean compareAndSet(int expect, int update) {
  14. return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
  15. }
  16. public final int get() {
  17. return value;
  18. }

Is it similar to optimistic lock , If the results match the expected results , Return the result to , Otherwise, try again and again , There's no synchronization , Both security and performance

java.util.concurrent.atomic There are many classes under the package , The use of these classes ensures that the “ obtain - to update ” The operation is atomic , So as to avoid competitive conditions

  1. AtomicBoolean  It can be updated atomically  boolean  value .
  2. AtomicInteger  It can be updated atomically  int  value .
  3. AtomicIntegerArray  Can update its elements in the atomic way  int  Array .
  4. AtomicIntegerFieldUpdater<T>  Reflection based utility , You can specify  volatile int  Field for atom update .
  5. AtomicLong  It can be updated atomically  long  value .
  6. AtomicLongArray  Can update its elements in the atomic way  long  Array .
  7. AtomicLongFieldUpdater<T>  Reflection based utility , You can specify  volatile long  Field for atom update .
  8. AtomicMarkableReference<V> AtomicMarkableReference  Maintain object references with tag bits , It can be updated atomically .
  9. AtomicReference<V>  Object references that can be updated atomically .
  10. AtomicReferenceArray<E>  The object reference array of its elements can be updated atomically .
  11. AtomicReferenceFieldUpdater<T,V>  Reflection based utility , You can specify  volatile  Field for atom update .
  12. AtomicStampedReference<V> AtomicStampedReference  Maintenance with integers “ sign ” Object reference of , It can be updated atomically .

Atomic class

stay JDK5.0 Before , It is impossible to realize the algorithm of no lock and no wait , Unless you use a local library , Ever since Atomic After variable class , It's possible . Here is the graph java.util.concurrent.atomic The class structure under the package .
  • Scalar class :AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference
  • Array class :AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray
  • Updater class :AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater
  • Compound variable class :AtomicMarkableReference,AtomicStampedReference

The first group AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference These four basic types are used to deal with Boolean , Integers , long integer , Object four kinds of data , Its internal implementation is not a simple use synchronized, It's a more efficient way CAS (compare and swap) + volatile and native Method , Thus avoiding synchronized The high cost of , Greatly improved execution efficiency . Let's take an example , It's the same as us i++ The corresponding atomic operation is :getAndIncrement()

  1. public static void main(String[] args) {
  2. AtomicInteger ai = new AtomicInteger();
  3. System.out.println(ai);
  4. ai.getAndIncrement();
  5. System.out.println(ai);
  6. }

We can have a look AtomicInteger The implementation of the :

  1. /**
  2. * Atomically increments by one the current value.
  3. *
  4. * @return the previous value
  5. */
  6. public final int getAndIncrement() {
  7. return unsafe.getAndAddInt(this, valueOffset, 1);
  8. }

Here we call a Unsafe Class to handle , It seems that we need to keep looking unsafe Class source code .JDK8 in sun.misc Next UnSafe class , Click on View source code

From the comments on the source code , This class is used to perform low level 、 Collection of methods for unsafe operations . Although this class and all methods are public (public), But the use of this class is still limited , You can't be on your own java This class is used directly in the program , Because only the credit code can get the instance of this class . So we usually can't use this class in our code , Because the operation of its design is too low-level , If the operation is not careful, it may bring great disaster , So it's forbidden to access normal code directly , Of course JDK There's no problem with it .

Atomic Medium CAS

From the previous explanation we can see that ,CAS The principle is to compare the expected value with the original value , If it is the same, update it to a new value ,

Here's this “ One of the original values ” How to , Let's see. AtomicInteger The realization in :

  1. // setup to use Unsafe.compareAndSwapInt for updates
  2. private static final Unsafe unsafe = Unsafe.getUnsafe();
  3. private static final long valueOffset;
  4. static {
  5. try {
  6. valueOffset = unsafe.objectFieldOffset
  7. (AtomicInteger.class.getDeclaredField("value"));
  8. } catch (Exception ex) { throw new Error(ex); }
  9. }

Used here UnSafe One way objectFieldOffset(), View source code :

  1. public native long objectFieldOffset(Field f);

This method is used to get the one we mentioned above “ The value of the original ” Memory address of . It's a local approach , The return value is valueOffset. Its parameters field Namely AtomicInteger The definition of value attribute :

  1. private volatile int value;
  2. /**
  3. * Creates a new AtomicInteger with the given initial value.
  4. *
  5. * @param initialValue the initial value
  6. */
  7. public AtomicInteger(int initialValue) {
  8. value = initialValue;
  9. }
  10. /**
  11. * Creates a new AtomicInteger with initial value {@code 0}.
  12. */
  13. public AtomicInteger() {
  14. }

value It's a volatile Variable , Visible in memory , No thread is allowed to copy it , therefore JVM It can guarantee that any thread can always get the latest value of this variable at any time . here value Value , Can be in AtomicInteger Class initialization , You can leave it blank , If left blank, it will be automatically assigned to 0.

Let's go back to CAS, have a look getAndIncrement() The method is how to use CAS Realized .

  1. /**
  2. * Atomically increments by one the current value.
  3. *
  4. * @return the previous value
  5. */
  6. public final int getAndIncrement() {
  7. return unsafe.getAndAddInt(this, valueOffset, 1);
  8. }

continue :

  1. public final int getAndAddInt(Object o, long offset, int delta) {
  2. int v;
  3. do {
  4. v = getIntVolatile(o, offset);//------------0---------------
  5. } while (!compareAndSwapInt(o, offset, v, v + delta));//-------------1-------------
  6. return v;
  7. }
  1. /**
  2. * Atomically update Java variable to <tt>x</tt> if it is currently
  3. * holding <tt>expected</tt>.
  4. * @return <tt>true</tt> if successful
  5. */
  6. public final native boolean compareAndSwapInt(Object o, long offset,//---------------2--------------
  7. int expected,
  8. int x);

Let me explain a little bit , Actually compareAndSwapInt The explanation is very clear , Atomic update the value of the variable to x, If successful, return true, We know , If we create AtomicInteger No parameters are passed in to the instance , Then the value of the original variable is 0, So the above //----------0----------- Where you get it v The value is 0,1 The code at is :

while(!compareAndSwapInt(o, offset, 0, 1)) We know offset The value corresponding to the address is the initial value of the original variable 0, So with the expected value 0 identical , So we assign the initial value to 1, return true, Take the reverse as false, The loop ends , return v That is to update the previous value 0. This is similar to i++ The implementation of atomic operation of operation , Of course, in the end CAS The realization of native Of , use C Language Realized , We don't see the source code here , I'll decompile this code sometime to see .

CAS Thread safety

Said along while , We're going back to the original question : How to achieve thread safety in this way ? Please think about it yourself , In fact, we don't do any synchronous operation at the language level , You can also see that there is no lock on the source code , But why is it thread safe ? This is it. Atomic Wrap up the secrets of these classes : No processing at the language level , We give it to the hardware —CPU And memory , utilize CPU More processing power , Implement hardware level blocking , Plus volatile Variable can realize thread safety based on atomic operation . So ,CAS It's not that there's no blocking , It's just blocking, not language 、 In terms of threads , But at the hardware level , So there is no doubt that this kind of operation will be faster and more efficient !

summary

Although based on CAS The thread safety mechanism is very good and efficient , But the point is , Not all thread safety can be achieved in this way , This is only suitable for some small particle sizes , It's only when you need a counter that it works , Otherwise, there will be no lock .

11.java The atomicity of concurrency 、 visibility 、 Orderliness  

Java The memory model revolves around how to deal with atomicity in concurrent processes 、 visibility 、 The three characteristics of order , Here are the implementation principles of these three features :

1. Atomicity (Atomicity) : from Java The atomicity variable operations directly guaranteed by the memory model include read、load、use、assign、store and write six , Generally speaking, the access, reading and writing of basic data types are atomic . If the application scenario needs a wider range of atomicity guarantees ,Java The memory model also provides lock and unlock Operations to meet this need , Although the virtual machine does not lock And unlock Operation is directly open to users , But it provides a higher level of bytecode instructions monitorenter and monitorexit To use these two operations in hiding , These two bytecode instructions reflect Java In the code is the synchronization block ---synchronized keyword , So in synchronized Operations between blocks are also atomic .

Atomicity
The atom is the smallest unit in the world , It is indivisible . such as a=0;(a Not long and double type ) This operation is indivisible , So we say this operation is atomic operation . Another example :a++; This operation is actually a = a + 1; It's divisible , So it's not an atomic operation . All non atomic operations have thread safety problems , We need to use synchronization technology (sychronized) To make it an atomic operation . An operation is an atomic operation , So we call it atomic .java Of concurrent Some atomic classes are provided under the package , We can read API To understand the usage of these atomic classes . such as :AtomicInteger、AtomicLong、AtomicReference etc. .

1、 Atomicity (Atomicity)
Atomicity means that in an operation it means cpu You can't pause in the middle and then schedule , Not interrupted , Do not execute complete , Or not .
If an operation is atomic , In the case of multithreading concurrency , There will be no changes to variables
such as a=0;(a Not long and double type ) This operation is indivisible , So we say this operation is atomic operation . Another example :a++; This operation is actually a = a + 1; It's divisible , So it's not an atomic operation .
All non atomic operations have thread safety problems , We need to use synchronization technology (sychronized) To make it an atomic operation . An operation is an atomic operation , So we call it atomic .java Of concurrent Some atomic classes are provided under the package , We can read API To understand the usage of these atomic classes . such as :AtomicInteger、AtomicLong、AtomicReference etc. .

( from Java The atomicity variable operations directly guaranteed by the memory model include read、load、use、assign、store and write six , Generally speaking, the access, reading and writing of basic data types are atomic . If the application scenario needs a wider range of atomicity guarantees ,Java The memory model also provides lock and unlock Operations to meet this need , Although the virtual machine does not lock And unlock Operation is directly open to users , But it provides a higher level of bytecode instructions monitorenter and monitorexit To use these two operations in hiding , These two bytecode instructions reflect Java In the code is the synchronization block —synchronized keyword , So in synchronized Operations between blocks are also atomic .)

One . Atomicity means that an operation cannot be interrupted . Even when multiple threads are executing together , Once an operation begins , It won't be disturbed by other threads .
Java Atomic operations in include :
1) except long and double Assignment of basic types other than
2) All references reference Assignment of
3)java.concurrent.Atomic.* All operations of all classes in the package .
however java Yes long and double Assignment operation of is non atomic !!long and double The number of bytes occupied is 8, That is to say 64bits. stay 32 On bit operating system 64 The reading and writing of bit data should be completed in two steps , Each step takes 32 Bit data . That's right double and long There will be problems with the assignment operation of : If two threads write a variable memory at the same time , Write low for a process 32 position , And the other is high 32 position , This will result in 64 Bit data is invalid data . So you need to use volatile Keyword to prevent this kind of phenomenon .volatile The atomicity of the get and set operations is not guaranteed by itself , Only maintain the visibility of changes . however java The memory model guarantee for is declared as volatile Of long and double Variable get and set Operation is atomic .

public class UnatomicLong implements Runnable {
private static long test = 0;

private final long val;

public UnatomicLong(long val) {
this.val = val;
}

@Override
public void run() {
while (!Thread.interrupted()) {
test = val; // Both threads are trying to put their own private variables val Assign to class private static variable test
}
}

public static void main(String[] args) {
Thread t1 = new Thread(new UnatomicLong(-1));
Thread t2 = new Thread(new UnatomicLong(0));
System.out.println(Long.toBinaryString(-1));
System.out.println(pad(Long.toBinaryString(0), 64));
t1.start();
t2.start();
long val;
while ((val = test) == -1 || val == 0) {
// If static member test The value of is -1 or 0, The two thread operations do not cross
}
System.out.println(pad(Long.toBinaryString(val), 64));
System.out.println(val);
t1.interrupt();
t2.interrupt();
}
// prepend 0s to the string to make it the target length
private static String pad(String s, int targetLength) {
int n = targetLength - s.length();
for (int x = 0; x < n; x++) {
s = "0" + s;
}
return s;
}
}
Run discoverer on while It's a dead cycle , This is because of the JVM yes 64bits. stay 64 position JVM in double and long Assignment operation of is atomic operation .
stay eclipse Revision in China jre For one 32bit Of JVM Address , The following operation results will be obtained :
1111111111111111111111111111111111111111111111111111111111111111
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000011111111111111111111111111111111
// Obviously test The value of is broken
4294967295

Atomicity : One or more operations Either all of them are executed and the execution process will not be interrupted by any factors , Or they don't do it .
stay Java in , Reading and assigning variables of basic data type is atomic operation , That is, these operations cannot be interrupted , Or execute , Or not .
Although the above sentence seems simple , But it's not that easy to understand . Here's an example i:
Please analyze which of the following operations are atomic operations :
x = 10; // sentence 1
y = x; // sentence 2
x++; // sentence 3
x = x + 1; // sentence 4
What do you think , Some friends may say the above 4 The operations in each statement are atomic operations . In fact, there are only sentences 1 Atomic operations , The other three statements are not atomic operations .
sentence 1 It's just going to put the number 10 Assign a value to x, That is to say, when the thread executes this statement, it will directly change the value 10 Write to working memory .
sentence 2 It actually contains 2 Operations , It has to read first x Value , then x The value of is written to working memory , Although read x And take x The value of is written to working memory this 2 All operations are atomic operations , But together, it's not an atomic operation .
alike ,x++ and x = x+1 Include 3 Operations : Read x Value , add 1 operation , Write a new value .
So the above 4 There are only statements 1 The operation is atomic .
in other words , Just a simple read 、 assignment ( And you have to assign a number to a variable , The assignment of variables to each other is not an atomic operation ) It's atomic manipulation .
But here's one thing to note : stay 32 Under the platform , Yes 64 Bit data reading and assignment need to be done through two operations , There is no guarantee of its atomicity . But it seems to be in the latest JDK in ,JVM It's guaranteed that 64 Bit data reading and assignment are also atomic operations .
As can be seen from the above ,Java The memory model only guarantees that basic reads and assignments are atomic operations , If you want to achieve the atomicity of a wider range of operations , Can pass synchronized and Lock To achieve . because synchronized and Lock It can guarantee that only one thread can execute the code block at any time , Then naturally there is no atomicity , So that atomicity .

2. visibility (Visibility)
Visibility is when a thread modifies the value of a thread shared variable , Other threads can immediately learn about this change .Java The memory model synchronizes new values back to main memory after variables are modified , Refresh the variable value from main memory before reading the variable. This method relies on main memory as the transmission medium to achieve visibility , Whether it's a normal variable or a volatile It's the same with variables , Common variables vs volatile The difference between variables is volatile The special rule of ensures that the new value can be synchronized to the main memory immediately , And refresh from memory immediately before use . Because we can say volatile Ensure the visibility of variables during thread operation , Ordinary variables don't guarantee that .
except volatile outside ,Java There are also two keywords that allow visibility , They are synchronized. The visibility of synchronization blocks is determined by “ Execute on a variable unlock Before the operation , This variable must be synchronized back to main memory ( perform store and write operation )” This rule gets , and final Keyword visibility refers to : By final The decorated field is once the constructor is initialized , And the constructor didn't “this” Reference passed out , So you can see it in other threads final Value of field .

Visibility is when multiple threads access the same variable , A thread modified the value of this variable , Other threads can see the modified value immediately .
It depends on visibility ,Java Provides volatile Keywords to ensure visibility .
volatile The principle of visibility is every time When accessing variables, a refresh is performed , So every access is the latest version in main memory .
When a shared variable is volatile When decorating , It ensures that the modified value is immediately updated to main memory , When there are other threads that need to read , It will go to memory to read new values .
And common shared variables don't guarantee visibility , Because after the common shared variable is modified , When it is written to main memory is uncertain , When other threads go to read , At this time, the memory may still be the old value , So there's no guarantee of visibility .
in addition , adopt synchronized and Lock It also ensures visibility ,synchronized and Lock It can guarantee that only one thread can acquire lock and execute synchronization code at the same time , And before releasing the lock, the changes to variables will be refreshed to main memory . So you can guarantee visibility .

2. visibility
Visibility is when multiple threads access the same variable , A thread modified the value of this variable , Other threads can see the modified value immediately .
visibility ,Java Provides volatile Keywords to ensure visibility .
When a shared variable is volatile When decorating , It ensures that the modified value is immediately updated to main memory , When there are other threads that need to read , It will go to memory to read new values .
And common shared variables don't guarantee visibility , Because after the common shared variable is modified , When it is written to main memory is uncertain , When other threads go to read , At this time, the memory may still be the old value , So there's no guarantee of visibility .
in addition , adopt synchronized and Lock It also ensures visibility ,synchronized and Lock It can guarantee that only one thread can acquire lock and execute synchronization code at the same time , And before releasing the lock, the changes to variables will be refreshed to main memory . So you can guarantee visibility .

2、 visibility (Visibility)

Visibility is when a thread modifies the value of a thread shared variable , Other threads can immediately learn about this change .Java The memory model synchronizes new values back to main memory after variables are modified , Refresh the variable value from main memory before reading the variable. This method relies on main memory as the transmission medium to achieve visibility , Whether it's a normal variable or a volatile It's the same with variables , Common variables vs volatile The difference between variables is volatile The special rule of ensures that the new value can be synchronized to the main memory immediately , And refresh from memory immediately before use . Because we can say volatile Ensure the visibility of variables during thread operation , Ordinary variables don't guarantee that .

except volatile outside ,Java There are also two keywords that allow visibility , They are synchronized. The visibility of synchronization blocks is determined by “ Execute on a variable unlock Before the operation , This variable must be synchronized back to main memory ( perform store and write operation )” This rule gets , and final Keyword visibility refers to : By final The decorated field is once the constructor is initialized , And the constructor didn't “this” Reference passed out , So you can see it in other threads final Value of field .
( visibility , It refers to the visibility between threads , The modified state of one thread is visible to another . This is the result of a thread modification . The other thread will see . such as : use volatile Decorated variable , There will be visibility .volatile Decorated variables do not allow thread internal caching and reordering , That is to modify the memory directly . So it's visible to other threads . But here's a problem to pay attention to ,volatile It can only make the modified content visible , But there's no guarantee that it's atomic . such as volatile int a = 0; And then there's an operation a++; This variable a Visibility , however a++ It's still a non-atomic operation , This operation also has thread safety problems .)

visibility
visibility , It refers to the visibility between threads , The modified state of one thread is visible to another . This is the result of a thread modification . The other thread will see . such as : use volatile Decorated variable , There will be visibility .volatile Decorated variables do not allow thread internal caching and reordering , That is to modify the memory directly . So it's visible to other threads . But here's a problem to pay attention to ,volatile It can only make the modified content visible , But there's no guarantee that it's atomic . such as volatile int a = 0; And then there's an operation a++; This variable a Visibility , however a++ It's still a non-atomic operation , This operation also has thread safety problems .

3. Orderliness
Order means that the program is executed in the order of code execution .
stay Java In memory model , Allow compiler and processor to reorder instructions , However, the reordering process will not affect the execution of single threaded programs , But it will affect the correctness of multithreading concurrent execution .( for example : When you rearrange, some assignments are advanced )
stay Java Inside , Can pass volatile Keywords to ensure a certain “ Orderliness ”( The specific principle is described in the next section ). In addition, you can use synchronized and Lock To ensure order , Obviously ,synchronized and Lock Ensure that there is a thread executing synchronization code at every time , So let the threads execute the synchronization code in sequence , Nature guarantees order .

3、 Orderliness (Ordering)
Java The natural order of programs in the memory model can be summed up in one sentence : If you observe in this thread , All operations are orderly ; If you observe another thread in one thread , All operations are unordered . The first half refers to “ Serial semantics in threads ”, The second half of the sentence refers to “ Instruction reordering ” Phenomenon and “ Main memory synchronization delay in working memory ” The phenomenon .

Java Language provides volatile and synchronized Two keywords to ensure the order of operations between threads ,volatile The keyword itself contains the semantics to prohibit the reordering of instructions , and synchronized It is from “ Only one thread is allowed to work on a variable at a time lock operation ” That's the rule , This rule determines that two synchronization blocks holding the same lock can only enter serially .
Antecedent principle :
If Java All the ordering in the memory model depends on volatile and synchronized To complete , Then some operations will become verbose , But we're writing Java I didn't feel this when I was running concurrent code , This is because Java There is one in the language “ Happen first ”(Happen-Before) Principles . This principle is very important , It's about judging whether there's competition in the data , The main dependence of thread safety .

The first occurrence principle refers to Java Sequential relationship between two operations defined in memory model , If the operation A First occurs in operation B, In fact, it means that the operation occurs B Before , operation A The impact can be operated B The observed ,“ influence ” Contains values that modify shared variables in memory 、 Sent a message 、 Method called, etc . What does it mean ? Here's an example :
// Threads A In the implementation of
i = 1;
// Threads B In the implementation of
j = i;
// Threads C In the implementation of
i = 2;
Assuming that thread A The operation ”i=1“ Occurs first in a thread B The operation of ”j=i“, Then we can determine the thread B After , Variable j The value of must be equal to 1, There are two reasons for this conclusion , First, according to the principle of first occurrence ,”i=1“ The results can be observed ; The two is thread. C Before going on stage , Threads A No other thread will modify variables after the operation ends i Value . Now consider threads C, We still have threads A and B Antecedent relationship between , And threads C Appear in thread A and B Between operations , however C And B No prior relationship , that j The value of may be 1, It could be 2, Because the thread C Corresponding variable i May be affected by threads B The observed , It may not be observed , When a thread B There is a risk of reading out of date data , No multithreading security .

Here is Java Under the memory model ” natural “ Antecedent relationship , These antecedents exist without any synchronizer assistance , Can be used directly in coding . If the relationship between two operations is not in this column , And can't be derived from the following rules , They have no sequential guarantee , Virtual machines can reorder them at will .

a. Program Order Rule (Pragram Order Rule):
In a thread , In order of program code , The operation of writing before takes place before the operation of writing after . It should be the order of control flow rather than the order of program code , Because we need to think about branches 、 Loop structure .
b. Tube lock rule (Monitor Lock Rule): One unlock The operation occurs first of all on the same lock lock operation . The same lock must be emphasized here , and ” Back “ The order of time .
c.volatile Variable rule (Volatile Variable Rule): To a volatile The write operation of a variable occurs first and then the read operation of the variable , there ” Back “ It also refers to the chronological order .
d. Thread start rule (Thread Start Rule):Thread Object's start() Method occurs first in every action of this thread .
e. Thread finally rule (Thread Termination Rule):
All operations in a thread occur first at the termination detection of this thread , We can go through Thread.join() Method end ,Thread.isAlive() The return value and other segments of detect that the thread has terminated execution .
f. Thread interrupt rule (Thread Interruption Rule):
For threads interrupt() Method calls occur first when the interrupted thread's code detects the occurrence of an interrupt event , Can pass Thread.interrupted() Method detects if an interrupt has occurred .
g. Object termination rule (Finalizer Rule): An object initialization is completed ( Construction method execution completed ) What happened first finalize() The beginning of the method .
g. Transitivity (Transitivity): If you operate A First occurs in operation B, operation B First occurs in operation C, Then we can get the operation A First occurs in operation C Conclusion .
One operation ” First in time “ Doesn't mean this operation will be ” Happen first “, So if an operation ” Happen first “ Can we deduce that this operation must be ” First in time “ Well ? It doesn't work , A typical example is instruction reordering . So there's basically no relationship between the chronological order and the principle of gentleman's occurrence , Therefore, to measure concurrent security issues, the principle of first occurrence must prevail .

3. Orderliness (Ordering)
Java The natural order of programs in the memory model can be summed up in one sentence : If you observe in this thread , All operations are orderly ; If you observe another thread in one thread , All operations are unordered . The first half refers to “ Serial semantics in threads ”, The second half of the sentence refers to “ Instruction reordering ” Phenomenon and “ Working memory main memory synchronization delay ” The phenomenon . Java Language provides volatile and synchronized Two keywords to ensure the order of operations between threads ,volatile The keyword itself contains the semantics to prohibit the reordering of instructions , and synchronized It is from “ Only one thread is allowed to work on a variable at a time lock operation ” That's the rule , This rule determines that two synchronization blocks holding the same lock can only enter serially .

Antecedent principle : If Java All the ordering in the memory model depends on volatile and synchronized To complete , Then some operations will become verbose , But we're writing Java I didn't feel this when I was running concurrent code , This is because Java There is one in the language “ Happen first ”(Happen-Before) Principles . This principle is very important , It's about judging whether there's competition in the data , The main dependence of thread safety .
The first occurrence principle refers to Java Sequential relationship between two operations defined in memory model , If the operation A First occurs in operation B, In fact, it means that the operation occurs B Before , operation A The impact can be operated B The observed ,“ influence ” Contains values that modify shared variables in memory 、 Sent a message 、 Method called, etc . What does it mean ? Here's an example :
// Threads A In the implementation of
i = 1;
// Threads B In the implementation of
j = i;

// Threads C In the implementation of
i = 2;
Assuming that thread A The operation ”i=1“ Occurs first in a thread B The operation of ”j=i“, Then we can determine the thread B After , Variable j The value of must be equal to 1, There are two reasons for this conclusion , First, according to the principle of first occurrence ,”i=1“ The results can be observed ; The two is thread. C Before going on stage , Threads A No other thread will modify variables after the operation ends i Value . Now consider threads C, We still have threads A and B Antecedent relationship between , And threads C Appear in thread A and B Between operations , however C And B No prior relationship , that j The value of may be 1, It could be 2, Because the thread C Corresponding variable i May be affected by threads B The observed , It may not be observed , When a thread B There is a risk of reading out of date data , No multithreading security .
Here is Java Under the memory model ” natural “ Antecedent relationship , These antecedents exist without any synchronizer assistance , Can be used directly in coding . If the relationship between two operations is not in this column , And can't be derived from the following rules , They have no sequential guarantee , Virtual machines can reorder them at will .
a. Program Order Rule (Pragram Order Rule): In a thread , In order of program code , The operation of writing before takes place before the operation of writing after . It should be the order of control flow rather than the order of program code , Because we need to think about branches 、 Loop structure .
b. Tube lock rule (Monitor Lock Rule):
One unlock The operation occurs first of all on the same lock lock operation . The same lock must be emphasized here , and ” Back “ The order of time .
c.volatile Variable rule (Volatile Variable Rule): To a volatile The write operation of a variable occurs first and then the read operation of the variable , there ” Back “ It also refers to the chronological order .
d. Thread start rule (Thread Start Rule):Thread Object's start() Method occurs first in every action of this thread .
e. Thread finally rule (Thread Termination Rule):
All operations in a thread occur first at the termination detection of this thread , We can go through Thread.join() Method end ,Thread.isAlive() The return value and other segments of detect that the thread has terminated execution .
f. Thread interrupt rule (Thread Interruption Rule):
For threads interrupt() Method calls occur first when the interrupted thread's code detects the occurrence of an interrupt event , Can pass Thread.interrupted() Method detects if an interrupt has occurred .
g. Object termination rule (Finalizer Rule): An object initialization is completed ( Construction method execution completed ) What happened first finalize() The beginning of the method .
g. Transitivity (Transitivity): If you operate A First occurs in operation B, operation B First occurs in operation C, Then we can get the operation A First occurs in operation C Conclusion .
One operation ” First in time “ Doesn't mean this operation will be ” Happen first “, So if an operation ” Happen first “ Can we deduce that this operation must be ” First in time “ Well ? It doesn't work , A typical example is instruction reordering . So there's basically no relationship between the chronological order and the principle of gentleman's occurrence , Therefore, to measure concurrent security issues, the principle of first occurrence must prevail .

Orderliness : That is to say, the sequence of program execution is in accordance with the sequence of code execution .

stay Java In memory model , Allow compiler and processor to reorder instructions , However, the reordering process will not affect the execution of single threaded programs , But it will affect the correctness of multithreading concurrent execution .
stay Java Inside , Can pass volatile Keywords to ensure a certain “ Orderliness ”( The specific principle is described in the next section ). In addition, you can use synchronized and Lock To ensure order , Obviously ,synchronized and Lock Ensure that there is a thread executing synchronization code at every time , So let the threads execute the synchronization code in sequence , Nature guarantees order .
A lot of introductions JVM Concurrent books or articles will talk about JVM In order to optimize performance , Instruction reordering is used , But for what is instruction reordering , Why reordering optimizes performance is rarely mentioned , In fact, it's very simple , Suppose there are two shared variables a and b:
private int a;
private int b;
In a thread A There are two statements to assign values to these two shared variables :
a=1;
b=2;
Suppose that when threads A Yes a During the copy operation, it is found that this variable has been locked in the main memory by other threads , So at this point, the thread A What do I do ? Wait for the lock to release ? No , Waiting is a waste of time , It will try to do b Assignment of ,b It's not occupied at this time , So it's going to start with b assignment , I'll do it again a assignment , Then the order of execution becomes :
b=2;
a=1;
For within the same thread , Such a change will not have an impact on logic , But in the case of multithreading, instruction reordering will bring problems , Look at the following scenario :
In a thread A in :
context = loadContext();
inited = true;
In a thread B in :
while(!inited ){
sleep
}
doSomethingwithconfig(context);
hypothesis A There's a reordering in :
inited = true;
context = loadContext();
that B It is very likely that you will get one that has not been initialized or has not been initialized yet context, This causes a program error .
First make sure the program is correct, then optimize the performance . Here, the error caused by reordering is obviously heavier than the performance optimization caused by reordering More . To solve the reordering problem, we need to volatile keyword ,volatile Keyword can ensure that the operation of variables in the thread will not be reordered, but in the order specified in the code ask .

 

Concurrent java.util.concurrent.atomic More articles on atomic operation class packages

  1. java.util.concurrent.atomic Class package details

    java.util.concurrent The package is divided into three parts , Namely java.util.concurrent.java.util.concurrent.atomic and java.util.concurren ...

  2. java Concurrent programming : Thread safety management class -- Atomic package --java.util.concurrent.atomic

    java.util.concurrent.atomic Description of AtomicBoolean It can be updated atomically boolean value . AtomicInteger It can be updated atomically int value . ...

  3. Atomic classes java.util.concurrent.atomic.* Principle analysis

    Atomic classes java.util.concurrent.atomic.* Principle analysis In concurrent programming , The application of atomic operation class can be said to be everywhere . It provides great convenience for thread safe reading and writing . The two key points of atomic class are : can ...

  4. java.util.concurrent.atomic Bao explained in detail

    Atomic The role of package : It is convenient for programmers to work in multithreading environment , Atomic operation without lock Atomic Package core : Atomic The classes in the package basically use Unsafe Implemented wrapper class , The core operation is CAS Atomic manipulation About CAS compar ...

  5. Talk about high concurrency ( Twelve ) analysis java.util.concurrent.atomic.AtomicStampedReference See how to solve the source code CAS Of ABA problem

    Talk about high concurrency ( 11、 ... and ) Several spin lock implementations ( Children under five ) Used in java.util.concurrent.atomic.AtomicStampedReference Atomic variables point to the end of the work queue , Why use At ...

  6. Java Multithreading :CAS And java.util.concurrent.atomic

    Several concepts of lock Pessimistic locking Always assume the worst , Every time I get data, I think others will modify it , So it's locked when you take the data , Until the lock is released, no other thread is allowed to modify the data .Java In such as synchronized and reentrantLock That's it ...

  7. Java Concurrent — Atomic classes ,java.util.concurrent.atomic package ( Reprint )

    Atomic classes Java from JDK 1.5 Began to offer java.util.concurrent.atomic package ( hereinafter referred to as Atomic package ), This package The atomic operation class of provides a simple way to use . High performance . Thread safely updates a variable ...

  8. Java: Multithreading ,java.util.concurrent.atomic Baozhi AtomicInteger/AtomicLong usage

    1. background java.util.concurrent.atomic This bag is very practical , It solves the problem that we used to write a synchronization method to realize self growing fields . stay Java In language , Incremental operators (++) It's not atomic , It's just ...

  9. Java Atomic classes java.util.concurrent.atomic

    Java Atomic classes java.util.concurrent.atomic 1.i++ Why non thread safe i++ In fact, it is divided into 3 A step : obtain i Value , hold i+1, hold i+1 The result of the assignment to i If multithreading i++ ...

Random recommendation

  1. adopt Javascript obtain URL Parameters in (query string)

    We know ,"GET" In request , Usually put the parameter in URL Back , Such as this http://www.cnblogs.com/season-huang/index?param=yes&art ...

  2. git config Command to use

    1. git config brief introduction We know config It means configuration , that git config Command is right git Do some configuration . Configuration is usually written in the configuration file , that git Where is the configuration file for ? Interact , Let's ask the big one first ...

  3. T-SQL Inquire about 、 Modify data sheet

    T-SQL Modify table data INSERT sentence grammar : INSERT [TOP(expression) [PERCENT]] [INTO] { <object> | rowset_function ...

  4. java Environmental Science

    http://www.iyunv.com/thread-65867-1-1.html http://www.360doc.com/content/15/0525/19/21365845_4732029 ...

  5. [ original ]centos6.5 dhcpd The service has been failed state

    Because to deploy kickstart Automated systems distribute , So you need to configure dhcp The server , I've used the same machine for configuration before , No, there's no problem , But this time in the configuration dhcpd.conf After the document , When the service is restarted, it always prompts [ro ...

  6. How to adjust php The size of the app's upload attachment ?

    Jiuding holdings, a domestic private equity firm, has created APP, Send it as soon as you come  20 The address for collecting yuan in cash :http://jdb.jiudingcapital.com/phone.html Internal invitation code :C8E245J ( No invitation code , No cash to send ) Domestic private ...

  7. ACM_ Prime screening

    /* * Prime sieve method , Judgment is less than MAXN Is the number of prime numbers . *notprime It's a watch , by false It means a prime number ,true It means that it is not a prime number */ const int MAXN = 1000010; bool not ...

  8. MSIL Practical guide - Generate if...else... sentence

    if...else... Statement is a very important choice statement , Its generation generally needs ILGenerator Of DefineLabel Methods and MarkLabel Method , as well as Brtrue_S and Br_S Instructions . One .DefineLa ...

  9. linux install mysql5.7 edition

    Get ready first mysql5.7.17 Installation package , Install the package in  /data/software Under the table of contents Enter into /usr/local Under the table of contents , decompression mysql Installation package command :   cd /usr/local tar ...

  10. Big data development cognition --spark

    1. Spark rdd The generation process · Spark The task scheduling is divided into four steps 1RDD objects RDD The preparation stage of , organization RDD And RDD The dependency of the generated approximate RDD Of DAG chart ,DAG A graph is a directed ring graph . 2DAG s ...