当前位置: 首页 > news >正文

Java中常见的锁synchronized、ReentrantLock、ReentrantReadWriteLock、StampedLock

在Java中,锁是实现多线程同步的核心机制。不同的锁适用于不同的场景,理解其实现原理和使用方法对优化性能和避免并发问题至关重要。


一、隐式锁:synchronized 关键字

实现原理
  • 基于对象监视器(Monitor):每个Java对象都有一个内置的监视器锁(monitor lock),通过 synchronized 关键字获取。
  • 锁升级机制(JVM优化):
    • 偏向锁:无竞争时,标记线程ID,避免CAS操作。
    • 轻量级锁:通过CAS竞争锁,失败后升级为重量级锁。
    • 重量级锁:通过操作系统互斥量(mutex)实现线程阻塞。
使用方法
// 1. 同步代码块
synchronized (obj) { // 临界区代码
}// 2. 同步实例方法
public synchronized void method() { }// 3. 同步静态方法
public static synchronized void method() { }
适用场景
  • 简单同步需求:无需复杂锁功能的场景(如可中断、超时等)。
  • 代码简洁性优先:自动释放锁,避免忘记解锁的风险。

二、显式锁:ReentrantLock

实现原理
  • 基于AQS(AbstractQueuedSynchronizer)
    • 通过 state 变量(CAS操作)记录锁状态。
    • 使用CLH队列管理等待线程。
  • 支持公平性:可选择公平锁(按排队顺序获取)或非公平锁(插队竞争)。
使用方法
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {// 临界区代码
} finally {lock.unlock(); // 必须手动释放
}// 高级功能示例:尝试获取锁
if (lock.tryLock(1, TimeUnit.SECONDS)) {try { /* ... */ } finally { lock.unlock(); }
}
适用场景
  • 复杂锁需求:需要可中断、超时、公平性等特性。
  • 细粒度控制:如跨方法加锁解锁(synchronized 只能在代码块内)。

三、读写锁:ReentrantReadWriteLock

实现原理
  • 分离读锁(共享)和写锁(独占)
    • 读锁允许多线程并发读,写锁独占。
    • AQS的 state 高16位记录读锁,低16位记录写锁。
使用方法
ReadWriteLock rwLock = new ReentrantReadWriteLock();
Lock readLock = rwLock.readLock();
Lock writeLock = rwLock.writeLock();// 读操作
readLock.lock();
try { /* 读数据 */ } finally { readLock.unlock(); }// 写操作
writeLock.lock();
try { /* 写数据 */ } finally { writeLock.unlock(); }
适用场景
  • 读多写少:如缓存系统、高频查询场景。
  • 数据一致性要求:写操作需要互斥,读操作可并发。

四、乐观锁:StampedLock(Java 8+)

实现原理
  • 基于票据(Stamp)的锁机制
    • 支持三种模式:写锁、悲观读锁、乐观读。
    • 乐观读不阻塞写操作,通过验证Stamp判断数据一致性。
使用方法
StampedLock stampedLock = new StampedLock();// 乐观读
long stamp = stampedLock.tryOptimisticRead();
// 读取数据
if (!stampedLock.validate(stamp)) {// 数据被修改,升级为悲观读锁stamp = stampedLock.readLock();try { /* 重新读取数据 */ } finally { stampedLock.unlockRead(stamp); }
}// 写锁
long stamp = stampedLock.writeLock();
try { /* 写数据 */ } finally { stampedLock.unlockWrite(stamp); }
适用场景
  • 读多写少且容忍数据不一致:如统计、日志处理。
  • 极高性能需求:乐观读避免锁竞争,但需处理验证逻辑。

五、其他锁机制

1. Condition 条件变量
  • ReentrantLock 配合使用,实现线程间协作(类似 wait/notify)。
  • 典型场景:生产者-消费者模型。
2. 分布式锁
  • 如基于Redis的 Redisson 或ZooKeeper实现。
  • 适用场景:跨JVM或分布式系统同步。

六、锁的选择与性能优化

锁对比表
锁类型特性性能适用场景
synchronized自动释放,非公平锁低竞争时高效简单同步需求
ReentrantLock可中断、超时、公平锁高竞争时高效复杂锁需求
ReadWriteLock读写分离读多写少高效缓存、查询系统
StampedLock乐观读,支持锁升级极高并发读多写少,容忍数据不一致
最佳实践
  1. 减少锁粒度:缩小临界区范围。
  2. 避免嵌套锁:防止死锁(如按固定顺序获取锁)。
  3. 监控锁竞争:使用JProfiler或JStack分析锁状态。

七、总结

  • 简单场景优先选择 synchronized(JVM优化成熟)。
  • 复杂需求使用 ReentrantLockReadWriteLock
  • 极致性能考虑 StampedLock,但需谨慎处理数据一致性。

合理选择锁类型,结合性能测试和监控,是构建高效并发系统的关键。

http://www.xdnf.cn/news/29683.html

相关文章:

  • MainActivity与RecActivity之间的双向数据传递详解
  • 从 0~1 保姆级 详细版 PostgreSQL 数据库安装教程
  • 数据库备份-docker配置主从数据库
  • k8s安装kubeadm
  • 探索大语言模型(LLM):Transformer 与 BERT从原理到实践
  • 回溯算法(2):全排列问题
  • 基于DeepSeek与Excel的动态图表构建:技术融合与实践应用
  • WebSocket介绍
  • 二级评论列表-Java实现
  • 从零搭建微服务项目Pro(第6-2章——微服务鉴权模块SpringSecurity+JWT)
  • OCR技术与视觉模型技术的区别、应用及展望
  • Python语法系列博客 · 第7期[特殊字符] 列表推导式与字典推导式:更优雅地处理数据结构
  • 使用Redis实现实时排行榜
  • 【Easylive】​​Gateway模块 bootstrap.yml 解析
  • 点云数据处理开源C++方案
  • elementUI中MessageBox.confirm()默认不聚焦问题处理
  • Qt UDP 通信的详细实现步骤和示例代码
  • spring boot应用部署IIS
  • matlab论文图一的地形区域图的球形展示Version_1
  • 基于springboot的老年医疗保健系统
  • 【Matlab】中国东海阴影立体感地图
  • 【蓝桥杯 2025 省 A 扫地机器人】题解
  • Graham Scan算法求解二维凸包
  • 通过Xshell上传文件到Linux
  • Python:使用web框架Flask搭建网站
  • JS案例-Promise/A+ 规范的手写实现
  • 【厦门大学】DeepSeek大模型赋能政府数字化转型
  • OSPF实验
  • React-memo (useMemo, useCallback)
  • PG数据库推进医疗AI向量搜索优化路径研究(2025年3月修订版)