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

Java中存在哪些锁?

一、内置锁(Synchronized)

Java 语言原生支持的锁机制,基于 JVM 实现,无需显式释放。

  • 特性
    • 自动获取 / 释放锁(代码块执行完或异常时自动释放)。
    • 可修饰方法(锁住当前对象或类)或代码块(锁住指定对象)。
    • JDK 6 后优化为 “偏向锁 → 轻量级锁 → 重量级锁” 的升级过程(自适应锁)。
  • 示例
    // 修饰方法(锁住当前对象)
    synchronized void method() { ... }// 修饰代码块(锁住指定对象)
    Object lock = new Object();
    void method() {synchronized (lock) { ... }
    }
    

二、显式锁(java.util.concurrent.locks)

JDK 5+ 引入的锁框架,需手动获取和释放,功能更灵活。

1. ReentrantLock(可重入锁)
  • 特性
    • 支持重入(同一线程可多次获取锁,需对应次数释放)。
    • 可中断(lockInterruptibly() 允许线程在等待锁时响应中断)。
    • 可设置公平性(构造函数传入 true 为公平锁,按申请顺序获取锁)。
    • 支持条件变量(Condition,实现更灵活的等待 / 通知机制)。
  • 示例
    ReentrantLock lock = new ReentrantLock(true); // 公平锁
    try {lock.lock(); // 获取锁// 临界区代码
    } finally {lock.unlock(); // 释放锁(必须在finally中)
    }
    
2. ReentrantReadWriteLock(读写锁)
  • 特性
    • 分离读锁和写锁,允许多个线程同时读(共享),但写操作独占。
    • 读锁与写锁互斥,写锁与写锁互斥,适合 “读多写少” 场景。
    • 支持重入和公平性设置。
  • 示例
    ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
    ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();// 读操作(共享)
    readLock.lock();
    try { ... } finally { readLock.unlock(); }// 写操作(独占)
    writeLock.lock();
    try { ... } finally { writeLock.unlock(); }
    
3. StampedLock( stamped 锁)

JDK 8 引入,优化读写锁性能,支持三种模式:

  • 写锁(独占):与 ReentrantReadWriteLock 的写锁类似。
  • 悲观读锁(共享):与普通读锁类似,允许多线程读。
  • 乐观读:无锁模式,读取时不阻塞写操作,需校验版本号(stamp)判断数据是否被修改。
    适合 “读极多写极少” 场景,性能优于 ReentrantReadWriteLock

三、分布式锁

跨 JVM 进程的锁机制,用于分布式系统中多节点的资源竞争(如 Redis、ZooKeeper 实现)。

  • 特性
    • 基于第三方组件(如 Redis 的 SET NX 命令、ZooKeeper 的临时节点)实现。
    • 需处理锁超时、释放异常、重入性等问题。
  • 示例(Redis 分布式锁简化逻辑)
    // 获取锁(SET NX + 过期时间)
    Boolean locked = redisTemplate.opsForValue().setIfAbsent("lockKey", "value", 30, TimeUnit.SECONDS);
    if (locked) {try {// 业务逻辑} finally {// 释放锁(需校验是否为当前线程持有)redisTemplate.delete("lockKey");}
    }
    

四、其他特殊锁

  1. 偏向锁 / 轻量级锁 / 重量级锁(Synchronized 的升级过程):

    • 偏向锁:单线程场景下,消除锁竞争开销(仅记录线程 ID)。
    • 轻量级锁:多线程交替执行时,用 CAS 避免重量级锁的内核态切换。
    • 重量级锁:多线程竞争激烈时,依赖操作系统互斥量(Mutex)实现,开销大但安全。
  2. 自旋锁:线程获取锁失败时,不立即阻塞,而是循环重试(自旋),减少上下文切换,适合锁持有时间短的场景(JDK 中的 Unsafe 类提供 CAS 实现)。

  3. 公平锁 / 非公平锁

    • 公平锁:按线程申请锁的顺序获取,避免饥饿,但性能较低(如 ReentrantLock(true))。
    • 非公平锁:允许线程 “插队” 获取锁,可能导致饥饿,但性能更高(默认模式)。

总结

Java 中的锁按范围可分为本地锁(Synchronized、ReentrantLock 等)和分布式锁;按特性可分为可重入锁、读写锁、公平锁等。

扩展:

1、Synchronized修饰方法(锁住当前对象或类)或代码块(锁住指定对象)二者有什么不同?

锁对象的区别:

修饰普通方法

  • 锁的对象是当前实例对象(this
  • 多个个线程调用同一个对象的该方法时,会竞争同一把锁;但调用不同对象的该方法时,互不干扰(每个对象有独立的锁)。

修饰静态方法

  • 锁的对象是当前类的 Class 对象(每个类只有一个 Class 对象,全局唯一)。
  • 无论多少个实例对象,调用该静态方法时都会竞争同一把锁(类级别的锁)

修饰代码块

  • 锁的对象是代码块中显式指定的对象(可以是 this、类对象、自定义对象等)。
  • 灵活性更高,可根据需求选择锁的范围(实例级、类级或自定义对象级)。

其余区别:

维度synchronized 修饰方法synchronized 修饰代码块
锁对象普通方法:当前实例(this);静态方法:类对象(Xxx.class显式指定的对象(this、类对象、自定义对象等)
锁粒度粗(整个方法)细(仅代码块)
灵活性低(锁对象固定)高(可自由选择锁对象和范围)
性能可能较差(同步范围大)通常更优(同步范围可控)
适用场景整个方法都需要同步的简单场景仅部分代码需要同步的复杂场景
http://www.dtcms.com/a/390225.html

相关文章:

  • 非连续性内存分配:分页
  • [x-cmd] x-cmd 性能
  • Zynq开发实践(SDK之定时器)
  • Java IO核心知识提问点
  • 微前端--前端架构的模块化革命
  • SQL分析-基础
  • V821---4M高集成无线视频芯片
  • count down 92 days
  • 学习日记-JS+DOM-day58-9.18
  • 【Python】基于界面库PyQt5+QTLinguist的多语言切换功能实现
  • Flutter 组件介绍:TickerMode
  • SQL 聚合函数总结:COUNT、SUM、AVG、MAX、MIN 详解
  • 资深专业新媒体营销数字营销培训老师商学院教授课程老师培训讲师唐兴通讲授10大经典社群私域案例:Lululemon的热汗式信仰社群运营社群活动
  • 玉米病虫害数据集检测识别数据集:近4k图像,7类,yolo标注
  • Batch Size与预热导致深度学习模型推理时间忽快忽慢
  • 过滤器(Filter)与拦截器(Interceptor)知识点总结
  • 深度学习与机器学习
  • Linux服务器从零开始-mysql安装
  • Emacs 折腾日记(三十)——打造C++ IDE 续
  • 解密DNS:互联网的隐形导航系统
  • Mysql修改用户密码,修改MySQL密码如何安全的步骤是什么
  • PS练习2:将图片贴入实际环境中
  • cocos shader 流光环绕
  • kali nethunter 开启ssh
  • vue3滚动到顶部钩子函数+组件简单示例
  • Linux 开发工具(3)
  • Hive 运行
  • PPT中为图片添加透明渐变的蒙版
  • 数字签名过程中的消息摘要和加密的作用
  • Unity物理系统笔记