getAndUpdate()返回旧值,基于CAS循环执行无副作用、幂等的函数式更新,适用于条件更新、状态机跃迁、统计聚合等场景,需避免闭包修改、非幂等操作及长耗时计算。

原子类的 getAndUpdate() 方法允许你基于当前值执行一个确定性的更新操作,并返回更新前的旧值。它接收一个 UnaryOperator<t></t>(即函数式接口 T → T),让你能用纯函数方式表达“读取当前值 → 计算新值 → 原子写入”的逻辑,避免手动加锁或循环重试。
核心机制:CAS 循环 + 函数式计算
getAndUpdate() 底层依赖 CAS(Compare-And-Swap)自旋,不是简单地“读一次、算一次、写一次”。它会:
- 读取当前值
current - 调用你传入的函数
fn.apply(current)得到next - 尝试用 CAS 将值从
current更新为next - 若失败(期间被其他线程修改),则重试:重新读取最新值,再次计算,再 CAS
这意味着你的函数必须是无副作用、幂等、快速完成的——不能依赖外部状态、不能阻塞、不能抛出受检异常(否则需包装为 RuntimeException)。
适用典型场景:非简单加减的原子更新
当 incrementAndGet() 或 addAndGet() 不够用时,getAndUpdate() 就派上用场。例如:
-
带条件的更新:当前值小于阈值才翻倍,否则归零
atomicInteger.getAndUpdate(v -> v -
状态机跃迁:用整数编码状态(如 0=INIT, 1=RUNNING, 2=STOPPED),实现安全的状态流转
status.getAndUpdate(s -> s == 0 ? 1 : s); // 仅允许从 INIT → RUNNING -
统计聚合:维护最小值,每次用新值和当前最小值比较更新
minValue.getAndUpdate(v -> Math.min(v, newValue));(注意:这里newValue需在闭包中捕获且不变)
与 updateAndGet()、accumulateAndGet() 的关键区别
别混淆这三个方法:
-
getAndUpdate(fn):返回旧值,适合需要“先拿到旧值做判断/记录”再更新的逻辑 -
updateAndGet(fn):返回新值,语义更贴近“更新后立刻要用结果” -
accumulateAndGet(x, binOp):接收一个二元操作(如Integer::max),等价于getAndUpdate(v -> binOp.apply(v, x)),专为“用外部值参与运算”优化,代码更简洁
选哪个取决于你关心的是旧值、新值,还是想省略闭包捕获外部变量的样板代码。
实战提醒:避免常见陷阱
使用时要注意几个易错点:
-
函数内不要修改外部变量:闭包引用的变量必须是 final 或事实 final;若需累积中间结果,应把状态封装进原子变量本身(如用
AtomicReference<mystate></mystate>) - 不保证函数只执行一次:因 CAS 可能失败重试,函数可能被多次调用,务必确保幂等性(比如不要在函数里发 HTTP 请求或写日志)
-
避免长耗时计算:自旋期间会持续占用 CPU,且增加 CAS 冲突概率;复杂逻辑建议先在外部预计算,再用
compareAndSet()手动控制 -
类型匹配要小心:如
AtomicLong对应LongUnaryOperator,不是UnaryOperator<long></long>(虽然 lambda 写法一样,但编译器推导依赖函数式接口定义)

















