AQS锁机制原理

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/paul_wei2008/article/details/25722023
ReentrantReadWriteLock 与 ReentrantLock 核心就是Sync(AQS子类)及AQSSynchronized基于内部对象锁JVM指令的级别
ReentrantReadWriteLock 引用传入 内部类 ReadLock和WriteLock,将其Sync传入两个内部类,如果读锁如果发现没有排他锁exclusiveCount则可以上锁  
ReentrantLock 机制原理:
ReentrantLock就是基于Sync的,而Sync就是一种AQS子类,其中核心机制AQS都实现
Sync及AQS的核心实现(源码级别)

AQS核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源的设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制AQS是用CLH队列锁实现的,即将暂时获取不到锁的线程加入到队列中。

那么首先看一下CLH队列锁的数据结构及实现算法。

(a)CLH队列的数据结构(如图):


简述:CLH队列是一个虚拟的双向队列(虚拟的双向队列即不存在队列实例,仅存在结点之间的关联关系)。AQS是将每条请求共享资源的线程封装成一个CLH锁队列的一个结点(Node)来实现锁的分配的。具体构建队列的算法是这样的:

假设: 有共享资源S目前正被L3线程占用,此时有L1、L2线程分别对资源S进行lock操作以及获取锁后进行unlock操作。具体的流程如下:

(1)由于目前资源S被占用,所以将线程L1包装成一个CLH队列的Node,将这个Node的前驱(prev)指向当前对列里的队尾,放入队尾这个操作采用了CAS原语(原子操作)。如果当前的队尾为NULL,那么就建一个虚拟的Header,然后将T1线程挂载到虚拟Header下。核心代码如下:

Ps:  addWaiter就是放入队列的操作。

 

Ps:采用CAS将节点加入到队尾,如果队尾为null进入enq操作。

Ps:创建了一个虚拟的Header

(2) L2线程请求资源S,那么它和L1线程一样将自己加入到队尾,L2的prev指向L1,L1.next指向L2(双向队列嘛)。

(3) 当L3释放资源即unlock的时候,唤醒与L3关联的下一个节点,同时释放当前节点。关键代码:

               

 (b)每个结点类的属性及方法信息:

属性简述:CANCELLED:表示因为超时或者中断,结点被设置为取消状态,被取消的状态结点不应该去竞争锁。SIGNAL:表示这个结点的继任结点被阻塞了,因为等待某个条件而被阻塞。CONDITION:表示这个结点在队列中,因为等待某个条件而被阻塞。这几个是常量属性默认值为:

这几个常量用来设置waitStatus属性。

Thread属性表示关联到这个结点的线程。Prev和next就是关联前后结点的索引变量。NextWaiter 记录的是这个结点是独占式还是可共享的属性。

ReentrantLock当中的部分实例代码:

1.     两个构造函数(可见默认使用的非公平锁的分配机制):

2.     Lock方法的实现其实就是直接代理了Sync lock的实现:

3.     TryLock方法也是一样的,都是代理自Sync

4.     解锁方法

展开阅读全文

没有更多推荐了,返回首页