JavaDriver JavaDriver
首页
  • 基础
  • 并发
  • JVM
  • 设计模式
  • 计算机网络
  • 操作系统
  • 数据结构
  • 算法
  • MYSQL
  • REDIS
  • Netty
  • Kafka
系统设计
非技术
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

YoungAnn

西二旗Java老司机一枚 致力于社会主义添砖Java
首页
  • 基础
  • 并发
  • JVM
  • 设计模式
  • 计算机网络
  • 操作系统
  • 数据结构
  • 算法
  • MYSQL
  • REDIS
  • Netty
  • Kafka
系统设计
非技术
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 计算机网络

  • 操作系统

    • 进程间有哪些通信方式?
    • 简述自旋锁与互斥锁的使用场景
      • 自旋锁
      • 自旋锁优缺点
      • 自旋锁的使用场景
      • 互斥锁
      • 自旋锁和互斥锁的使用场景
    • 进程和线程之间有什么区别?
    • 简述几个常用的 Linux 命令以及他们的功能
    • 进程有多少种状态?
    • 简述 select, poll, epoll 的使用场景以及区别
    • Linux 下如何排查 CPU 以及 内存占用过多?
    • 进程通信中的管道实现原理是什么?
    • Linux 下如何查看 CPU 荷载,正在运行的进程,某个端口对应的进程?
    • 如何调试服务器内存占用过高的问题?
    • Linux 如何查看实时的滚动日志?
    • 简述 Linux 零拷贝的原理
    • 为什么进程切换慢,线程切换快?
    • 简述创建进程的流程
    • 简述 Linux 虚拟内存的页面置换算法
    • 简述 Linux 进程调度的算法
    • 什么时候会由用户态陷入内核态?
    • Linux 下如何查看端口被哪个进程占用?
    • Linux 中虚拟内存和物理内存有什么区别?有什么优点?
    • 简述 traceroute 命令的原理
    • 简述IO模型
  • 数据结构

  • 算法

  • 剑指Offer题解

  • 计算机基础
  • 操作系统
YoungAnn
2022-09-21
目录

简述自旋锁与互斥锁的使用场景

img

# 自旋锁

自旋锁是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗 CPU

img

/**
 * 面试题分享:手写一个自旋锁
 *
 **/
public class SpinLockDemo {

    AtomicReference<Thread> lock = new AtomicReference<>();

    public void myLock(){
        Thread thread = Thread.currentThread();
        //如果不为空,自旋
        while (!lock.compareAndSet(null,thread)){

        }
    }

    public void myUnlock(){
        Thread thread = Thread.currentThread();
        //解锁后,将锁置为 null
        lock.compareAndSet(thread,null);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 自旋锁优缺点

缺点:

  1. 如果某个线程持有锁的时间过长,就会导致其它等待获取锁的线程进入循环等待,消耗CPU。使用不当会造成CPU 使用率极高。
  2. 上面 Java 实现的自旋锁不是公平的,即无法满足等待时间最长的线程优先获取锁。不公平的锁就会存在“线程饥饿”问题。

优点:

  1. 自旋锁不会使线程状态发生切换,一直处于用户态,即线程一直都是 active 的;不会使线程进入阻塞状态,减少了不必要的上下文切换,执行速度快
  2. 非自旋锁在获取不到锁的时候会进入阻塞状态,从而进入内核态,当获取到锁的时候需要从内核态恢复,需要线程上下文切换。 (线程被阻塞后便进入内核(Linux)调度状态,这个会导致系统在用户态与内核态之间来回切换,严重影响锁的性能)

# 自旋锁的使用场景

如果锁的使用者持有锁的时间非常长,那么其余的等待获得锁的线程就会一直做自旋操作,这是非常浪费 CPU 的使得 CPU 有效利用率大大降低。其次如果并发抢锁的线程非常多,也会加大这种浪费。

那么显然锁的持有时间非常短是使用自旋锁的场景。

因为自旋锁不会阻塞不会陷入内核重新调度其他线程,所以如果自旋带来的 CPU 消耗比阻塞,陷入内核,OS 调度其他线程,再切回用户态这一系列过程来的 CPU 消耗少那么自旋锁就能够节省 CPU,让 CPU 更多的去执行有效代码! 因为线程切换,陷入内核等等这一系列的操作和傻傻的自旋操作一样都是在做“无意义”事情,白白的消耗 CPU。

# 互斥锁

互斥锁是一种「独占锁」,比如当线程 A 加锁成功后,此时互斥锁已经被线程 A 独占了,只要线程 A 没有释放手中的锁,线程 B 加锁就会失败,于是就会释放 CPU 让给其他线程,既然线程 B 释放掉了 CPU,自然线程 B 加锁的代码就会被阻塞

在这里插入图片描述

对于互斥锁加锁失败而阻塞的现象,是由操作系统内核实现的。

当加锁失败时,内核会将线程置为「睡眠」状态,等到锁被释放后,内核会在合适的时机唤醒线程,当这个线程成功获取到锁后,于是就可以继续执行。

所以,互斥锁加锁失败时,会从用户态陷入到内核态,让内核帮我们切换线程,虽然简化了使用锁的难度,但是存在一定的性能开销成本。

性能开销的成本就是上下文切换的成本。

# 自旋锁和互斥锁的使用场景

a. 如果我们明确知道被锁住的代码的执行时间很短,那我们应该选择开销比较小的自旋锁 b. 如果临界区需要睡眠,应该选择互斥锁 c. 中断里应该使用自旋锁,因为中断处理中不允许睡眠

编辑 (opens new window)
上次更新: 2023/02/17, 17:03:51
进程间有哪些通信方式?
进程和线程之间有什么区别?

← 进程间有哪些通信方式? 进程和线程之间有什么区别?→

最近更新
01
电商-商品系统设计
12-17
02
关于如何写OKR
12-09
03
对事不对人 vs 对人不对事
12-09
更多文章>
Theme by Vdoing | Copyright © 2022-2023 YoungAnnn | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式