ReentrantLock 可替代 synchronized 实现细粒度锁控制,支持超时、中断和尝试获取;分段锁、无锁原子类(如 LongAdder)、延迟初始化与 Copy-On-Write 等策略可减少竞争。

用 ReentrantLock 替代 synchronized 做细粒度控制
synchronized 是隐式锁,作用范围固定(方法或代码块),且无法中断、无法超时、无法尝试获取。当多个线程频繁争抢同一把锁时,等待队列会堆积,响应变慢。
改用 ReentrantLock 可以显式控制加锁行为,比如用 tryLock(long, TimeUnit) 设置最大等待时间,避免无限阻塞;用 lockInterruptibly() 支持线程中断,防止死等。
- 只在真正共享写操作的临界区加锁,读多写少场景优先考虑
StampedLock或ReadWriteLock - 避免在锁内做 I/O、远程调用、长循环等耗时操作
- 锁对象尽量私有、不可变,别用
this或公共类对象(如String.class)作锁,否则易被外部误锁
把大锁拆成多个小锁:分段锁与对象锁分离
典型例子是 ConcurrentHashMap 的分段机制——它不锁整个 map,而是按 hash 槽位划分成 16(或更多)个 Segment(Java 8+ 改为 Node 数组 + CAS + synchronized 单桶),让不同 key 的写操作大概率落在不同桶里,互不干扰。
你自己设计缓存或计数器时也可以模仿:比如用 Map 替代一个全局 AtomicLong,再按业务 ID 取模路由到不同原子变量上。
立即学习“Java免费学习笔记(深入)”;
- 锁粒度不是越小越好,要考虑内存开销和哈希冲突概率
- 避免“锁倾斜”:某些分段被高频访问(如 id % 16 == 0 的桶),导致实际仍串行化
- 若用数组分段,建议长度取 2 的幂,方便用位运算替代取模提升性能
用无锁结构替代锁:Atomic 类与 VarHandle
对单个变量的简单读-改-写(如计数、状态标记),优先用 AtomicInteger、AtomicBoolean 等。它们底层基于 CPU 的 CAS 指令,没有线程挂起/唤醒开销,吞吐更高。
Java 9+ 推荐用 VarHandle 替代 Unsafe,它提供更安全、标准化的原子访问能力,支持 compareAndSet、getAndAdd 等操作,且能跨 JVM 实现保持语义一致。
-
AtomicInteger的incrementAndGet()在高竞争下可能自旋多次,不如直接用LongAdder(分段累加,最终合并) - 不要滥用
AtomicReference包裹复杂对象——CAS 失败重试成本高,且对象内部状态变更仍需额外同步 -
VarHandle需通过MethodHandles.privateLookupIn获取,注意模块可见性限制(尤其 Java 17+ 强模块化后)
减少锁持有时间:延迟初始化 + 不可变对象 + Copy-On-Write
锁竞争的本质是「同时想改同一份数据」。如果能把「改」的动作推迟、隔离或消除,自然就消除了锁需求。
例如:CopyOnWriteArrayList 适用于读远多于写的场景,每次写都复制新数组,读完全无锁;又如用 final 字段 + 构造器一次性初始化对象,后续只读不改,彻底规避同步。
-
Double-Checked Locking写法必须给字段加volatile,否则可能因指令重排序导致其他线程看到未构造完成的对象 -
CopyOnWrite结构写操作内存开销大,不适合频繁修改或大数据量 - 考虑用
ImmutableList(Guava)或List.copyOf()(Java 10+)代替手动拷贝,语义更清晰且有运行时保护
JMH 测真实吞吐,用 jstack 抓锁等待栈,用 Arthas 动态观察 ReentrantLock 的排队长度——数据比直觉可靠。









