ReentrantLock原理ReentrantReadWriteLock原理

Posted anduodefeng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ReentrantLock原理ReentrantReadWriteLock原理相关的知识,希望对你有一定的参考价值。

一、ReentrantLock原理

ReentrantLock是一个可重入的独占锁,同时只能有一个线程可以获取该锁,其他获取该锁的线程会被阻塞而放入该锁的AQS阻塞队列里面。ReentrantLock最终是使用AQS来实现的,并且根据参数来决定其内部是一个公平锁还是非公平锁,默认是非公平锁。

public ReentrantLock(){
    sync = new NonfairSync();
}
public ReentrantLock(boolean fair){
    sync = fair ? new FairSync() : new NonfairSync();
}

Sync类直接继承自AQS,它的子类NonfairSync和FairSync分别实现了获取锁的非公平和公平策略。AQS中的state状态值标识线程获取该锁的可重入次数,默认情况下,state=0表示没有线程获取锁,当一个线程获取到锁的时候,会尝试使用CAS修改state的值+1,如果该线程获取成功,就记录该锁的持有者是当前线程,当这个线程在没有释放锁的情况下第二次获取该锁之后,state状态值被设置成2,也就是重入的次数;当线程释放锁的时候,释放一次,state-1,直到state变成0之后,该锁才能被其他线程再次获取。

  • 获取锁
public void lock(){
     sync.lock();
}

可以看到ReentrantLock获取锁委托给了sync的lock方法,sync的实现,由传入的参数确定是公平锁实现还是非公平锁实现;

首先先看一下非公平锁的实现:

final void lock(){
      if(compareAndSetState(0,1){
       setxxxxx(Thread.currentThread);   //cas修改state成功,设置锁持有者是当前线程
    }else{
        acquire(1);    //cas修改state失败,调用AQS的acquire,再次尝试获取锁,如果还 
                             //不成功,放入AQS阻塞队列;
    }
}    

acquire方法里面,比较核心的是调用了tryAcquire(int args)方法,

技术图片

AQS没有定义tryAcquire的实现,它需要子类自己定制化,ReentrantLock的重写tryAcquire方法如下:

技术图片

 

 

 可以看到,在这个方法里,会再次尝试着cas修改state状态获取锁,如果失败了,就返回false,放到AQS阻塞队列中。

非公平锁的体现:如果线程A进入tryAcquire方法的代码(4)时,state != 0,那么线程A就放到了AQS的阻塞队列中;后面线程B进入了tryAcquire方法中,进入到代码(4)时,发现state=0了,那么线程B就可以直接获取锁。虽然线程A先执行的,线程B是后执行的,但是获取到锁的却是后来的线程B,这就是非公平锁的体现。

其次是公平锁的实现:

技术图片

 

 

 公平性策略的实现主要依赖于:hasQueuedPredecessors()方法:

技术图片  返回false,即该线程可以获取锁;否则,该线程不能获取锁,由阻塞队列的头结点获取锁。【公平锁的体现】;

 

 

 如果当前线程节点有前驱节点则返回true,否则如果当前AQS队列为空或者当前线程节点是AQS的第一个节点则返回false(即:该线程可以获取锁)。其中如果h==t 则说明当前队列为空,直接返回false;如果h!=t并且s==null,说明有一个线程要作为AQS的第一个节点入队列,那么返回true;如果h!=t并且s!=null和s.thread!=Thread.currentThread()则说明队列里的第一个元素不是当前线程,那么也返回true。

二、ReentrantReadWriteLock原理

ReentrantLock是独占锁,同时只能有一个线程获取该锁,而实际中会有读多写少的场景,ReentrantLock满足不了这个需求,所以有了ReentrantReadWriteLock类,它可以允许多个线程可以同时获取读锁。它的内部维护了一个ReadLock和WriteLock,他们依赖Sync实现具体功能,也同样提供了公平锁和非公平锁。但是AQS中只维护了一个state状态,一个state怎么标识读和写两种状态?ReentrantReadWriteLock使用了state的高16位表示读状态,低16位表示写状态。

以上是关于ReentrantLock原理ReentrantReadWriteLock原理的主要内容,如果未能解决你的问题,请参考以下文章

ReentrantLock原理详解

ReentrantLock原理ReentrantReadWriteLock原理

ReentrantLock原理,ReentrantLock和synchronized区别

从ReentrantLock的实现看AQS的原理及应用

ReentrantLock实现原理

源码分析ReentrantLock实现原理