ReentrantLock支持公平锁和非公平锁,默认使用非公平锁。
主要记录公平锁里面的实现
通过源码可以发现公平锁的加锁方法
模拟ReentrantLock的加锁过程。
自定义一个Lock进行实现
public interface Lock {
void lock();
void unLock();
}
在ReentrantLock实现类里面,有几个变量
/**
* 0 表示未加锁状态
* > 0 表示当前lock是加锁状态
*/
private int state;
/**
* 独占模式
* 同一时刻只有一个县城可以持有锁,其他的线程,在为获取到锁时,会被阻塞
*/
private Thread exclusiveOwnerThread;
Node封装节点,里面包含有前置节点和引用节点和线程信息
static final class Node{
// 前置节点引用
Node prev;
// 后置节点引用
Node next;
// 封装的线程本尊
Thread thread;
public Node(Thread thread) {
this.thread = thread;
}
public Node() {
}
}
在源码中,加公平锁的时候,主要是进行该段代码逻辑获取加锁
private void acquireQueued(Node node,int arg){
// 只有当前node成功获取到锁以后, 才会跳出自旋
for (;;){
//
// 1. 当前node 是head的后继节点. 才有这个权限
Node pred = node.prev;
// 当前node 拥有抢占权限
//
if(pred == head && tryAcquire(arg)){
// 这里面, 说明当前线程 竞争锁成功啦。
// 1.设置当前head 为当前线程的node
// 2. 协助原始head 出队
setHead(node);
pred.next = null ; // help GC
return;
}
// 将当前线程挂起
LockSupport.park();
}
}
private Node addWaiter(){
Node newNode = new Node(Thread.currentThread());
// 如何入队
// 1. 找到newNode的前置节点
// 2.更新newNode.prev = 前置节点
// 3. CAS更新tail为 newNode
// 4.更新pred.next = newNode
// 前置条件: 队列已经有等待者node了,当前node 不是第一个进入对的node
Node pred = tail;
if(pred != null){
newNode.prev = pred;
// 当前线程成功入队
if(compareAndSetTail(pred,newNode)){
pred.next = newNode;
return newNode;
}
}
// 1.tail == null 队列时空对象
// 2.cas设置失败了,被其他线程抢先一步了。
enq(newNode);
return newNode;
}
/**
* 自旋入队,只有成功后才返回
*
* 1.tail == null 队列时空对象
* 2.cas设置失败了,被其他线程抢先一步了。
*/
private void enq(Node node){
for(;;){
// 第一种情况: 队列时空
// 当前线程是第一个去抢占锁失败的线程
// head节点 任何时候 都代表当前占用锁的线程
if(tail == null){
// 说明当前线程 给当前持有锁的线程 补充 head 操作成功
if(compareAndSetHead(new Node())){
//
tail = head;
// 还会继续自旋
}else {
// 说明当前队列中已经有node了,这里是一个追加node的过程
Node pred = tail;
if(pred != null){
node.prev = pred;
// 当前线程成功入队
if(compareAndSetTail(pred,node)){
pred.next = node;
return ;
}
}
}
}
}
}
在公平锁加锁的过程中,还有一段逻辑是获取锁的过程
private boolean tryAcquire(int arg){
if(state == 0){
// 条件1: 取反后值为true,表示当前线程前面没有等待者
// 条件2: lock方法可能有多线程调用,使用CAS,成立表示当前线程抢锁成功
if(!hasQueuedPredecessor() && compareAndSetState(0,arg)){
// 抢锁成功
// 1.需要将exclusiveOwnerThread 设置为当前进入的线程
this.exclusiveOwnerThread = Thread.currentThread();
return true;
}
// 当前锁被占用的时候来到此处
// 并且更新state值
}else if(Thread.currentThread() == this.exclusiveOwnerThread) {
// 里面不存在并发
// 说明当前线程为持锁线程, 需要返回true,
int c = getState();
c = c + arg;
// 越界判断
this.state = c;
return true;
}
// 什么时候返回false?
// 1.CAS加锁失败
// 2.state > 0 且 当前线程不是占用者线程
return false;
}