一.常见的锁策略
锁:非常广义的话题;
synchronized:只是市面上五花八门的锁的其中一种典型的实现,Java内置的推荐使用的锁;
(1)乐观锁 && 悲观锁
乐观锁:加锁的时候,假设出现锁冲突的概率不大;接下来围绕加锁要做的工作很少;
悲观锁:加锁的时候,假设出现锁冲突的概率很大;接下来围绕加锁要做的工作更多;
synchronized是乐观还是悲观的呢? "自适应"
使用synchronized,初始情况下是乐观的(预估接下来锁冲突不大),
同时会统计接下来锁冲突了多少次,
如果发现,锁冲突的次数达到一定程度了,就会转成悲观的.
C++中的std::mutex锁的特点就是悲观的.
(2)重量级锁 && 轻量级锁
重量级锁:加锁的开销比较大,要做更多的工作.[往往,悲观的时候,会做的重]
轻量级锁:加锁的开销比较小,要做的工作相对少.[往往乐观的时候,会做的轻]
不能100%等价,乐观悲观是站在"预估锁冲突"的角度;重量清凉则是站在加锁时间开销的角度;
(3)挂起等待锁 && 自旋锁
挂起等待锁属于是悲观锁/重量级锁的一种典型实现;(CPU消耗少,等待时间变多了)
预测拿到锁的概率不大,让出了CPU资源,CPU就可以用来做别的事了;
自旋锁属于是乐观锁/轻量级锁的一种典型实现;(CPU消耗多,等待时间相对少了)
忙等:等待的过程中不会释放CPU资源,不停的检测锁是否被释放.一旦锁被释放了,就立即有机会能获取到锁了;
若很多线程都在忙等总的CPU消耗就会非常高,故锁冲突概率不高的情况下,才能忙等;
并且若竞争太激烈,导致有些线程,要等待很久才能拿到锁;
---------------------------------------------------------------------------------------------------------------------------------
synchronized"自适应":
轻量级锁就是基于"自旋"的方式实现的.(JVM内部,用户态代码实现的);
重量级锁就是基于"挂起等待"的方式实现的.(调用操作系统 api, 在内核中实现的);