核心是精准轻量加锁:按数据维度分片锁、用cas原子操作替代互斥锁、读写分离选合适并发容器,避免过度同步与锁粒度不当。

核心思路是:让写操作尽可能不互相阻塞,同时避免过度同步带来的开销。关键不在“加更多锁”,而在“让锁管得更准、更少、更轻”。
按数据维度拆分锁,避免全局串行
当多个线程写入的是逻辑上独立的数据(比如不同用户、不同订单号、不同商品ID),就不该共用一把锁。强行用 synchronized 方法或 ReentrantLock 保护整个容器,会把并发变成排队。
- 用 ConcurrentHashMap 替代 synchronized 的 HashMap 或 Hashtable:它对每个桶(bucket)或段(Segment,JDK 7)单独加锁,不同 key 的写入可并行
- 自定义分片锁:例如按 userId % N 分成 N 组,每组配一个 ReentrantLock,写操作只锁定对应分片,而不是整个计数器或缓存
- 避免在循环里反复加解锁:JVM 可能自动做锁粗化,但显式设计更可靠;若连续更新同一对象的多个字段,应把操作合并到一个临界区,而不是逐字段加锁
优先用无锁/乐观策略替代互斥锁
不是所有写操作都必须“抢锁”。对简单状态变更(如计数、标志位),CAS 类型的原子操作通常更快、更轻量。
- AtomicInteger / AtomicLong:适合累加、递增、设置标志等单变量操作,无上下文切换开销
- AtomicReference + compareAndSet:适用于需要原子更新对象引用的场景,比如替换整个配置对象
- ConcurrentLinkedQueue / LinkedBlockingQueue:生产者-消费者模型中,队列本身的 CAS 实现天然支持高并发写入,比手动加锁维护 List 更高效
读写分离:写少读多时明确区分锁语义
如果写操作频率远低于读操作(如配置缓存、用户画像快照),用互斥锁会让大量读请求被写线程拖慢。这时读写锁能显著提升吞吐。
- 用 ReentrantReadWriteLock:写锁独占,读锁共享,多个读线程可同时执行,写线程需等待所有读完成
- 注意写饥饿问题:若持续有读请求,写可能长期得不到机会;可考虑降级为普通锁,或限制读锁持有时间
- JDK 8+ 推荐 StampedLock:支持乐观读(validate + retry 模式),在极少写冲突时性能优于读写锁
结合业务特征选结构,不迷信“线程安全”标签
并发容器不是万能解药,要匹配真实访问模式:
- CopyOnWriteArrayList:仅适用于读极多、写极少(如监听器列表)、且写后不频繁遍历的场景;每次写都复制数组,写多时内存和 GC 压力大
- ConcurrentSkipListMap:需要排序且高并发写时,比 synchronized TreeMap + 手动锁更优
- 若写操作本身耗时较长(如含远程调用、文件 IO),锁粒度再细也难提升吞吐——应先异步化或批量聚合写入,再用锁保护本地缓冲
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











