Java JUC 锁与原子类

java.util.concurrent 中的显式锁与原子类:相对 synchronized 的能力边界与适用场景。

#type / concept #status / growing #tech / dev #resource / java

[!info] 关联笔记

Java JUC 锁与原子类

这个概念为什么出现

synchronized 简洁,但缺少超时获取、可中断获取、多条件队列等能力。java.util.concurrent.locks 与原子类提供更细控制与无锁算法基础(CAS)。

[!abstract] 一句话理解 ReentrantLock 等提供显式加解锁与高级特性;Atomic* 用 CAS 更新单变量;选它们是因为需求超出内置锁或单变量热点更新。

最小可运行示例

场景:抢券用原子计数;复杂临界区用 ReentrantLock 超时

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

public class CouponRace {
    private final AtomicInteger remaining = new AtomicInteger(1);
    private final ReentrantLock lock = new ReentrantLock();

    boolean tryTakeAtomic() {
        while (true) {
            int cur = remaining.get();
            if (cur <= 0) return false;
            if (remaining.compareAndSet(cur, cur - 1)) return true;
        }
    }

    boolean tryCriticalWork() throws InterruptedException {
        if (lock.tryLock(50, TimeUnit.MILLISECONDS)) {
            try {
                return true; // 模拟临界区
            } finally {
                lock.unlock();
            }
        }
        return false;
    }

    public static void main(String[] args) throws Exception {
        CouponRace r = new CouponRace();
        System.out.println(r.tryTakeAtomic());
        System.out.println(r.tryTakeAtomic());
        System.out.println(r.tryCriticalWork());
    }
}

建议运行:

javac CouponRace.java && java CouponRace

期望输出:

true
false
true

结合场景再看三个关注点

  1. CAS 循环处理竞争。
  2. unlock 必须在 finally
  3. 超时锁避免死等。

核心概念与准确模型

1. ReentrantLock

  • 可重入
  • 公平/非公平
  • lockInterruptibly / tryLock
  • Condition

2. 读写锁

  • ReadWriteLock:读多写少场景(先测量)

3. 原子类

  • AtomicInteger/AtomicReference/LongAdder
  • 单变量更新;复杂不变量仍要锁或无锁结构

边界情况与反直觉行为

  1. 忘记 unlock → 永久阻塞。
  2. CAS ABA 问题(需要时用 AtomicStampedReference)。
  3. 公平锁吞吐可能更差。

常见误区

[!warning] 常见误区:所有地方替换为 ReentrantLock 无额外需求时 synchronized 更简单;可读性也是正确性的一部分。

工程实践

  1. 锁对象私有。
  2. 热点计数考虑 LongAdder。
  3. 与业务事务边界对齐,避免锁跨越远程调用。
  4. 死锁诊断用线程转储。

本节总结

  • 显式锁=更多控制
  • 原子类=单变量 CAS
  • 简单场景不炫技

自测题

  1. 何时用 tryLock 超时?
  2. AtomicInteger 能否保护“扣库存并记日志两步不变量”?
参考答案
  1. 避免死等、实现降级快速失败。
  2. 不能单独保证多步骤不变量,需要更高层同步/事务设计。

延伸阅读与资料来源

资料类型支撑内容
java.util.concurrent.locksAPI
Atomic variables tutorial教程原子变量
创建于 2026/7/15 更新于 2026/7/15