锁的核心作用是保证互斥性、可见性和有序性,解决竞态条件等问题;synchronized适合低并发简单场景,ReentrantLock提供中断、超时等高级控制,ReadWriteLock优化读多写少场景,原子类适用于冲突少的轻量更新。

锁的核心作用就三点:保证同一时间只有一个线程能操作共享资源(互斥性),让线程修改后的新值对其他线程可见(可见性),以及防止指令重排导致逻辑错乱(有序性)。这三者共同解决多线程下的竞态条件、缓存不一致和执行顺序异常问题。
内置锁(synchronized)适合什么场景
它像一把“自动钥匙”——加锁简单,不用管释放,JVM全包办。适合并发压力不大、逻辑清晰的同步需求。
- 工具类中的线程安全方法(如单例工厂、简单计数器)
- 电商库存扣减这类短临界区、低竞争的操作
- 不需要中断、超时、公平性等高级控制的场景
注意:别一上来就锁整个方法,优先用 synchronized(对象) 锁代码块,缩小粒度;JDK 1.6+ 已默认启用锁升级优化(偏向→轻量→重量),但 JDK 15 起偏向锁已被废弃,高版本更依赖轻量级自旋与系统级阻塞协同。
显式锁(ReentrantLock)强在哪
它是一把“可编程门锁”,功能全但得自己管开关。核心优势是可控性强。
立即学习“Java免费学习笔记(深入)”;
- 支持 lockInterruptibly() —— 线程等待锁时可被中断,避免无限挂起
- tryLock(long, TimeUnit) 可设超时,抢不到就放弃,防死锁或雪崩
- 构造时传 true 可启用公平模式,按排队顺序分发锁(适合防饥饿)
- 配合 Condition 实现精准唤醒(比如只通知消费者,不惊动生产者)
典型用法必须写在 try-finally 里:lock() 在 try 前,unlock() 固定放在 finally 块中,否则一旦异常抛出,锁就永远卡住。
读写分离场景用 ReadWriteLock
当读操作远多于写操作(比如配置中心、缓存元数据、用户权限快照),ReadWriteLock 就比单纯用 synchronized 或 ReentrantLock 高效得多。
- 读锁可并发:多个线程能同时持读锁,不互斥
- 写锁独占:写锁与读锁、写锁之间全部互斥
- 写锁可降级为读锁(但读锁不能升级为写锁)
注意:它不保证锁的公平性,默认是非公平的;若读多且写极少,还可考虑 Java 8 引入的 StampedLock —— 它支持“乐观读”,失败再转悲观,吞吐更高,但使用稍复杂。
别忽略乐观锁和原子类
不是所有同步都靠“加锁”。对于简单变量(如 int、boolean、引用)的更新,CAS(Compare-And-Swap)类原子操作更轻量。
- AtomicInteger.incrementAndGet() 替代 synchronized++,无锁、无阻塞
- LongAdder 在高并发累加场景下比 AtomicInteger 更优(分段累加+合并)
- 版本号 + CAS(如数据库 update ... where version = ?)属于应用层乐观锁,适合业务逻辑允许重试的场景
本质上,乐观锁适用于“冲突少、重试代价低”的读多写少业务,比如点赞数、浏览量统计。
基本上就这些。选锁不是比谁更“高级”,而是看场景要什么:要省心选 synchronized,要灵活选 ReentrantLock,要读性能选 ReadWriteLock,要极致轻量选原子类。不复杂但容易忽略的是——锁的粒度、持有时间、是否可中断,往往比锁类型本身更能决定系统表现。










