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; }
|

总结
本文系统讲解了相关技术要点。通过学习掌握核心概念和实践方法,提升技术能力。
关键要点
- 理解核心技术原理
- 掌握实际应用方法
- 学习最佳实践和注意事项
实践建议
- 结合实际项目练习
- 深入研究官方文档
- 持续学习和实践