本章节所讲解的锁策略不仅仅是局限于 Java . 任何和 “锁” 相关的话题, 都可能会涉及到以下内容. 这些特性主要是给锁的实现者来参考的.
本文中讲解的锁, 并不是指某个具体的锁, 而是一个抽象的概念, 描述的是 “一类锁”. 即使是普通的程序猿也需要了解一些, 对于合理的使用锁也是有很大帮助的.
关注收藏, 开始学习吧
乐观锁:
预测该场景中, 不太会出现锁冲突的情况. 假设数据一般情况下不会产生并发冲突, 所以在数据进行提交更新的时候, 才会正式对数据是否产生并发冲突进行检测, 如果发现并发冲突了, 则让返回用户错误的信息, 让用户决定如何去做.
悲观锁:
预测该场景中, 非常容易出现锁冲突. 总是假设最坏的情况, 每次去拿数据的时候都认为别人会修改, 所以每次在拿数据的时候都会上锁, 这样别人想拿这个数据就会阻塞直到它拿到锁.
锁冲突: 指两个线程尝试去获取一把锁, 一个线程获取成功, 则另一个线程就会阻塞等待, 这就是锁冲突.
锁的核心特性 “原子性”, 这样的机制追根溯源是 CPU 这样的硬件设备提供的.
mutex
互斥锁.synchronized
和 ReentrantLock
等关键字和类.注意, synchronized 并不仅仅是对 mutex 进行封装, 在 synchronized 内部还做了很多其他的 工作
轻量级锁:
加锁机制尽可能的不使用 mutex
, 而是尽量在用户态代码完成. 加锁开销比较小, 花费时间少, 占用资源较少.
重量级锁:
加锁机制重度依赖 OS 提供的 mutex
. 加锁开销比较大, 花费时间多, 占用资源较多.
注意:
挂起等待锁:
挂起等待锁, 是重量级锁的一种典型实现. 通过内核态, 借助系统提供的锁机制, 当出现锁冲突的时候, 会牵扯到内核对于线程的调度. 将冲突的线程挂起 (阻塞等待).
自旋锁:
自旋锁, 是轻量级锁的一种典型实现. 在用户态下, 通过自旋的方式 (while 循环), 实现类似于加锁的效果.
自旋锁伪代码:
while (抢锁(lock) == 失败) {}
多线程之间, 数据的读取方之间不会产生线程安全问题, 但数据的写入方互相之间以及和读者之间都需要进行互斥. 如果两种场景下都用同一个锁, 就会产生极大的性能损耗. 所以读写锁因此而产生.
读写锁 (readers-writer lock), 顾名思义, 在执行加锁操作时需要额外表明读写意图, 复数读者之间并不互斥, 而写者则要求与任何人互斥.
一个线程对于数据的访问, 主要存在两种操作: 读数据 和 写数据.
读写锁就是把读操作和写操作区分对待. Java 标准库提供了 ReentrantReadWriteLock
类, 实现了读写锁.
ReentrantReadWriteLock.ReadLock
类表示一个读锁. 这个对象提供了 lock / unlock 方法进行加锁解锁.ReentrantReadWriteLock.WriteLock
类表示一个写锁. 这个对象也提供了 lock / unlock 方法进行加锁解锁.其中,
而在实际开发中, 读操作出现的频率, 往往比写操作要高得多. 在该场景中, 使用读写锁的话, 就可以尽可能的避免产生锁竞争, 此时, 多线程并发执行的效率就会更高. 而如果使用互斥锁的话, 就会产生不必要的挂起等待, 这就是前者读写锁存在的意义.
假设有三个线程 A, B, C.
A 先尝试获取锁, 获取成功. 然后 B 再尝试获取锁, 获取失败, 阻塞等待. 然后C 也尝试获取锁, C 也获取失败, 也阻塞等待.
当线程 A 释放锁的时候, 会发生什么呢?
公平锁:
遵守 “先来后到”. B 比 C 先来的. 当 A 释放锁的之后, B 就能先于 C 获取到锁.
非公平锁:
不遵守 “先来后到”. B 和 C 都有可能获取到锁. 谁先拿到锁就是谁的.
注意:
可重入锁:
可重入锁的字面意思是 “可以重新进入的锁”, 即允许同一个线程多次获取同一把锁.
比如一个递归函数里有加锁操作, 递归过程中这个锁会阻塞自己吗? 如果不会, 那么这个锁就是可重入锁 (因为这个原因可重入锁也叫做递归锁).
不可重入锁:
按照之前对于锁的设定, 第二次加锁的时候, 就会阻塞等待. 直到第一次的锁被释放, 才能获取到第二个锁. 但是释放第一个锁也是由该线程来完成, 结果这个线程已经躺平了, 啥都不想干了, 也就无法进行解锁操作. 这时候就会产生死锁. 这个锁就是不可重入锁.
那么, 死锁具体是什么一个什么样的情况呢? 我们在下一篇博文详细讲述.
✨ 本文主要讲述了锁的几个主要策略. 主要讲解了几大锁策略的概念, 以及其所对应的场景.
✨ 想了解更多的多线程知识, 可以收藏一下本人的多线程学习专栏, 里面会持续更新本人的学习记录, 跟随我一起不断学习.
✨ 感谢你们的耐心阅读, 博主本人也是一名学生, 也还有需要很多学习的东西. 写这篇文章是以本人所学内容为基础, 日后也会不断更新自己的学习记录, 我们一起努力进步, 变得优秀, 小小菜鸟, 也能有大大梦想, 关注我, 一起学习.
再次感谢你们的阅读, 你们的鼓励是我创作的最大动力!!!!!