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

Java 并发锁实战手册:各类锁的特性、适用场景与选择方法论

Java开发中的锁

摘要:在Java开发中,锁是处理多线程并发安全的核心工具。不同类型的锁适用于不同场景,理解它们的特性和适用场景能帮助我们写出高效且安全的并发代码。以下是Java中常见锁的分类及实际开发中的使用场景

一、基于锁的获取方式:隐式锁 vs 显式锁

1. 隐式锁(synchronized)

  • 特点:JVM原生支持,无需手动释放,自动实现锁的获取与释放;可重入、非公平锁(默认);在JDK 1.6后进行了大量优化(偏向锁、轻量级锁、重量级锁升级机制)。
  • 使用方式:修饰方法(锁对象为this或类对象)、修饰代码块(指定锁对象)。
    // 修饰方法
    public synchronized void method1() { ... }// 修饰代码块
    public void method2() {synchronized (this) { ... }
    }
    
  • 实际场景
    • 并发量较低的简单场景(如工具类的线程安全方法)。
    • 不需要复杂锁控制(如中断、超时、公平性)的场景。
    • 优势:使用简单,不易因忘记释放锁导致死锁,JVM优化成熟,性能接近显式锁。
  • 注意:锁粒度不宜过大(避免影响并发效率),如尽量锁代码块而非整个方法。

2. 显式锁(java.util.concurrent.locks.Lock)

需手动调用lock()获取锁、unlock()释放锁(通常在finally中释放),功能更灵活。

(1)ReentrantLock(可重入锁)
  • 特点:可重入、支持公平/非公平锁(构造函数指定)、可中断获取锁、超时获取锁、尝试获取锁(tryLock())。
  • 使用方式
    Lock lock = new ReentrantLock(); // 非公平锁(默认)
    // Lock lock = new ReentrantLock(true); // 公平锁public void method() {lock.lock();try {// 业务逻辑} finally {lock.unlock(); // 必须释放,否则可能死锁}
    }
    
  • 实际场景
    • 需要灵活控制锁的场景:如超时获取锁(避免永久阻塞)、中断等待锁的线程(lockInterruptibly())。
    • 需要公平锁的场景(如对执行顺序有严格要求,避免线程饥饿)。
    • 复杂的同步逻辑(如多个条件变量配合Condition使用)。
    • 示例:线程池任务中,需要控制某资源的并发访问,且允许超时放弃。
(2)ReadWriteLock(读写锁)
  • 特点:拆分为读锁(ReadLock)和写锁(WriteLock),多线程可同时获取读锁(共享),但写锁与读锁/写锁互斥(排他);适合“读多写少”场景。
  • 使用方式
    ReadWriteLock rwLock = new ReentrantReadWriteLock();
    Lock readLock = rwLock.readLock();
    Lock writeLock = rwLock.writeLock();// 读操作
    public void read() {readLock.lock();try { ... } finally { readLock.unlock(); }
    }// 写操作
    public void write() {writeLock.lock();try { ... } finally { writeLock.unlock(); }
    }
    
  • 实际场景
    • 缓存系统(如本地缓存,大量线程读缓存,少量线程更新缓存)。
    • 配置文件读取(多数情况读配置,少数情况更新配置)。
  • 注意:读锁不能升级为写锁(避免死锁),写锁可降级为读锁。
(3)StampedLock( stamped 锁)
  • 特点:JDK 8引入,比ReadWriteLock更灵活,支持三种模式:写锁、悲观读锁、乐观读;乐观读无需加锁,通过版本号判断是否有写入,适合“读远多于写”场景。
  • 使用方式
    StampedLock lock = new StampedLock();// 乐观读
    long stamp = lock.tryOptimisticRead();
    // 读取数据
    if (!lock.validate(stamp)) { // 验证期间是否有写入stamp = lock.readLock(); // 升级为悲观读锁try { ... } finally { lock.unlockRead(stamp); }
    }// 写锁
    long writeStamp = lock.writeLock();
    try { ... } finally { lock.unlockWrite(writeStamp); }
    
  • 实际场景
    • 高频读、低频写的场景(如统计数据展示,极少更新但频繁查询)。
    • 对性能要求极高,且读操作占绝对主导的场景。
  • 注意:不支持重入,使用时需避免重入调用导致死锁。

二、基于锁的竞争策略:乐观锁 vs 悲观锁

1. 悲观锁

  • 特点:认为并发冲突会频繁发生,每次操作前必须获取锁,阻塞其他线程(如synchronizedReentrantLock)。
  • 适用场景:写操作频繁、并发冲突严重的场景(如库存扣减、转账)。

