轻量级锁与重量级锁的区别

1、用户态与内核态

1.1 什么是用户态与内核态

用户态和内核态是操作系统的两种运行状态,这两个运行状态的区别主要是为了对访问能力进行限制,用户态的权限较低,而内核态的权限较高。用户态是指应用程序运行的环境,而内核态是指操作系统内核运行的环境。

  • 用户态:用户态运行的程序只能受限地访问内存,只能直接读取用户程序的数据,并且不允许访问外围设备,用户态下的 CPU 不允许独占,也就是说 CPU 能够被其他程序获取。
  • 内核态:内核态运行的程序可以访问计算机的任何数据和资源,不受限制,包括外围设备,比如网卡、硬盘等。处于内核态的 CPU 可以从一个程序切换到另外一个程序,并且占用 CPU 不会发生抢占情况。

1.2 用户态和内核态是如何切换的?

为什么要进行切换呢?

  • 在用户态下,应用程序可以执行一般的操作,如读写文件、网络通信等。但是,有些特权操作,如访问硬件设备、修改内存映射等,需要通过系统调用来请求内核执行。这时,操作系统会将应用程序的状态保存起来,并切换到内核态执行相应的操作。

  • 在内核态下,操作系统具有更高的权限和更广泛的资源访问能力。它可以执行特权指令、访问硬件设备、管理内存等。当内核完成相应的操作后,会将结果返回给应用程序,并将控制权切换回用户态。

  • 用户态和内核态的切换是为了保护系统的安全性和稳定性。通过限制应用程序对系统资源的直接访问,可以防止恶意程序对系统造成破坏。同时,通过将特权操作交给内核执行,可以确保这些操作的正确性和一致性。

用户态和内核态的切换主要发生在以下几种情况:

  • 系统调用:当用户程序需要请求操作系统提供的服务时,如读写文件、创建进程等,需要通过系统调用来实现。这时,会发生从用户态到内核态的切换。

  • 中断处理:当硬件设备发生中断请求时,操作系统需要处理这个中断,这时,会发生从用户态到内核态的切换。

  • 异常处理:当用户程序运行出错,如除0错误、访问非法内存等,操作系统需要处理这个异常,这时,会发生从用户态到内核态的切换。

用户态和内核态的切换过程如下:

1.保存当前程序的状态:包括程序计数器、寄存器等。

2.设置内核栈:因为用户栈和内核栈是分开的,所以需要切换到内核栈。

3.设置权限:将CPU的运行级别从用户态切换到内核态。

4.跳转到内核程序:根据中断向量表,跳转到相应的内核程序进行处理。

5.恢复程序状态:处理完后,恢复原来程序的状态,包括程序计数器、寄存器等。

6.恢复权限:将CPU的运行级别从内核态切换回用户态。

2、轻量级锁与重量级锁

2.1 什么是轻量级锁与重量级锁

重量级锁:我们知道,当要进入一个同步、线程安全的方法时,是需要先获得这个方法的锁的,退出这个方法时,则会释放锁。如果获取不到这个锁的话,意味着有别的线程在执行这个方法,这时我们就会马上进入阻塞的状态,等待那个持有锁的线程释放锁,然后再把我们从阻塞的状态唤醒,我们再去获取这个方法的锁。这种获取不到锁就马上进入阻塞状态的锁,我们称之为重量级锁。重点在于获取不到锁的线程,会一直处在等待状态,什么东西都做不了

  • 优点:线程竞争不使用自旋,不会消耗CPU。
  • 缺点:线程阻塞,响应时间缓慢。

轻量级锁:一般都是用自旋锁+CAS来实现的,我们可以定义自选的次数,到达这个次数后,我们就退出,不抢这个锁了,然后走对应的逻辑;或者升级为重量级锁

  • 优点:竞争的线程不会阻塞,提高了程序的响应速度。

  • 缺点:如果始终得不到锁竞争的线程使用自旋会消耗CPU,因为执行CAS原语是要靠CPU的。

2.2 轻量级锁与重量级锁的区别

轻量级锁和重量级锁是Java中两种不同的锁机制,它们在多个方面有以下区别:

  1. 用户态和内核态:

    • 轻量级锁主要在用户态下执行,当线程竞争不激烈时,使用轻量级锁可以避免在用户态和内核态之间切换的额外消耗,从而提高性能。
    • 重量级锁则需要切换到内核态执行,当线程竞争激烈时,使用重量级锁可以避免大量的CPU资源浪费在无效的轮询上。
  2. 是否阻塞当前线程:

    • 轻量级锁在获取锁失败时,会采用自旋的方式尝试获取锁,不会阻塞当前线程。但如果自旋次数过多,仍无法获取到锁,那么轻量级锁会膨胀为重量级锁,此时会阻塞线程。
    • 重量级锁在获取锁失败时,会直接将线程阻塞,直到获取到锁为止。
  3. 锁的状态:

    • 轻量级锁在锁对象的Mark Word中存储了锁定线程的栈帧信息,当锁被释放时,系统通过CAS操作来进行锁的释放。
    • 重量级锁在锁对象的Mark Word中存储了指向重量级锁(Monitor)的指针,当锁被释放时,需要唤醒被阻塞的线程。
  4. 使用场景:

    • 轻量级锁适用于线程冲突较少的情况,因为线程冲突少,线程有很大概率在第一次就获取到锁,避免了系统切换的开销。
    • 重量级锁适用于线程冲突较多的情况,因为线程冲突多,自旋很可能无法在限定次数内获取到锁,此时阻塞线程反而能更好地节省CPU资源。
  5. 性能开销:

    • 轻量级锁的性能开销主要来自于CAS操作和自旋等待,但在竞争不激烈的情况下,这些开销通常可以被接受。
    • 重量级锁的性能开销主要来自于线程切换和线程阻塞唤醒,这些开销在竞争激烈的情况下是必要的,因为它们可以避免CPU资源的浪费。

总的来说,轻量级锁和重量级锁各有优势,适用于不同的场景,Java虚拟机会根据具体情况动态地选择使用轻量级锁还是重量级锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

悬浮海

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

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

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

打赏作者

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

抵扣说明:

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

余额充值