Atomic类通过CAS实现无锁原子性,依赖CPU底层指令保证“读-判-写”不可分割,适用于纯内存简单状态变更;不适用于复合操作、I/O或跨变量约束场景。
Atomic类(如AtomicInteger)的线程安全,根本不是加锁来的。它依赖CPU提供的底层原子指令——CAS(Compare-And-Swap),在硬件层面保证“读-判-写”三步不可分割。只要当前值等于预期值,就原子地更新为新值;否则失败并返回false,由调用方决定重试或放弃。
compareAndSet(int expect, int update)是核心方法,所有其他操作(如incrementAndGet())最终都基于它循环尝试synchronized块典型场景是「纯内存状态变更」且操作足够简单:计数器、开关标志、序列号生成、引用计数等。一旦涉及I/O、多变量协同、条件分支依赖共享状态,就该退回到锁或更高级并发结构。
AtomicInteger:likeCount.incrementAndGet()统计点赞数AtomicBoolean:running.compareAndSet(true, false)安全关闭轮询线程if (counter.get() > 100) counter.set(0) —— 这里存在竞态窗口,应改用getAndUpdate()或锁new AtomicInteger(-1)这种非零初始化很常见,别漏掉compareAndSet()返回false不是异常,而是明确告诉你“值已被别人改了”。这时候不能沉默,也不能粗暴重试无限循环(可能饿死CPU),得结合业务做合理兜底。
getAndUpdate()或updateAndGet()——它们内部已封装了CAS自旋逻辑,语义更清晰getAndAccumulate()配合IntBinaryOperator
lazySet()代替set():它不保证立即可见,但写入更快,适合发布状态标记(如done.lazySet(true))CAS会误认为没变。JDK提供了AtomicStampedReference带版本戳解决,但多数计数类场景无需考虑它只保单个变量的原子读写,不保复合操作、不保可见性传播、不保跨变量约束。比如两个AtomicInteger相加再存入第三个,这个“加+存”整体仍非原子。
a.set(1); b.set(2),线程2可能看到a==1 && b==0(因JVM和CPU重排序)AtomicRef
erence把多个字段包进一个不可变对象里整体更新int local = x.get() + y.get();比AtomicInteger local = new AtomicInteger(x.get() + y.get());干净得多真正容易被忽略的是:Atomic类只解决原子性,不自动解决可见性和有序性边界。哪怕用了AtomicInteger,如果在它之后立刻读一个普通int字段,那个读操作仍可能看不到最新值——该加volatile还得加,该同步代码块还得同步。