2. 乐观锁

  • 特点:认为并发冲突少,操作时不加锁,仅在提交时校验是否有冲突(通常基于CAS机制或版本号)。
  • Java中的实现
    • Atomic系列类(如AtomicInteger,基于CAS)。
    • 自定义版本号机制(如数据库表的version字段)。
  • 使用方式
    AtomicInteger count = new AtomicInteger(0);
    count.incrementAndGet(); // 原子自增(CAS实现)
    
  • 实际场景
    • 并发冲突少的场景(如计数器、序列号生成)。
    • 读多写少,且写入冲突概率低的场景(如用户积分更新)。
  • 注意:CAS存在“ABA问题”,可通过版本号解决(如AtomicStampedReference)。

三、基于锁的公平性:公平锁 vs 非公平锁

  • 公平锁:线程获取锁的顺序与请求顺序一致,避免饥饿,但性能稍差(需维护等待队列)。
    • 适用场景:对顺序性要求高的场景(如生产环境的任务调度,需按提交顺序执行)。
  • 非公平锁:线程获取锁的顺序不固定,可能“插队”,吞吐量更高(默认选择)。
    • 适用场景:多数并发场景(如普通业务逻辑),优先追求性能。

四、基于锁的粒度:偏向锁、轻量级锁、重量级锁(synchronized底层优化)

这三种是synchronized的底层实现,随竞争升级:

  • 偏向锁:无实际竞争时,锁偏向第一个获取它的线程,减少CAS操作(适用于单线程反复获取锁的场景)。
  • 轻量级锁:轻度竞争时,通过CAS自旋获取锁,避免线程阻塞(适用于短时间持有锁的场景)。
  • 重量级锁:重度竞争时,膨胀为操作系统级别的互斥锁,线程进入内核态阻塞(适用于长时间持有锁的场景)。

实际开发中无需手动控制,JVM自动升级,理解其机制可帮助优化锁的使用(如减少锁持有时间,避免频繁升级)。

五、选择建议

  1. 优先使用synchronized:简单、安全,JVM优化成熟,适合大多数低至中并发场景。
  2. 需要灵活控制(超时、中断、公平性)时,用ReentrantLock
  3. 读多写少场景,用ReadWriteLock;读远多于写,用StampedLock
  4. 并发冲突少,用乐观锁(Atomic类);冲突多,用悲观锁。
  5. 尽量减小锁粒度(如锁对象用局部变量而非全局对象),减少锁竞争。

根据具体业务的并发特点选择合适的锁,平衡安全性与性能。

http://www.dtcms.com/a/427434.html

相关文章:

  • 从化商城网站建设wordpress主题制作全过程
  • 传统网站架构 和 现代云服务 的区别简要分析
  • numpy -- 字符串函数 add()与multiply()
  • 使用Polars和PyTorch完成药物发现
  • 利津网站定制网络游戏投诉平台
  • 网站建设询价做网站必须网站备案
  • 跛脚就被辞退,道歉有用还要制度干什么?
  • 在windows 的子系统Ubuntu部署qanything-v2
  • AudioNotes:当FunASR遇见Qwen2,音视频转笔记的技术革命
  • 蛋白质结构预测:从AlphaFold到未来的计算生物学革命
  • 地区性中介类网站建设做网站的电脑需要什么配置
  • 4-6〔O҉S҉C҉P҉ ◈ 研记〕❘ WEB应用攻击▸文件上传漏洞-A
  • 《五年级上册语文1-8单元习作详解》+五年级语文作文指导/各单元提纲/写作技巧+完整电子版可下载打印
  • 第二届管理与智能社会发展国际学术会议(MISD 2026)
  • SEO描述字数计算工具
  • 做网站找模板苏州市城市建设局网站
  • junit4中通过autowired注入和构造器注入混合模式下单测
  • 青羊区建设网站百度官方认证
  • 《决策树、随机森林与模型调优》
  • k8s-容器探针
  • PHP 数组 如何移动某个元素到某个元素前面
  • RynnVLA-001:利用人类演示来改进机器人操作
  • Linux操作系统课问题总结:从/proc目录到磁盘管理
  • Honeywell SS360NT磁性位置传感器—扫地机器人
  • 百度站长工具seo查询云南网页设计制作
  • php网站优点深圳市福田区
  • 开源代码uSNMP推荐
  • 鸿蒙:获取屏幕的刷新率、分辨率、监听截屏或录屏状态等
  • Springboot城市空气质量数据管理系统futcv(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 开发一个网站的费用两学一做11月答题网站