文章目录

  • 本文链接
  • 什么是自旋锁
    • 参考链接
  • 自旋锁和互斥锁的区别
    • 参考链接

本文链接

  • 击打

什么是自旋锁

  • 多线程对共享资源访问,

    • 为防止并发引起的相关问题,
    • 常引入锁的机制来处理并发问题。

  • 获取到资源的线程A对这个资源加锁,
  • 其他线程如B要访问这个资源首先要获得锁,
  • 而此时A持有这个资源的锁,只有等待线程A逻辑执行完,释放锁,
  • 这个时候B才能获取到资源的锁进而获取到该资源。
  • 这个过程中,A一直持有着资源的锁,那么没有获取到锁的其他线程比如B怎么办?通常就会有两种方式:
    1. 没有获得锁的进程就直接进入阻塞(BLOCKING),这种就是互斥锁
    1. 没获得锁的进程,不进入阻塞,而一直循环着,看是否能够等到A释放了资源的锁。

  • 《C++ 11》中就有这样的描述:
  • spin lock是非阻塞锁,
    • 如果某线程需要获取锁,但该锁已经被其他线程占用时,
    • 该线程不会被挂起,而是在不断的消耗CPU的时间,不停的试图获取锁。
  • 互斥量(mutex)是阻塞锁,
    • 当某线程无法获取锁时,
    • 该线程会被直接挂起,
    • 该线程不再消耗CPU时间,
    • 当其他线程释放锁后,操作系统会激活那个被挂起的线程,让其运行。

  • 《linux内核设计与实现》内核态,用户态,
  • 对自旋锁来说,自旋锁使线程处于用户态,
  • 而互斥锁需要重新分配,进入到内核态。
  • 用户态比较轻,内核态比较重。
  • 用户态和内核态这个也是linux中必备的知识基础,
  • 借鉴这个,可进行很多程序设计语言API上的优化,
  • 比如说javaio的部分,操作io的时候,先从用户态,进入内核态,
  • 再用内核态去操作输入输出设备的抽象,
  • 这里减少用户态到内核态的转换就是新io的一部分优化,后面聊

  • wiki中的定义:
  • 自旋锁是计算机科学
    • 用于多线程同步的一种锁,
    • 线程反复检查锁变量是否可用。
    • 由于线程在这一过程中保持执行,
    • 因此是一种忙等待。

  • 自旋锁避免了进程上下文的调度开销,因此对于线程只会阻塞很短时间的场合是有效的。
  • 因此OS的实现在很多地方用自旋锁。
  • Windows提供的轻型读写锁(SRW Lock)内部就用了自旋锁。
  • 单核CPU不适用自旋锁,这里单核指的是单核单线程的CPU
  • 因为,在同一时间只有一个线程是处在运行状态,假设运行线程A发现无法获取锁,只能等待解锁,但因为A自身不挂起,所以那个持有锁的线程B没有办法进入运行态,只能等到OS分给A的时间片用完,才有机会被调度。
  • 这种情况下使用自旋锁的代价很高。
  • (单核CPU不适合自旋锁,这个也只是针对单核单线程的情况,现在的技术基本单核都是支持多线程的)

  • 为什么要用自旋锁
  • 互斥锁有个缺点,
  • 他的执行流程是这样的 托管代码 - 用户态代码 - 内核态代码、上下文切换开销与损耗,
  • 若获取到资源锁的线程A立马处理完逻辑释放掉资源锁,
  • 如果是采取互斥方式,则线程B从没有获取锁到获取锁这个过程中,就要用户态和内核态调度、上下文切换的开销和损耗。
  • 所以就有了自旋锁的模式,让线程B就在用户态循环等着,减少消耗。

  • 自旋锁适用于锁使用者保持锁时间比较短
  • 这种情况下自旋锁的效率要远高于互斥锁。

  • 自旋锁潜在的问题
  • 过多占用CPU的资源,
  • 如果锁持有者线程A一直长时间的持有锁处理自己的逻辑,
  • 那么线程B就会一直循环等待过度占用cpu资源
  • 递归使用可能会造成死锁,不过这种场景一般写不出来

  • CAS
  • 不写术语定义了,
  • 简单的理解就是这个CAS是由操作系统定义的,
  • 由若干指令组成的,这个操作具有原子性,这些指令如果执行,就会全部执行完,不会被中断。
  • CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。
  • 当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。

  • CAS的问题
  • 经典的CAS的ABA问题,
  • 上面提到了CAS操作的时候,要检测值有没有变化,
  • 如果一个值原来是A,后来变成了B, 后来又变成了A,
  • CAS会认为没有发生变化。
  • 解决方案:
  • 加版本号 1A - 2B - 3A
  • jdk1.5提供了AtomicStampedReference来解决这个问题

  • 只能保证一个共享变量的原子操作
  • CAS通常是对一个变量来进行原子操作的,所以如果对多个变量进行原子操作就会有问题了。
  • 解决方案
  • 简单粗暴,加锁,反而加入了复杂性,最low的方式
  • 跟上面的加版本号的道理一样,就是将多个变量拼成一个变量(可以拼成一个字符串)
  • jdk1.5 提供了AtomicStampedReference,这个reference 就是个对象引用,把多个变量放在这个对象里即可

  • JAVA CAS封装
  • sun.misc.Unsafe是JDK里面的一个内部类,这个类当中有三个CAS的操作

  • JAVA自旋锁应用
  • Jdk1.5后,提供java.util.concurrent.atomic包,里面提供一组原子类。
  • 基本上就是当前获取锁的线程,执行更新的方法,其他线程自旋等待,
  • 比如atomicInteger类中的getAndAdd方法内部实际上使用的就是Unsafe的方法。
    /**
  • Atomically adds the given value to the current value.
  • @param delta the value to add
  • @return the previous value
    */
    public final int getAndAdd(int delta) {
    return unsafe.getAndAddInt(this, valueOffset, delta);
    }

