← [ BACK_TO_NOTES ]

Java JUC 锁与原子类

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

#concept #growing #dev #java

[!info] related notes

Java JUC 锁与原子类

这个概念为什么出现

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

[!abstract] 一句话理解 ReentrantLock 等提供显式加解锁与高级特性;原子类提供单变量操作的原子性,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;tryLock 返回 false 时不能解锁。\
  3. 超时只限制获取锁的等待,不限制进入临界区后的工作耗时。

核心概念与准确模型

1. ReentrantLock

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

2. 读写锁

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

3. 原子类

  • AtomicInteger/AtomicReference 提供原子读写与 CAS 等操作。
  • LongAdder 面向高并发统计,sum 不是并发更新下的原子快照,不能用“sum 后判断再递减”实现限额抢券。\
  • 单变量更新;复杂不变量仍要锁或无锁结构

边界情况与反直觉行为

  1. 忘记 unlock → 永久阻塞。
  2. CAS ABA 问题(需要时用 AtomicStampedReference)。
  3. 公平锁吞吐可能更差,也不保证线程调度公平;ReentrantLock 的无参 tryLock 不遵守公平排队策略。
  4. updateAndGet 等函数式原子更新在竞争时可能重复执行更新函数,函数应无副作用。\

常见误区

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

工程实践

  1. 锁对象私有。
  2. 统计性热点计数可考虑 LongAdder;需要精确读改写或 CAS 条件更新时用合适的原子变量/锁。\
  3. 与业务事务边界对齐,避免锁跨越远程调用。
  4. 死锁诊断用线程转储。

本节总结

  • 显式锁=更多控制
  • 原子变量提供单变量操作保证,不能自动保护多个字段或外部副作用\
  • 简单场景不炫技

自测题

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

延伸阅读与资料来源

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

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本