Java 常见锁类型及适用场景详解
系统梳理了 Java 中的锁机制,涵盖内置锁 synchronized 与显式锁 Lock 接口。详细解析了可重入锁、乐观锁与悲观锁、公平与非公平锁、读写锁及锁升级原理。结合实战选型指南,针对简单互斥、高并发读写、任务排队等不同场景推荐合适的锁方案,帮助开发者优化并发性能与线程安全。

系统梳理了 Java 中的锁机制,涵盖内置锁 synchronized 与显式锁 Lock 接口。详细解析了可重入锁、乐观锁与悲观锁、公平与非公平锁、读写锁及锁升级原理。结合实战选型指南,针对简单互斥、高并发读写、任务排队等不同场景推荐合适的锁方案,帮助开发者优化并发性能与线程安全。

这是最核心的分类维度,直接决定锁的使用方式和核心能力。
Java 关键字,JVM 层面实现的隐式锁(无需手动释放),是最基础、使用最广泛的锁。JDK1.6 后引入「锁升级」机制,性能大幅提升。
Mark Word + 监视器锁(ObjectMonitor);public class SynchronizedDemo {
// 1. 实例方法锁(对象锁):锁当前实例对象
public synchronized void objectLock() {
System.out.println(Thread.currentThread().getName() + "获取对象锁");
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
}
// 2. 静态方法锁(类锁):锁当前类的 Class 对象
public static synchronized void classLock() {
System.out.println(Thread.currentThread().getName() + "获取类锁");
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
}
// 3. 代码块锁:自定义锁对象(灵活度最高)
private final Object lockObj = new Object();
public void blockLock() {
synchronized (lockObj) {
System.out.println(Thread.currentThread().getName() + "获取代码块锁");
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
}
}
public static void main(String[] args) {
SynchronizedDemo demo = new SynchronizedDemo();
// 竞争同一对象锁,串行执行
new Thread(demo::objectLock, "线程 1").start();
new Thread(demo::objectLock, "线程 2").start();
}
}
JUC 包下 java.util.concurrent.locks.Lock 接口的实现类,手动加锁 / 释放锁(需在 finally 中释放,避免死锁),是 synchronized 的补充和增强。
| 实现类 | 核心特性 |
|---|---|
| ReentrantLock | 可重入、支持公平 / 非公平、可中断、超时获取锁 |
| ReentrantReadWriteLock | 读写分离(读共享、写独占)、可重入 |
| StampedLock | 支持乐观读、读写锁、写锁,性能优于读写锁 |
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockDemo {
// 公平锁(按请求顺序获取),默认非公平锁(性能更高)
private static final ReentrantLock lock = new ReentrantLock(true);
public static void doTask() {
// 1. 加锁(可替换为 lockInterruptibly():可中断锁)
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "获取锁");
// 模拟业务操作
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断状态
} finally {
// 2. 释放锁(必须放 finally,否则死锁)
if (lock.isHeldByCurrentThread()) {
lock.unlock();
System.out.println(Thread.currentThread().getName() + "释放锁");
}
}
}
public static void main(String[] args) {
new Thread(ReentrantLockDemo::doTask, "线程 A").start();
new Thread(ReentrantLockDemo::doTask, "线程 B").start();
}
}
基于锁的行为和并发特性分类,帮你理解锁的底层逻辑和适用场景。
| 类型 | 定义 | 示例 | 适用场景 |
|---|---|---|---|
| 可重入锁 | 同一线程可多次获取同一把锁,不会死锁 | synchronized、ReentrantLock | 所有业务场景(递归调用、同一线程多次操作共享资源) |
| 不可重入锁 | 同一线程多次获取同一锁会死锁 | 自定义简单自旋锁(未处理重入) | 极少使用(仅严格限制锁获取次数的特殊场景) |
public class ReentrantDemo {
public synchronized void outer() {
System.out.println("外层方法获取锁");
inner(); // 同一线程再次获取同一锁,无死锁
}
public synchronized void inner() {
System.out.println("内层方法获取锁");
}
public static void main(String[] args) {
new ReentrantDemo().outer(); // 正常执行,无死锁
}
}
这是并发设计思想的分类,而非具体锁实现。
| 类型 | 核心思想 | 实现方式 | 适用场景 |
|---|---|---|---|
| 悲观锁 | 假设必有竞争,先锁后执行 | synchronized、ReentrantLock | 高冲突、写多读少(如库存扣减、转账) |
| 乐观锁 | 假设无竞争,先执行后检测 | CAS(Atomic 类)、版本号 | 低冲突、读多写少(如计数器、缓存更新) |
import java.util.concurrent.atomic.AtomicInteger;
public class OptimisticLockDemo {
// CAS 是乐观锁的核心实现
private static final AtomicInteger count = new AtomicInteger(0);
// 原子自增(无锁,冲突时重试)
public static void increment() {
count.incrementAndGet();
}
public static void main(String[] args) throws InterruptedException {
Runnable task = () -> {
for (int i = 0; i < 1000; i++) increment();
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("最终计数:" + count.get()); // 2000(线程安全)
}
}
| 类型 | 定义 | 示例 | 适用场景 |
|---|---|---|---|
| 公平锁 | 按请求顺序获取锁,先到先得 | ReentrantLock(true) | 对公平性要求高(如任务排队、避免线程饥饿) |
| 非公平锁 | 不按顺序,线程可插队获取锁 | synchronized、ReentrantLock() | 大部分场景(优先性能,容忍轻微饥饿) |
将锁拆分为「读锁(共享锁)」和「写锁(独占锁)」,核心规则:
读多写少的场景(如缓存、配置读取、商品详情页、数据查询),相比普通独占锁,能大幅提升读并发效率。
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockDemo {
private static final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private static final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
private static final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
private static int cacheData = 0;
// 模拟缓存数据
// 读操作(共享锁,多线程同时执行)
public static void readCache() {
readLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "读取缓存:" + cacheData);
Thread.sleep(200); // 模拟读耗时
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
readLock.unlock();
}
}
// 写操作(独占锁,串行执行)
public static void updateCache(int newData) {
writeLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "更新缓存:" + newData);
cacheData = newData;
Thread.sleep(200); // 模拟写耗时
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
writeLock.unlock();
}
}
public static void main(String[] args) {
// 5 个读线程(可同时执行,并发效率高)
for (int i = 0; i < 5; i++) {
new Thread(ReadWriteLockDemo::readCache, "读线程" + i).start();
}
// 1 个写线程(独占,所有读线程等待)
new Thread(() -> updateCache(100), "写线程").start();
}
}
JDK1.6 为优化 synchronized 引入的自适应锁机制,锁级别从低到高升级(不可逆),适配不同并发场景:
| 锁类型 | 核心特点 | 适用场景 |
|---|---|---|
| 偏向锁 | 锁偏向第一个线程,无竞争时零开销 | 单线程执行同步代码(如初始化资源) |
| 轻量级锁 | 多线程交替竞争,CAS 自旋获取锁 | 少量线程(2-3 个)交替执行 |
| 重量级锁 | 多线程激烈竞争,线程阻塞(OS 层面) | 大量线程同时竞争锁 |
| 类型 | 定义 | 示例 | 适用场景 |
|---|---|---|---|
| 自旋锁 | 获取锁失败时循环重试(自旋),不阻塞 | CAS、synchronized 轻量级锁 | 锁持有时间短、低冲突(如简单变量更新) |
| 阻塞锁 | 获取锁失败时线程阻塞,释放 CPU | synchronized 重量级锁、ReentrantLock | 锁持有时间长、高冲突(如复杂业务逻辑) |
将数据拆分为多个「段(Segment)」,每个段独立加锁,不同段的操作互不阻塞,并发度 = 段数(默认 16)。
JDK1.7 的 ConcurrentHashMap(JDK1.8 后用 CAS+Synchronized 替代),适用于高并发读写 Map 的场景。
| 业务场景 | 推荐锁类型 | 选型原因 |
|---|---|---|
| 简单互斥、代码简洁 | synchronized | 隐式锁,无需手动释放,JVM 优化优异 |
| 可中断 / 超时 / 公平锁 | ReentrantLock | 支持灵活的锁控制特性 |
| 读多写少(缓存 / 查询) | ReentrantReadWriteLock/StampedLock | 读共享,大幅提升读并发效率 |
| 低冲突、简单变量更新 | CAS(AtomicInteger/AtomicLong) | 无锁,性能最高,避免自旋消耗 |
| 高冲突、写多读少(转账) | synchronized/ReentrantLock | 悲观锁,避免高冲突下的 CAS 自旋 CPU 开销 |
| 公平性要求高(任务排队) | ReentrantLock(true) | 按请求顺序获取锁,避免线程饥饿 |
| 高并发 Map 操作 | ConcurrentHashMap | JDK1.8 用 CAS+Synchronized,兼顾性能和安全性 |

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online