ReetrantLock的看法

Lock是一个接口,其有很多种实现,Lock和sychronized关键词不同,Lock依赖aqs实现锁,没有应用到底层jvm等相关的技术,更适合应用层的扩展,实现方式很多,更方便更加灵活。

ReetrantLock:

实现了Lock接口
                                                                   

内部方法:
内部方法基本上都是由AQS(AbstractQueuedSynchronizer),这里有2个比较重要的类

  • FairSync                公平锁
  • NonfairSync          非公平锁

公平锁和非公平锁:

  • 公平锁:每个线程都能获取到锁,很少出现死等的情况,ReetrantLock中由一个FIFO队列实现
  • 非公平锁: 锁存在优先级或者抢占调度,Sychronized就是一类典型的非公平锁

默认非公平锁,线程抢锁直接对state进行CAS操作,不考虑是否有线程在队列中等待锁,抢到则服务,否则加入队列尾部

公平锁实现:

多了一个队列检查环节,hasQueuedPredecessors(查看对列中是否有后继节点)

AQS(AbstractQueuedSynchronizer)的概念

功能:

从功能上来说,AQS就是提供同步功能的一个解释类,提供2种不同的加锁方法, ReetrantLock和ReentrantReadWriteLock都依赖它

独占锁:在ReetrantLock中,只用到了它独占锁的方法
共享锁:ReentrantReadWriteLock实现

大致模型:

  • AQS内部维护了一个State变量(volatile),用于实现锁的可重入性
  • exclusive…用于存储当前占用锁的线程
  • AQS中维护了一个FIFO的队列,我们把它叫做CLH队列,队列的每个节点就是一个线程的封装类,CLH有两个指针,head和tail,head指向队列头部,tail指向队列尾部

    如果当前线程竞争锁失败,那么AQS会把当前线程以及等待状态信息构造成一个Node加入到同步队列中,同时再阻塞该线程。当获取锁的线程释放锁以后,会从队列中唤醒一个阻塞的节点(线程)。

AQS源码及实例分析

加锁过程

当有新的Thread进入时,如图例thread5将要进入锁竞争时
首先它会去用CAS操作去尝试获取锁,失败就进入CLH队列,抢到则进行下一步:
if state == 0:
如果为0则表明此时还没有线程抢到锁,"我是第一个",所以此时将state+1,接着set exclusiveOwnerThread = thread5

else:
不为0时说明有其他线程在占用锁,检查是否为当前线程(exclusiveOwnerThread)如果是则重入锁。
解锁过程

                              

排它锁和共享锁:
ReentrantLock默认排它锁

感谢您的阅读,本文由 YellowRifle 版权所有。如若转载,请注明出处:YellowRifle(https://yellowrifle.github.io/2019/10/23/ReetrantLock/
Mqtt
单点登录