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

Java并发编程:ReentrantReadWriteLock读写锁

前言

在Java并发编程中,锁机制是保证线程安全的重要手段。synchronizedReentrantLock都是排他锁,同一时刻只允许一个线程访问共享资源。但在实际业务场景中,读操作往往远多于写操作,如果多个读线程之间也要互相等待,会严重影响系统性能。

ReentrantReadWriteLock(读写锁)正是为了解决这个问题而设计的。它维护了一对锁:读锁写锁,通过读写分离的策略,大幅提升并发性能。


一、读写锁的核心特性

锁类型特性说明
读锁共享锁多个线程可同时持有读锁
写锁排他锁同一时刻只能有一个线程持有写锁

读写锁遵循以下基本原则:

  • 读-读共享:多个读线程可以同时执行

  • 写-写互斥:多个写线程不能同时执行

  • 读-写互斥:读操作和写操作不能同时进行


二、三种场景代码实战

2.1 读读共享

读锁是共享锁,多个线程可以同时获取读锁,互不阻塞。

public class ReadReadTest { public static void main(String[] args) { MyTask myTask = new MyTask(); new Thread(() -> myTask.read(), "t1").start(); new Thread(() -> myTask.read(), "t2").start(); } static class MyTask { private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void read() { try { lock.readLock().lock(); System.out.println(Thread.currentThread().getName() + " start"); Thread.sleep(10000); System.out.println(Thread.currentThread().getName() + " end"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.readLock().unlock(); } } } }

运行结果:

t1 start t2 start t1 end t2 end

可以看到,t1和t2几乎同时开始,读锁不互斥。

2.2 写写互斥

写锁是排他锁,同一时刻只能有一个线程持有写锁。

public class WriteWriteTest { public static void main(String[] args) { MyTask myTask = new MyTask(); new Thread(() -> myTask.write(), "t1").start(); new Thread(() -> myTask.write(), "t2").start(); } static class MyTask { private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void write() { try { lock.writeLock().lock(); System.out.println(Thread.currentThread().getName() + " start"); Thread.sleep(10000); System.out.println(Thread.currentThread().getName() + " end"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.writeLock().unlock(); } } } }

运行结果:

t1 start t1 end t2 start t2 end

t2必须等待t1释放写锁后才能执行,写锁互斥。

2.3 读写互斥

读写操作互斥,读操作进行时写操作必须等待,反之亦然。

public class ReadWriteTest { public static void main(String[] args) { MyTask myTask = new MyTask(); Thread t1 = new Thread(() -> myTask.read(), "t1"); Thread t2 = new Thread(() -> myTask.write(), "t2"); t1.start(); // 确保t1先获取读锁 Thread.sleep(2000); t2.start(); } static class MyTask { private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void read() { try { lock.readLock().lock(); System.out.println(Thread.currentThread().getName() + " start"); Thread.sleep(10000); System.out.println(Thread.currentThread().getName() + " end"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.readLock().unlock(); } } public void write() { try { lock.writeLock().lock(); System.out.println(Thread.currentThread().getName() + " start"); Thread.sleep(10000); System.out.println(Thread.currentThread().getName() + " end"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.writeLock().unlock(); } } } }

运行结果:

t1 start t1 end t2 start t2 end

t2必须等待t1读完才能开始写,读写互斥。


三、读写锁的适用场景

读写锁特别适合读多写少的业务场景:

场景是否适用原因
缓存系统✅ 非常适合大量读操作,偶尔更新
配置中心✅ 非常适合配置读取频繁,变更极少
计数器❌ 不适合读写比例接近1:1
账户转账❌ 不适合写操作频繁,锁竞争严重

四、注意事项

4.1 锁降级

ReentrantReadWriteLock支持锁降级:写锁可以降级为读锁,但读锁不能升级为写锁。

// 锁降级(允许) writeLock.lock(); readLock.lock(); // 写锁持有状态下获取读锁 writeLock.unlock(); // 仍然持有读锁 // 锁升级(不允许,会死锁) readLock.lock(); writeLock.lock(); // 线程永久阻塞!

5.2 公平性选择

与ReentrantLock一样,读写锁也支持公平/非公平模式:

  • 非公平模式(默认):吞吐量更高,但可能造成写线程饥饿

  • 公平模式:线程按请求顺序获取锁,避免饥饿

// 公平读写锁 ReentrantReadWriteLock fairLock = new ReentrantReadWriteLock(true);

5.3 重入特性

读写锁支持锁重入,但需要注意:

  • 读线程可以重复获取读锁

  • 写线程可以重复获取写锁,也可以获取读锁(锁降级)


六、总结

对比项ReentrantLockReentrantReadWriteLock
锁类型排他锁读写分离
读并发不并发并发
写并发不并发不并发
适用场景读写均衡读多写少

最佳实践:在读操作远多于写操作的场景下,优先考虑使用ReentrantReadWriteLock,它可以显著提升系统吞吐量,让并发性能得到质的飞跃。

http://www.jsqmd.com/news/878900/

相关文章:

  • LSLib:游戏资源逆向工程的架构级解决方案
  • 长期使用Taotoken Token Plan套餐在项目开发中的成本节省体感
  • 天际模组编排师:用LOOT主列表告别游戏崩溃的智能解决方案
  • Zotero文献去重插件:高效清理重复文献的完整解决方案
  • 辽宁省东港寄件省钱新思路!不用再跑门店比价,这些线上渠道寄全国划算又稳妥 - 时讯资讯
  • 大数据机器学习框架性能对比:从Spark MLlib到Scikit-learn的基准测试实践
  • next.js 开发中的水合(Hydration)问题
  • VSCode中R语言开发环境配置与使用完整教程
  • Mac Mouse Fix终极指南:让你的普通鼠标秒变专业级触控板
  • 新手必看,在Python项目中通过OpenAI兼容SDK调用Taotoken聚合API
  • 新版本Claude Desktop 无法使用 国产 deepseek v4 模型
  • 仅剩最后47套!《ChatGPT脑筋急转弯生成军规手册》PDF+127个经A/B测试验证的高互动Prompt模板(含儿童/职场/银发三版适配)
  • 基于符号传递熵与共识嵌套交叉验证的电竞选手技能评估模型
  • 开源入门踩坑实录:新手必避的10个坑,每个都让我熬到凌晨三点
  • 使用Taotoken后我的月度大模型API用量与成本变得清晰可见
  • 对比直接使用厂商API,Taotoken在稳定性方面的补充价值
  • GitHub中文插件:5分钟实现GitHub界面全面中文化的终极指南
  • 百度网盘直链解析:5分钟实现全速下载的终极指南
  • 数据驱动永磁材料设计:高通量微磁模拟与机器学习融合
  • 可视化 React 水合(Hydration)问题
  • 3个让你在家也能练出效果的健身法则
  • 【Gemini代码生成能力权威评测】:基于2000+真实编码场景的7大维度深度拆解
  • 终极伪代码生成器:如何让复杂代码秒变人类可读文档
  • Zotero中文文献管理难题的终极解决方案:茉莉花插件深度解析
  • 量子机器学习工程实践:从数据编码到梯度优化的核心挑战与前沿进展
  • 【AIGC内容竞争力突围关键】:为什么92%的ChatGPT使用者不会“讲故事”?资深NLP架构师首曝4层认知断层
  • 暗黑破坏神II角色存档编辑终极指南:5分钟掌握Diablo Edit2
  • 登录状态正常
  • Zotero文献去重终极指南:如何用3分钟清理500+重复文献
  • 如何用本地图像搜索工具实现千万级图片秒级检索:隐私优先的终极解决方案