假如你是“道格李”,你将如何设计Lock锁?

一、Lock锁的大体逻辑过程

下面的逻辑过程很重要,下面的逻辑就是整体上道格李设计Lock锁的逻辑
在阅读AQS+ReentrantLock源码的时候,细节部分都是基于这个大体过程慢慢填充进去的。 并且在掌握大体逻辑过程之后,再去看AQS+ReentrantLock的源码真的方便很多。

逻辑如下:

ReentrantLock lock = new ReentrantLock(false);//false是非公平锁,true是公平锁
T1,T2,T3三个线程要执行下面代码的逻辑;
只有T1可以执行,那么T2和T3两个线程放哪??

lock.lock()
   1. T1获取锁成功,而T2和T3进入循环
   while(true){  //当加锁失败不会立即释放cpu,而是进行CAS自旋,即:令线程入队成功,然后等待被唤醒,最后重新获取锁资源。
       if(CAS获取锁成功){ //在并发时,lock是通过cas的方式对其中【一个线程】进行加锁成功的
         break//为什么是CAS获取锁成功呢?lock是通过修改state状态进行获取锁资源的,如果修改成功则获取锁资源
       }
       //如果没有获取锁成功,线程进入【阻塞】状态, 线程把自己的运行状态保存到内存里面,【等待被唤醒】
       //   这个内存肯定是个容器:可能是队列,也可能是hashset. 具体是哪个根据真实的业务场景选择。
       HashSet.add(Thread)   //该集合存储线程对象的引用(地址)
           LinkedQueued.put(Thread);
       LockSupport.park();      //不需要深挖park是怎么实现的,只需要知道park可以阻塞线程。
   }
   
   2. T1获取到锁,执行代码. 执行结束后,T1执行unlock操作,从集合里面取出下一个线程尝试获取锁。
    //我们的逻辑
    xxxxxx
    xxxxxx
lock.unlock()    
         //想一想,如果线程一直阻塞,每个线程都有一个线程栈空间,那么我们的内存不就溢出了吗?
       //所以线程不是一直阻塞的,而是等着别人来【唤醒】自己。
       //不是唤醒全部线程,而是唤醒【指定的线程】。
       Thread t =  HashSet.get();  
       Thread t = LinkedQueued.take();
       LockSupport.unpark(t); //通过线程引用,唤醒这个线程

二、Lock锁的三大核心

1.自旋(while);
2.LockSuport;
3.CAS(改变锁状态state,从无锁状态0改成状态1有锁,或者可重入锁);
一个重要的数据结构:queue队列,存储阻塞的线程。

三、ReentrantLock加锁解锁流程图

下一篇:ReentrantLock【公平锁和非公平锁】的【加锁和解锁】全过程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@来杯咖啡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值