原子性指单个操作不可中断,如AtomicInteger.incrementAndGet()通过CAS保证“读-改-写”原子执行;它无锁高效,但仅保障单变量原子性,多字段联动仍需synchronized或Lock。
原子性在Java并发中,指的是一个操作(比如 incrementAndGet())从开始到结束,不会被线程调度打断——它要么全部执行完,要么根本没开始。这不等于整个业务逻辑线程安全。例如 i++ 看似简单,实际是“读-改-写”三步,中间可能被其他线程插队,所以它**不是原子操作**;而 AtomicInteger.incrementAndGet() 底层用CAS+volatile保证这三步合为一个不可分割的动作。
AtomicInteger 而不用 synchronized?因为它是无锁的:不阻塞线程、没有上下文切换开销,适合高并发计数场景(如请求统计、ID生成)。但要注意:
synchronized 是悲观锁,一进就锁住临界区;AtomicInteger 是乐观锁,靠底层CPU的CAS指令反复尝试更新,失败就重试AtomicInteger),CAS失败率升高,可能反而比 LongAdder 慢得多synchronized 或 Lock
compareAndSet() 是原子类的底层引擎,也是最容易误用的地方这个方法签名是 boolean compareAndSet(int expect, int update),意思是:“如果当前值等于 expect,才把它设成 update,否则不动并返回 false”。它常被用来实现自旋逻辑,但新手常犯两个错:
际上失败时啥也没发生expect 写成固定值(比如硬编码 0),而不是动态读取的当前值,导致 CAS 总是失败compareAndSet() 时,没配合 get() 重读最新值,陷入死循环或跳过更新int current;
do {
current = counter.get();
} while (!counter.compareAndSet(current, current + 1));
AtomicReference 当“万能线程安全包装器”AtomicReference 只保证“引用本身”的更新是原子的,不保证它指向的对象内部状态线程安全。比如你用它存一个 ArrayList,多个线程调用 list.add() 依然会出问题——因为 add() 不是原子操作,而且 ArrayList 本身非线程安全。
CopyOnWriteArrayList),要么在业务层加同步AtomicStampedReference 或 AtomicMarkableReference,不能硬扛lazySet() 虽然性能略高,但只保证写不重排序、不保证立即对其他线程可见,慎用于关键状态位