AtomicInteger AtomicInteger,可实现原子化的操作,不需要加锁,他底层是通过CAS实现的,看下使用方式
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 public class AtomicIntegerDemo { static int i; static AtomicInteger j = new AtomicInteger(); public static void main (String[] args) { synchronizedAdd(); atomicAdd(); } private static void synchronizedAdd () { for (int k = 0 ; k < 10 ; k++) { new Thread() { @Override public void run () { synchronized (AtomicIntegerDemo.class) { System.out.println(++i); } } }.start(); } } private static void atomicAdd () { for (int k = 0 ; k < 10 ; k++) { new Thread() { @Override public void run () { System.out.println(j.incrementAndGet()); } }.start(); } } }
AtomicLong、AtomicBoolean、AtomicReference、LongAdder等类,都是不加锁的,效率比较高,在项目中可以多用下。
CAS
判断此时此刻是否是某个值,如果是,则修改,如果不是则重新查询一个最新的值,再次执行判断,这个操作叫做CAS,Compare and Set。
Atomic原子类底层核心的原理就是CAS,每次尝试修改的时候都先对比一下,有没有人修改过这个值,没有人修改就自己修改,如果有人修改过,就重新查出来最新的值,再次重复那个过程。
Unsafe Atomic原子类,底层是通过JDK提供的Unsafe类去实现的,这个类不能由用户来实例化的,我们在自己的代码也无法去使用它的方法,他会在源码检查类加载器类型,如果非Bootstrap classloader就会抛异常
1 2 3 4 5 6 7 8 9 10 @CallerSensitive public static Unsafe getUnsafe () { Class var0 = Reflection.getCallerClass(); if (!VM.isSystemDomainLoader(var0.getClassLoader())) { throw new SecurityException("Unsafe" ); } else { return theUnsafe; } }
然后他具体实现Unsafe封装了一些不安全的操作,例如CAS操作的代码,比较底层,下面开始看下源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 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); } } private volatile int value;
incrementAndGet源码,是如何完成原子操作的
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 public final int incrementAndGet () { return unsafe.getAndAddInt(this , valueOffset, 1 ) + 1 ; } public final int getAndAddInt (Object var1, long var2, int var4) { int var5; do { var5 = this .getIntVolatile(var1, var2); } while (!this .compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }
CAS底层,是通过CPU指令来完成的,对一小块内存进行加锁,保证他的原子性。
Atomic类CAS的三个缺点 ABA问题 比如本来这个值,一开始是A,后来变成了B,然后又变成了A,假设代码期望A就设置新的值,结果线程1A->B->,他将值设置了回去,然后线程2发现确实是A,然后就cas成功了,他无法识别值是否发生过变化。从 Java 1.5 开始,JDK 的 atomic 包里提供了一个类 AtomicStampedReference 来解决 ABA 问题,会比较两个值的引用是否一致,如果一致,才会设置新值。
无限循环问题 上面源码看了,cas在有无限循环在里面的,在高并发场景下,多线程频繁并发修改,可能有的线程就会循环很多次才能cas成功,这个问题在JDK 1.8引入了LongAdder来解决,他采用分段CAS的思路。
多变量原子问题 AtomicInteger,只保证了一个int变量的原子操作,多个变量可以用AtomicReference,将多个变量封装到一个对象里,然后他会检查这个对象的引用是不是一个。
LongAddr 针对无线循环的问题JDK 1.8引入了LongAdder,我们来看一下他是如何提升性能的。
LongAdder里面有一个cell数组,cell是在Striped64中的静态内部类,每个cell维护自己的value,AtomicInteger中仅维护一个全局的value,调用sum将所有cell的value和base相加就是最终的值。
这样就实现了分段CAS,减少并发
1 2 3 4 5 6 7 8 9 10 11 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; }