锁策略和CAS,synchronized的优化过程

目录

1.重(轻)量级锁和(悲)乐观锁

2.自旋锁与挂起等待锁

3.公平锁和非公平锁

4.可重入锁和不可重入锁

5.CAS和synchronized的优化策略


1.重(轻)量级锁和(悲)乐观锁

重量级锁:锁冲突的程度大,主要依赖操作系统提供的锁,也就是区分用户态和内核态,两种状态的切换使得线程在重量级锁的作用下会进行阻塞,等待上一个锁的释放.

轻量级锁:锁冲突的程度小,主要依赖用户态来完成功能,当数据会被其他线程修改的时候,返回一个错误,让用户自己决定接下来要怎么执行.

乐观锁:经常会是轻量级锁

悲观锁:经常会是重量级锁,悲观锁会认为每次数据都有被修改的风险,所以每次都会上锁.

乐观锁和悲观锁可以理解为,我去问老师问题,悲观锁认为老师每次都在,所以不管老师在不在都回去问老师问题(每次都加锁),乐观锁去问老师,老师在就直接问老师(不加锁直接访问),老师不在就下次再来(虽然没加锁,但是会识别出数据是否冲突,并且让用户自己决定接下来怎么执行)

用户态和内核态可以理解为我们去银行办理业务,我们可以去窗口排队询问工作人员办理(内核态时间不可控,需要阻塞等待),也可以自己去自助办理(用户态时间可控,不用阻塞等待)

2.自旋锁与挂起等待锁

自旋锁:当锁冲突时,会发生阻塞等待,这时线程会离开CPU进入阻塞队列,其实大部分情况下,阻塞等待的时间不长,所以这种情况下线程可以不用离开CPU在CPU里,一旦锁被其他线程释放,就能第一时间获取到锁

挂起等待锁:相当于自旋锁的反面例子,锁冲突时线程会离开CPU进行阻塞等待,等到锁被其他线程释放了再进入CPU运行.

这种情形可以理解为:

我想追求女神,跟女神表白但是女神已经有男朋友了

挂起等待锁:沉浸在悲伤的情绪中久久不能自拔,感觉生活没有了希望,但过了很久(阻塞等待),女神不知道换了多少任男友后突然向我这个备胎表白了,这时候才能跟女神谈恋爱(进入运行)

自旋锁:每天坚持跟女神表白,死皮赖脸直到她分手后立即上位(在CPU内空转,但是能第一时间获取到锁)

可以看出来自旋锁是一种轻量锁的表现形式,大大减少了线程的调度,缺点就是消耗CPU资源

synchronized的轻量锁策略就是通过自旋锁的形式实现的

3.公平锁和非公平锁

公平锁:遵循先来后到,先尝试获取锁的线程获取成功,后者只能阻塞等待

非公平锁:机会均等,先来和后来都有一样的概率能获取到锁.

4.可重入锁和不可重入锁

可重入锁:允许同一个线程多次获取同一把锁

不可重入锁:同一个线程多次获取同一把锁会造成死锁

// 第一次加锁 , 加锁成功
lock ();
// 第二次加锁 , 锁已经被占用 , 阻塞等待 .
lock ();
当第一次加锁时,再加同一把锁就会造成线程还没释放第一个锁又加了一把锁结果两者都无法解锁

5.CAS和synchronized的优化策略

CAS保证原子性,操作都是原子的,实现了Java.util.concurrent.atomic包里面的类

CAS实现自旋锁,下面是伪代码:当锁被其他线程占用,则自旋等待不退出循环,如果这个锁没有被其他线程占用,则退出循环,进行下一步的解锁

public class SpinLock {
    private Thread owner = null;
    public void lock(){
        // 通过 CAS 看当前锁是否被某个线程持有. 
        // 如果这个锁已经被别的线程持有, 那么就自旋等待. 
        // 如果这个锁没有被别的线程持有, 那么就把 owner 设为当前尝试加锁的线程. 
        while(!CAS(this.owner, null, Thread.currentThread())){
       }
   }
    public void unlock (){
        this.owner = null;
   }
}

CAS可以理解为一个乐观锁,因为他的伪代码实现:当数据冲突时不会阻塞等待,只会返回错误

对比前后修改值的时候也会根据版本号进行判断(解决ABA问题的bug)

boolean CAS(address, expectValue, swapValue) {
 if (&address == expectedValue) {
   &address = swapValue;
        return true;
   }
    return false;
 }

synchronized:

1.开始是乐观锁,锁冲突频繁时转换为悲观锁

2.开始是轻量级锁,锁被持有的时间长转换成重量级锁

3.实现轻量级锁用自旋锁策略

4.是一种不公平锁,分先来后到,等到先来的线程释放锁后另外的线程可以运行

5.可重入锁

*6.不是读写锁

synchronized的加锁过程:

无锁 -> 偏向锁 -> 自旋锁 -> 重量级锁

偏向锁:不是真的锁,只是在被锁的对象头做个标记,记录这个锁属于当前的线程

本质上是延迟加锁,等到有线程来竞争时就立马加锁

就好比如男女朋友,即使两个人不结婚也能幸福生活,但是有其他竞争者来时,还是需要用法定夫妻关系维持稳定的生活,杜绝外来者有非分之想

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值