33.介绍Java中的锁

1. 偏向锁 → 轻量级锁 → 重量级锁

Java 中的 synchronized 锁有三种状态:偏向锁 → 轻量级锁 → 重量级锁,这些锁通过对象头中的 mark word 来标明锁的状态

偏向锁

  • 定义:当锁没有竞争时,无需加锁,只需打个标记
  • 工作原理:
    • 对象初始化后,若没有线程访问该对象的锁,则该对象是可偏向的
    • 当第一个线程访问并尝试获取锁时,锁会记录该线程作为锁的拥有者
    • 后续线程尝试获取锁时,如果是偏向锁的拥有者,可以直接获得锁,避免执行 CAS 操作
  • 性能:性能最佳,适用于无竞争的情况,开销非常小

轻量级锁

  • 定义:在大多数情况下,synchronized 中的代码是由多个线程交替执行的,且通常没有实际的竞争,或者仅存在短时间的竞争,这时使用 CAS 操作可以解决
  • 工作原理:
    • 当原本是偏向锁的锁被另一个线程访问时,说明出现了竞争,偏向锁将升级为轻量级锁
    • 线程会通过自旋的方式尝试获取锁,而不是立即进入阻塞状态
  • 性能:性能中等,利用自旋和 CAS 避免了重量级锁带来的线程阻塞和唤醒

重量级锁

  • 定义:重量级锁是互斥锁,通过操作系统的同步机制实现,因此其开销较大
  • 工作原理:
    • 当多个线程发生长期的实际竞争时,轻量级锁无法满足需求,锁会膨胀为重量级锁
    • 重量级锁会导致获取不到锁的线程进入阻塞状态
  • 性能:性能最差,因为会将线程阻塞,造成较大的开销

锁的升级路径

无锁 → 偏向锁 → 轻量级锁 → 重量级锁

2. 可重入锁 vs 非可重入锁

可重入锁

  • 定义:当前线程已经持有该锁时,可以在不释放该锁的情况下,再次获取该锁
  • 特点:
    • 允许线程在已持有锁的情况下多次获取该锁,不会导致死锁
    • 典型实现:synchronized、ReentrantLock

非可重入锁

  • 定义:线程不能在持有该锁的情况下再次获取该锁。若当前线程已经持有该锁,它必须先释放锁,然后才能重新获取该锁
  • 特点:
    • 线程不能重复获取同一把锁
    • 如果当前线程已经持有该锁,再次尝试获取时会导致死锁

3. 共享锁 vs 独占锁

共享锁

  • 定义:同一把锁可以被多个线程同时获得
  • 特点:
    • 多个线程可以同时持有该锁
    • 适用于读操作的场景

独占锁

  • 定义:锁只能同时被一个线程获得
  • 特点:
    • 只有一个线程可以持有该锁,其他线程必须等待释放
    • 适用于写操作的场景

读写锁中的应用

  • 读锁:是共享锁,多个线程可以同时持有该锁
  • 写锁:是独占锁,最多只能有一个线程持有该锁,其他线程必须等待

4. 公平锁 vs 非公平锁

公平锁

  • 定义:如果线程现在拿不到这把锁,它会进入等待队列,按照排队的顺序等待锁的分配
  • 特点:
    • 线程会按照先来先得的原则获得锁
    • 排队时间较长的线程优先获取锁,确保公平性

非公平锁

  • 定义:在某些情况下,忽略排队中的线程,发生插队现象
  • 特点:
    • 线程不严格按照排队顺序获取锁,可能会发生插队
    • 线程在某些情况下会跳过等待队列直接尝试获取锁

5. 悲观锁 vs 乐观锁

悲观锁

  • 定义:在获取资源之前,必须先拿到锁,以确保进入“独占”状态
  • 特点:
    • 当前线程在操作资源时,其他线程无法获取锁,因此其他线程无法干扰当前线程
    • 强调对共享资源的保护,适用于资源竞争较为激烈的场景

乐观锁

  • 定义:不要求在获取资源前拿到锁,也不锁住资源,而是通过 CAS 理念进行操作
  • 特点:
    • 在不独占资源的情况下,乐观地进行资源修改
    • 假设不会有线程干扰,因此避免了锁的开销,适用于资源竞争较少的场景

6. 自旋锁 vs 阻塞锁

自旋锁

  • 定义:当线程无法获取锁时,不会立即进入阻塞状态或释放 CPU 资源,而是通过循环不断尝试获取锁
  • 特点:
    • 使用循环尝试获取锁,直到成功为止
    • 在锁竞争较轻的情况下,能够减少阻塞带来的性能开销
    • 适用于锁被短时间占用的场景

阻塞锁

  • 定义:当线程无法获取锁时,会直接进入阻塞状态,释放 CPU 资源,等待锁被释放后再重新尝试获取
  • 特点:
    • 线程一旦无法获得锁,即进入阻塞状态,无法继续执行
    • 适用于锁竞争较为激烈的情况,但可能带来较大的上下文切换开销

7. 可中断锁 vs 不可中断锁

可中断锁

  • 定义:线程在尝试获取锁的过程中,如果被中断,可以在中断后进行其他操作,而不是一直等待锁
  • 特点:
    • ReentrantLock 是典型的可中断锁
    • 通过 lockInterruptibly 方法,在获取锁的过程中可以响应中断,线程可以在中断后执行其他逻辑,而不必一直等待

不可中断锁

  • 定义:一旦线程申请了锁,就没有回头路,必须等待锁被释放,无法响应中断
  • 特点:
    • 使用 synchronized 关键字修饰的锁是不可中断锁
    • 线程在等待锁时,如果被中断,只能等待锁获取完毕后再进行其他操作

这是我整理的笔记,目前还在学习阶段,文章中可能有错误和不足,欢迎大家斧正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dubhehug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值