常见锁策略

本文介绍了几种常见的锁策略,包括乐观锁与悲观锁的概念,读写锁的特性,以及轻量级锁和重量级锁的区别。自旋锁和挂起等待锁是两种不同的等待机制,前者消耗CPU资源,后者则不。公平锁和非公平锁关注的是线程获取锁的顺序,而可重入锁允许同一线程多次获取同一锁。Java中的synchronized是一个综合的锁机制,具备自适应性,既是悲观锁也是乐观锁,且为非公平和可重入的。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

常见锁策略:
不是只针对java的,别的语言,工具只要涉及到锁,也同样适用。
1.乐观锁Vs悲观锁
2.普通互斥锁Vs读写锁
3.轻量级锁vs重量级锁
4.自旋锁vs挂起等待锁
5.公平锁vs非公平锁
6.可重入锁Vs不可重入锁
(1)乐观锁vs悲观锁
锁的实现者,预测接下来锁冲突的概率大小。根据这个冲突的概率,来决定接下来怎么做?
锁冲突:就是锁竞争,两个线程针对一个对象加锁产生阻塞等待。
乐观锁:预测接下来冲突概率不大。
悲观锁:预测接下来冲突概率比较大。
两种锁导致最终要做的事情是不一样的。
(以下情况也并不绝对)
悲观锁一般要做的工作更多一些效率会更低。
乐观锁做的工作会更少一点, 效率更高。
站在加锁的过程上看待的, 加锁解锁过程中干的工作是多还是少?
(1)乐观锁,指的是干的事情少,轻量级。
(2)悲观锁,指的是干的事情多,重量级。
(2)读写锁
普通的互斥锁,就如同synchronized。 当两个线程竞争同一把锁,就会产生等待。
读写锁,分成两种情况:
1.读加锁
2.写加锁
产生竞争情况:
(1)读锁和读锁之间,不会产生竞争
(2)写锁和写锁之间,有竞争
(3)读锁和写锁之间,有竞争
    多个线程同时读同一个变量,没影响(也就不必加锁)。
(3)重量级锁vs轻量级锁
轻量级锁加锁解锁开销比较小:
        典型的,纯用户态的加锁逻辑,开销是比较小
重量级锁,加锁解锁开销比较大:
        典型的,进入内核态的加锁逻辑,开销是比较大的
(4)自旋锁vs挂起等待锁
自旋锁是轻量级锁的一种典型实现:
        通常是纯用户态的, 不需要经过内核态 (时间相对更短)。 自旋就类似于“忙等" ,占用CPU大量时间,持续  消耗CPU资源 ,反复询问当前锁是否就绪。
挂起等待锁是重量级锁的一种典型实现:
        通过内核的机制, 来实现挂起等待 (时间更长),挂起等待不消耗CPU资源,等待唤醒。
(5)公平锁 vs 非公平锁
假设三个线程 A, B, C. A 先尝试获取锁, 获取成功. 
然后 B 再尝试获取锁, 获取失败, 阻塞等待; 
然后 C 也尝试获取锁, C 也获取失败, 也阻塞等待.
当线程 A 释放锁的时候, 会发生啥呢?
公平锁: 遵守 "先来后到"。B 比 C 先来的. 当 A 释放锁的之后,B 就能先于 C 获取到锁。
非公平锁: 不遵守 "先来后到",B 和 C 都有可能获取到锁。
操作系统默认的锁的调度是非公平的情况
        要想实现公平锁需要引入额外的数据结构,来记录线程加锁的顺序, 需要一定的额外开销。
(6)可重入锁vs不可重入锁:synchronized
可重入:同一个线程针对同一把锁,连续加锁两次,不会死锁。 
不可重入:同一个线程针对同一把锁,连续加锁两次会死锁。
synchronized:
1.乐观锁&&悲观锁
2.轻量级锁&&重量级锁
3.乐观锁的部分是基于自旋锁实现的,悲观锁的部分是基于挂起等待锁实现的
    从上面可以看出synchronized是自适应:
    (a)初始使用的时候是乐观锁/轻量级锁/自旋锁
    (b)如果锁竞争不激烈,就处于上述状态不变。
            JMM在实现synchronized时候给我们提供自动优化的策略。 synchronized可以 自动适应多种不同的场景,比较 “智能"。
4.不是读写锁,是普通互斥锁。
5.是非公平锁
6.是可重入锁
在4,5,6中标准库中也有另外其他的锁能够实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值