AtomicInteger source code analysis

  Java 1.5 from the start to provide non-blocking thread-safe packaging, such as AtomicInteger, AtomicLong etc. These achieve similar, here to AtomicInteger example.

Unsafe operation are based AtomicInteger class, which is a utility class used inside JDK provide hardware-level atomic operations related introduction stamp . The following code from JDK1.8.
  First look at the member variables:

. 1  Private  static  Final the Unsafe the unsafe = Unsafe.getUnsafe ();
 2  // value of the memory offset 
. 3  Private  static  Final  Long valueOffset;
 . 4  
. 5  static {
 . 6      the try {
 . 7          // Get the offset value memory 
. 8          valueOffset = the unsafe .objectFieldOffset
 . 9              (of AtomicInteger. class .getDeclaredField ( "value" ));
 10      } the catch (Exception EX) { the throw  new new Error (EX);}
 . 11 }
12 //
13 private volatile int value;

   value is a specific value, which is a volatile variable to ensure the visibility of memory, and the other valueOffset a variable degree of importance and value is equivalent to a variable, as long as understand the role of these two variables, AtomicInteger basically understand , and why this specific variables, see the relevant methods introduced.

  Method AtomicInteger class all based on Unsafe, the role of related methods check out the links given at the beginning of their own or google, here only some way to explain the role and value of valueOffset.

1 public final int get() {
2     return value;
3 }
5 public final void set(int newValue) {
6     value = newValue;
7 }

  This is a basic two methods to set and get the value. It should be noted that, although the value is volatile variables, but this set () method is not to become safe, to be a test.

 1 public class AtomicIntegerExample implements Runnable {
 2     private static AtomicInteger atomicInteger = new AtomicInteger();
 3     private static CyclicBarrier barrier = new CyclicBarrier(2);
 4     private Integer a;
 6     private AtomicIntegerExample(Integer a) {
 7         this.a = a;
 8     }
10     public static void main(String[] args) {
11         AtomicIntegerExample example1 = new AtomicIntegerExample(1);
12         AtomicIntegerExample example2 = new AtomicIntegerExample(2);
13         int b = 0;
14         int count = 0;
15         while (count < 10) {
16             Thread thread1 = new Thread(example1);
17             Thread thread2 = new Thread(example2);
18             thread1.start();
19             thread2.start();
20             try {
21                 thread1.join();
22                 thread2.join();
23             } catch (InterruptedException e) {
24                 e.printStackTrace();
25             }
26             if (b != atomicInteger.get()) {
27                 System.out.print(atomicInteger+" ");
28                 b = atomicInteger.get();
29                 count++;
30             }
31             barrier.reset();
32         }
33     }
35     @Override
36     public void run() {
37         try {
38             barrier.await();
39         } catch (InterruptedException e) {
40             e.printStackTrace();
41         } catch (BrokenBarrierException e) {
42             e.printStackTrace();
43         }
44         //线程不安全
45         atomicInteger.set(a);
46     }
47 }

   The output is 2,121,212,121.

  Due to volatile variable visibility only guarantee, so in some cases still need to lock to ensure atomicity, in the following cases can be unlocked using volatile variables to ensure atomicity:  

  1) the operation result does not depend on the current value of the variable, or to ensure that only a single thread can update the value of the variable.

  2) variable does not need to participate in other state variables constant constraint

  Here set method, although satisfied the first point, but in addition there is a newsValue value in the expression, the second point is not satisfied, the specific check my previous blog understanding of java JVM memory model . In addition to the get and set methods, all methods all use valueOffset, The reason, I understand that because volatile prohibit JVM related to optimize memory reordering. So let's look at other ways:

1 public final int getAndSet(int newValue) {
2     return unsafe.getAndSetInt(this, valueOffset, newValue);
3 }

  The method is to get the current value and then set the value to newValue, look Unsafe methods:

. 1  public  Final  int getAndSetInt (Object var1, Long var2, int var4) {
 2      int var5;
 . 3      do {
 . 4          var5 = the this .getIntVolatile (var1, var2); // address atoms to obtain the address plus the offset var1 var2 the value of the variable 
. 5      } the while (! the this .compareAndSwapInt (var1, var2, var5, var4)); // spin CAS operation successfully return value to true to var4 
. 6  
. 7      return var5; // return the old value 
8 }

  This can be seen from the above method uses optimistic locking mechanism, in fact Unsafe optimistic locking is used.
  lazySet difference set method and packaging method is atomic most mentioned problem, using a volatile variable set assignment to ensure visibility but will lose some performance (due to the added volatile write barrier and store-load prohibition reordering), using lazySet Unsafe method is putOrderedInt class, JDK official explanation of it is, there will be the instruction following putOrderedInt reordering methods, so its visibility can not be guaranteed, but the memory barrier putOrderedInt use (store-store) using the ratio of volatile memory barriers (store-load) better performance, so lazySet way is to ensure that the performance but lose visibility.
  To summarize, the class of AtomicInteger Unsafe based implementation in which a specific value of the stored value, the main role is to ensure the visibility of the use, and is stored valueOffset memory offset value, when the use of class Unsafe the variables are used in the main role is to guarantee the performance.


Guess you like