并发环境下计数
 
需求 
 
count++表面上看只有一个操作,其实在底层是有3个操作,读出-自增-写回 
这3个操作在并发环境下会被打断,这种非原子操作造成了结果错误 
这个原子操作问题可以被java.util.concurrent.atomic包通过CAS方式解决
数值类型原子性 
 
以AtomicInteger实现为例,对int进行CAS原子化包装 
静态初始化块初始化了unsafe对象,以及获取value属性的内存位置偏移值,为CAS做准备
AtomicInteger.java 1 2 3 4 5 6 7 8 9 10 11 12 13 public  class  AtomicInteger  extends  Number  implements  java .io .Serializable   {         private  static  final  Unsafe unsafe = Unsafe.getUnsafe();     private  static  final  long  valueOffset;     static  {         try  {                          valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value" ));         } catch  (Exception ex) { throw  new  Error(ex); }     }      } 
 
被CAS操作的字段要使用volatile保证可见性,如果是long还可以保证多字节赋值完整性
AtomicInteger.java 1 2 3 4 5 6 7 8 9 private  volatile  int  value;public  final  int  get ()   {    return  value; } public  final  void  set (int  newValue)   {    value = newValue; } 
 
在原子操作方面,委派给Unsafe类实现相关功能 
针对写入操作,提供直接写入和CAS操作先比较再写入
AtomicInteger.java 1 2 3 4 5 6 7 public  final  int  getAndSet (int  newValue)   {    return  unsafe.getAndSetInt(this , valueOffset, newValue); } public  final  boolean  compareAndSet (int  expect, int  update)   {    return  unsafe.compareAndSwapInt(this , valueOffset, expect, update); } 
 
针对count++/count–这种先返回再增减的操作
AtomicInteger.java 1 2 3 4 5 6 7 8 9 10 11 public  final  int  getAndIncrement ()   {    return  unsafe.getAndAddInt(this , valueOffset, 1 ); } public  final  int  getAndDecrement ()   {    return  unsafe.getAndAddInt(this , valueOffset, -1 ); } public  final  int  getAndAdd (int  delta)   {    return  unsafe.getAndAddInt(this , valueOffset, delta); } 
 
针对++count/–count这种先增减再返回的操作,实际上和上面那组方法一样,底层上都是getAndAddInt实现
AtomicInteger.java 1 2 3 4 5 6 7 8 9 10 11 public  final  int  incrementAndGet ()   {    return  unsafe.getAndAddInt(this , valueOffset, 1 ) + 1 ; } public  final  int  decrementAndGet ()   {    return  unsafe.getAndAddInt(this , valueOffset, -1 ) - 1 ; } public  final  int  addAndGet (int  delta)   {    return  unsafe.getAndAddInt(this , valueOffset, delta) + delta; } 
 
对象类型原子性 
 
基本类型中的boolean,int,long可以分别由AtomicBoolean,AtomicInteger和AtomicLong提供原子操作 
如果是自定义的类,那么就需要AtomicReference负责,实现套路和上面基本一致,依然是volatile和unsafe协同实现 
不同的是这里采用了泛型支持自定义类型,并且没有数值型的增减操作
AtomicReference.java 1 2 3 4 5 6 7 8 9 10 11 12 13 public  class  AtomicReference <V > implements  java .io .Serializable   {    private  volatile  V value;          public  final  boolean  compareAndSet (V expect, V update)   {         return  unsafe.compareAndSwapObject(this , valueOffset, expect, update);     }     @SuppressWarnings ("unchecked" )     public  final  V getAndSet (V newValue)   {         return  (V)unsafe.getAndSetObject(this , valueOffset, newValue);     }      } 
 
CAS仅限对单个变量进行原子操作,如果同时操作多个变量,难以实现,可以考虑将多个变量作为一个整体组成一个对象,分散操作转变为一次整体操作,把旧的对象整体替换成新对象,效果上实现多变量原子操作
ABA问题 
 
CAS在比较时只能判断是不是相等,并一定能确认是不是被改变过。比如值从A改到B再改回A,如果CAS看到了A,它也不知道是否中间经历了B值。 
在基本类型上,因为只是一个数值,很多情况下值相等即可,改没改变无关紧要。然而和基本类型不同,引用型在比较时可能出现问题。 
按照普通的CAS逻辑,引用没变就认为对象没改过,但是实际上修改对象属性并不改变对象引用,CAS无法正确判断对象内部是否修改,这会导致更新丢失。
对象类型原子性和辅助标记 
 
既然单纯从对象引用无法判断是否修改,解决方案就是增加额外的判断内容,比如版本号。 
AtomicStampedReference内部除了对象引用reference,还绑定了一个数值stamp,形成Pair结构 
比较时单纯的对象引用比较是不够的,同时进行数值比较。
AtomicStampedReference.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public  class  AtomicStampedReference <V >  {    private  static  class  Pair <T >  {         final  T reference;         final  int  stamp;         private  Pair (T reference, int  stamp)   {             this .reference = reference;             this .stamp = stamp;         }         static  <T> Pair<T> of (T reference, int  stamp)   {             return  new  Pair<T>(reference, stamp);         }     }     private  volatile  Pair<V> pair;          public  boolean  compareAndSet (V expectedReference, V newReference, int  expectedStamp, int  newStamp)   {         Pair<V> current = pair;         return  expectedReference == current.reference && expectedStamp == current.stamp &&                          ((newReference == current.reference && newStamp == current.stamp) || casPair(current, Pair.of(newReference, newStamp)));     }     private  boolean  casPair (Pair<V> cmp, Pair<V> val)   {         return  UNSAFE.compareAndSwapObject(this , pairOffset, cmp, val);     }      } 
 
如果不想绑定数值,AtomicMarkableReference提供了绑定布尔值的结构,相当于一个简化版
AtomicMarkableReference.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public  class  AtomicMarkableReference <V >  {    private  static  class  Pair <T >  {         final  T reference;         final  boolean  mark;         private  Pair (T reference, boolean  mark)   {             this .reference = reference;             this .mark = mark;         }         static  <T> Pair<T> of (T reference, boolean  mark)   {             return  new  Pair<T>(reference, mark);         }     }     private  volatile  Pair<V> pair;      } 
 
数组原子性 
 
直接把数组当成一个引用,并不能保证每个数组元素的原子性 
原子包提供AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray三个版本
以AtomicIntegerArray为例,不出意外,底层是个int数组,但是不同的是没有volatile,而是一个final修饰,这是因为目标是提供操作数组元素的原子性,而不是改变数组引用本身 
每个操作都提供了数组索引,操作单个元素。这样单个元素就相当于AtomicInteger,可以进行各种操作
AtomicIntegerArray.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public  class  AtomicIntegerArray  implements  java .io .Serializable   {         private  final  int [] array;          public  AtomicIntegerArray (int [] array)   {                  this .array = array.clone();     }     public  final  void  set (int  i, int  newValue)   {         unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);     }     public  final  int  getAndSet (int  i, int  newValue)   {         return  unsafe.getAndSetInt(array, checkedByteOffset(i), newValue);     }     public  final  boolean  compareAndSet (int  i, int  expect, int  update)   {         return  compareAndSetRaw(checkedByteOffset(i), expect, update);     }          public  final  int  getAndIncrement (int  i)   {         return  getAndAdd(i, 1 );     }     public  final  int  getAndDecrement (int  i)   {         return  getAndAdd(i, -1 );     }      } 
 
对象属性原子性 
 
对象内可以包含一些volatile属性,为了保证单个属性可以进行原子操作,可以简单的把每个属性替换成原子对象版本 
原子包内还提供另外一种实现方式,基于反射构建的属性更新器静态工具类,提供AtomicIntegerFieldUpdater,AtomicLongFieldUpdater和AtomicReferenceFieldUpdater三个版本
属性更新器是由静态方法创建,提供对象类型,属性类型,属性名三个参数。更新器只和类型有关,和具体对象实例无关,可以被复用 
使用时传入操作对象和属性值即可,因为更新器已知该操作哪个属性
AtomicReferenceFieldUpdater.java 1 2 3 4 5 6 7 8 public  abstract  class  AtomicReferenceFieldUpdater <T ,V >  {    @CallerSensitive      public  static  <U,W> AtomicReferenceFieldUpdater<U,W> newUpdater (Class<U> tclass, Class<W> vclass, String fieldName)   {         return  new  AtomicReferenceFieldUpdaterImpl<U,W>(tclass, vclass, fieldName, Reflection.getCallerClass());     }          public  abstract  boolean  compareAndSet (T obj, V expect, V update)  ; } 
 
比如更新Sample类中的value字段
Sample 1 2 3 4 5 6 7 8 9 class  Sample  {    volatile  int  value = 0 ; } public  static  void  main (String[] args)   {    Sample s = new  Sample();     AtomicIntegerFieldUpdater<Sample> updater = AtomicIntegerFieldUpdater.newUpdater(Sample.calss, "value" );     updater.compareAndSet(s,0 ,1 ); } 
 
Adder类 
 
Java8新增的原子操作类,包括LongAdder和DoubleAdder两个版本。 
AtomicLong和LongAdder两者功能类似,都可以用来计数,但是在高竞争下,LongAdder性能更好 
性能区别在于实现原理不同,AtomicLong底层只维护一个变量,而LongAdder维护了一个动态大小的变量数组,分散了竞争
实现上LongAdder继承了Striped64,即把单一变量操作分散到变量数组的公共实现 
大体流程是各线程选择数组不同元素操作,尽可能避免竞争,取值时再对数组结果进行汇总。对外界透明,感觉在操作单一变量
LongAdder.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public  class  LongAdder  extends  Striped64  implements  Serializable   {         public  void  increment ()   {         add(1L );     }     public  void  decrement ()   {         add(-1L );     }          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);         }     }          public  long  longValue ()   {         return  sum();     }               public  long  sum ()   {         Cell[] as = cells; Cell a;         long  sum = base;         if  (as != null ) {             for  (int  i = 0 ; i < as.length; ++i) {                 if  ((a = as[i]) != null )                     sum += a.value;             }         }         return  sum;     }      }