\newline
\newline

  • java中的syncronized,在1.5中有大优化,加入了偏隙锁也叫偏向锁,
  • 实现方式:在对象头markword中打上线程的信息,这样资源上的锁的获取就偏向了这个线程,
  • 后面,会涉及一系列的锁升级的问题,
  • 间隙锁 - 轻量锁 - 重量级锁 ,锁升级后面单独抽出来写一篇,这个轻量锁实际上就是使用的也是自旋锁的实现方式。

参考链接

  • 添加链接描述

自旋锁和互斥锁的区别

  • 自旋锁是一种互斥锁的实现方式,一般的互斥锁会在等待期间放弃cpu,
  • spinlock是不断循环并测试锁的状态,这样就一直占着cpu。

  • 互斥锁:用于保护临界区,确保同一时间只有一个线程访问数据。
  • 对共享资源的访问,先对互斥量加锁,如果互斥量已经上锁,调用线程会阻塞,直到互斥量被解锁。
  • 在完成了对共享资源的访问后,要对互斥量进行解锁。

  • 临界区:每个进程中访问临界资源的那段程序称为临界区,每次只允许一个进程进入临界区,进入后不允许其他进程进入。
  • 自旋锁:与互斥量类似,它不是通过休眠使进程阻塞,而是在获取锁之前一直处于忙等(自旋)阻塞状态。
  • 用在以下情况:
    • 锁持有的时间短,且线程不希望在重新调度上花太多的成本。
    • “原地打转”。

  • 自旋锁与互斥锁的区别:

    • 线程在申请自旋锁时,
    • 线程不被挂起,而是处于忙等的状态。

  • 信号量:是个计数器,来控制多个进程对共享资源的访问。
  • 常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。
  • 主要作为进程间以及同一进程内不同线程之间的同步手段。

参考链接

  • 添加链接描述

