赞
踩
锁
:非常广义的概念,不是指某个具体的锁,所有的锁都可以往这些策略中套
synchronized
:只是市面上五花八门的锁种,其中一种典型的实现,Java 内置的,推荐使用的锁
这两个词不是指某个具体的锁,而是锁的一种“特性”,描述了“一类”
乐观锁:加锁的时候,假设出现冲突的概率不大
使用 synchronized
,初始情况下,是乐观的(预估接下来锁冲突概率不大)
站在预测锁冲突的概率是否高
synchronized
是自适应的
效果和悲观乐观是重叠的,只是站在的角度不一样
重量级锁:加锁的开销比较大,要做的工作更多
站在加锁的开销角度
synchronized
也是自适应的
挂起等待锁:属于是悲观锁/重量级锁的一种典型实现
自旋锁:乐观锁/轻量级锁的一种典型实现
比如:
你去追你的女神:
女神女神,我好喜欢你,
你尝试对女神加锁
女神表示:我有男朋友了女神表示她这把锁已经被别的线程给加了
你就可以选择“等待”,等到女神锁被释放,比如:你选择每天仍然会给女神不停地问候“早安,午安…”,这里的行为称为“自旋锁”
- 这里的等待是“忙等”,等待的过程中 CPU 的资源不会释放
- 某天女神和男朋友吵架了,不开心,你就立刻能感知到,机会来了。这样你就可以在女神锁释放的第一时间,立刻抓住机会,能够上位
- 不停地,循环地检测锁是否被释放,一旦锁释放,就能立即有机会能获得锁
你选择把女神拉黑,先不联系了,若干年后你从别人那里听说,女神分手了,你再去联络女神,这种行为就是“挂起等待锁”
- 不联系,就相当于“让出 CPU 资源”CPU 就可以去做别的事了
- 不理女神之后,我们就可以有心思好好学习,好好敲代码,好好找工作了,在过程中做成更多的事情。过了一段时间后,我们通过一些途径听说女神分手了,再伺机而动,但“听说”的时效性很低,这个中间可能有很长的时间跨度。在这个时间跨度里,女神是否由谈了男朋友?分手了多少次?你是不知道的
- 挂机时间更长,但能节省下 CPU 资源去做别的事情
注意:
synchronized
“自适应”
- 轻量级锁就是基于自旋的方式实现的(JVM 内部,用户态代码实现)
- 重量级锁就是基于挂起等待的方式实现的(调用操作系统 API,在内核中实现)
纯用户态代码往往执行效率比内核态代码的高一些,总体来说,我们还是认为“自旋”的效率更高的,但是 CPU 开销更大
挂起等待锁的操作虽然 CPU 开销变少了,但整体的等待时间更多
日常生活中,说的公平可能有不同的含义
当女神分手了,该轮到谁上位呢?
公平锁: 在计算机中,约定“先来后到”为公平
非公平锁: 系统原生
synchronized
属于非公平锁
N
个线程竞争同一个锁,其中一个线程拿到锁了,后续该线程释放锁之后,剩下的 N-1
个线程,就要重新竞争锁,谁能拿到锁,就不一定了synchronized
在系统内核的基础上,没有做啥额外的操作如需要使用公平锁,就需要做额外的工作
死锁问题:如果一个线程,针对同一把锁,连续加锁两次,就可能出现死锁,如果把锁设为“可重入”就可以避免死锁了
可重入:是专门的计算机术语,不要写作“可重复”这样的词
可重入锁
{
加一次锁,计数器加一}
解锁一次,计数器减一synchronized
并非是读写锁
所谓的读写锁,把“加锁操作”分为两种情况
在实际开发中,在大部分场景下,读操作的频次,本身就比写操作的频次高。所以就让读操作不产生锁冲突,这样就只有少数写操作会产生冲突,这样效率就高了
读写锁提供了两种加锁的 API,系统内置的锁,Java 标准库中的读写锁类为:ReentrantReadWriteLock
ReentrantReadWriteLock
的内部类 ReentrantReadWriteLock.ReadLock
表示加读锁,这个对象提供了 lock/unlock
⽅法进⾏加锁解锁ReentrantReadWriteLock
的内部类 ReentrantReadWriteLock.WriteLock
表示加写锁,这个对象也提供了lock/unlock
⽅法进⾏加锁解锁Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。