什么是自旋锁+自旋锁和互斥锁的区别相关推荐

  1. java锁(公平锁和非公平锁、可重入锁(又名递归锁)、自旋锁、独占锁(写)/共享锁(读)/互斥锁、读写锁)

    前言 本文对Java的一些锁的概念和实现做个整理,涉及:公平锁和非公平锁.可重入锁(又名递归锁).自旋锁.独占锁(写)/共享锁(读)/互斥锁.读写锁 公平锁和非公平锁 概念 公平锁是指多个线程按照申请 ...

  2. Linux内核中的同步原语:自旋锁,信号量,互斥锁,读写信号量,顺序锁

    Linux内核中的同步原语 自旋锁,信号量,互斥锁,读写信号量,顺序锁 rtoax 2021年3月 在英文原文基础上,针对中文译文增加5.10.13内核源码相关内容. 1. Linux 内核中的同步原 ...

  3. c语言中锁的作用,c 互斥锁

    互斥锁的作用保护共享数据: 在并发机制的情况下,有时候会有多个线程同时访问同一片数据,为了保护数据操作的准确性就需要通过加锁来进行保护.保持操作互斥: 可能一个程序会有多个操作,但是同一个时间只能有一 ...

  4. 自旋锁:pthread_spinlock_t,互斥锁:pthread_mutex_t,条件变量:pthread_cond_t,读写锁:pthread_rwlock_t

    Table of Contents pthread提供的锁 互斥锁 自旋锁 pthreadtypes.h    nptl\sysdeps\unix\sysv\linux\i386\bits    44 ...

  5. 第十二节:深究内核模式锁的使用场景(自动事件锁、手动事件锁、信号量、互斥锁、读写锁、动态锁)

    一. 整体介绍 温馨提示:内核模式锁,在不到万不得已的情况下,不要使用它,因为代价太大了,有很多种替代方案. 内核模式锁包括: ①:事件锁 ②:信号量 ③:互斥锁 ④:读写锁 ⑤:动态锁 二. 事件锁 ...

  6. 独占锁(写锁)/共享锁(读锁)/互斥锁

    理论 独占锁:指该锁一次只能被一个线程所持有.对于ReentrantLock和Synchronized而言都是独占锁. 共享锁:该锁可以被多个线程所持有.对于ReentrantReadWriteLoc ...

  7. java的互斥锁_java基础之互斥锁初解

    JDK中常用synchronized用于解决线程安全的问题,那么在JDK1.5的新特性中还提供了一个ReenTrantLock类用于解决线程安全问题,这个类就被称作为互斥锁. 假定我们有三个子线程协同 ...

  8. linux进程--自旋锁和互斥锁的区别(十四)

    自旋锁(Spin lock) 自旋锁与互斥锁有点类似,只是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是 否该自旋锁的保持者已经释放了锁,"自旋&qu ...

  9. 高效编程之互斥锁和自旋锁

    两种锁的加锁原理 互斥锁:线程会从sleep(加锁)-->running(解锁),过程中有上下文的切换,cpu的抢占,信号的发送等开销. 自旋锁:线程一直是running(加锁-->解锁) ...

  10. 华为应用锁退出立即锁_面试官:你说说互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景...

    前言 生活中用到的锁,用途都比较简单粗暴,上锁基本是为了防止外人进来.电动车被偷等等. 但生活中也不是没有 BUG 的,比如加锁的电动车在「广西 - 窃·格瓦拉」面前,锁就是形同虚设,只要他愿意,他就 ...

最新文章

  1. 机器人日行十万步却无需动力源!究竟如何完美的机械结构让你开始怀疑人身...
  2. 命令行mvn打包的时候报错:No compiler is provided in this environment. Perhaps you are running on a JRE
  3. 学python买什么电脑-程序员,买了台破Apple电脑,用来学Python
  4. 【LINUX】Oracle数据库 linux磁盘头数据损坏修复
  5. ubuntu12.4上安装minigui3.0.12
  6. android 电池栏的高度,Android如何取得状态栏、任务栏高度
  7. IOS 封装轮播图
  8. 如何使用卡巴斯基急救盘清理感染的PC
  9. LSGO软件技术团队2015~2016学年第九周(1026~1101)总结
  10. 我忽然发现我写的cve漏洞管理系统简直就是redmine的一个小模块
  11. Canvas渲染会取代DOM吗?
  12. 当万物互联触手可及 你准备好了吗?
  13. win10系统安装软件安装和问题处理
  14. linux ext4 磁盘修复,修复损坏的 ext4 大分区数据
  15. 【GAPPER乡村笔记项目】盘点老龄化社会背景下人工智能及机器人技术的应用
  16. prevent to do sth 与 prevent sb (from) doing 用法
  17. 学而不思则罔,思而不学则殆
  18. Android案例手册 - Android Studio连接夜神模拟器和逍遥模拟器
  19. CornerNet,CenterNet关键代码解读: kp,_decode,left pooling
  20. 忽尔今夏,SpringSide 3.0

热门文章

  1. Java程序员:一整个项目的具体开发流程介绍
  2. Linux的触屏手势软件安装,Touchégg: Linux 上触摸板/屏的多指手势
  3. html自动获取系统时间,js、html获取系统当前时间方法
  4. 2005感动——洪战辉
  5. linux修改mysql的环境变量_Linux环境变量配置全攻略
  6. java基于Springboot+vue的健身房课程预约平台 element
  7. C语言文件操作(四) —— 文件读取结束的判定(feof、ferror)
  8. LCD 1602 稳定显示 [李园7舍_404]
  9. 树莓派4b 串口通信实现自发自收
  10. 机器学习—— 朴素贝叶斯分类器