并发内存模型之AQS——ReentrantLock加锁流程

ReentrantLock 是什么

是java 实现的公平锁/非公平锁,也是可重入锁

跟aqs(AbstractQueuedSynchronizer ) 什么关系

AbstractQueuedSynchronizer 翻译过来是抽象队列同步 是不是意味着aqs内部维护中一个队列。

1.下图是 ReentrantLock 内部实现 公平锁FairSyncaqs的关系

并发内存模型之AQS——ReentrantLock加锁流程_第1张图片

2.下图是 ReentrantLock 内部实现 公平锁NonfairSyncaqs的关系

并发内存模型之AQS——ReentrantLock加锁流程_第2张图片

3.aqs 内部维护的队列是什么样子的

简单看下aqs内部队列的实现

static final class Node {
//该节点的上一个节点
    volatile Node prev;
//该节点的下一个节点
    volatile Node next;
//持有该节点的线程    
     volatile Thread thread;
}

可以看出来aqs内部维护着一个Node 有点像LinkedList,所以aqs底层准确来说是由一个链表实现的

4.aqs 出了有个内部类是Node外,aqs这个类属性还维护着链表的头节点尾节点

//头节点
    private transient volatile Node head;
//尾节点
    private transient volatile Node tail;

ReentrantLock的加锁原理

标题【一键免费获取】《Android核心技术进阶资料》

先来一个逻辑图,ReentrantLock加锁的过程就是如此简单:
并发内存模型之AQS——ReentrantLock加锁流程_第3张图片
1、通过lock()方法加锁,通过unlock()方法释放锁;

2、调用lock()之后,内部会判断当前锁的状态,只有在state == 0成立的情况下锁才是空闲的。

3、在空闲状态下,并不能立刻加锁成功,还要判断等待队列中有没有等待的线程。如果没有则直接加锁成功,如果有则优先从队列中获取线程加锁。

4、如果state > 0则说明当前锁被其他线程持有,持有该锁的线程在exclusiveOwnerThread属性中关联。

5、判断exclusiveOwnerThread == currentThread 是否成立;如果成立说明当前线程持有该锁,则对state累加1(通过这种方式实现锁重入);

6、如果该锁不是当前线程持有,则把该线程加入到队列中等待。

ReentrantLock加锁逻辑简单明了,下面则对实现源码分析。

ReentrantLock 公平锁加锁流程

首先,根据我们传入的boolean值决定ReentrantLock为公平锁还是非公平锁。(默认为非公平锁)

我们调用lock()方法加锁时,底层实际为调用ReentrantLock持有的Sync对象的acquire(1)方法。

public void lock() {
     sync.acquire(1);
 }

acquire(1)方法调用tryAcquire(1)方法尝试加锁,失败后调用acquiredQueued(addWaiter(Node.EXECUSIVE),arg)方法将当前线程包装成一个Node节点加入到等待队列

   public final void acquire(int arg) {
     if (!tryAcquire(arg) &&
         acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
         selfInterrupt();
 }

tryAcquire()方法会首先判断锁是否空闲,如果空闲则用hasQueuePreProcessor()判断自己是否需要排队,如果不需要排队则CAS操作尝试获取锁,获取锁成功,则将持有锁的线程设置为自己。如果需要排队,则返回false,表示用tryAcquire(1)方法尝试获取锁失败,将自己加入到等待队列。

    @ReservedStackAccess
     protected final boolean tryAcquire(int acquires) {
         final Thread current = Thread.currentThread();
         int c = getState();
         //锁空闲
         if (c == 0) {
         //判断自己是否需要排队
             if (!hasQueuedPredecessors() &&
                 compareAndSetState(0, acquires)) { //不需要排队则用CAS获取锁
                 setExclusiveOwnerThread(current);//成功,则设置自己为持有锁的线程
                 return true;
             }
         } 
         else if (current == getExclusiveOwnerThread()) {  //锁不空闲,判断自己是否持锁
             int nextc = c + acquires;//持锁则重入
             if (nextc < 0)
                 throw new Error("Maximum lock count exceeded");
             setState(nextc);
             return true;
         }
         return false;//否则,返回尝试加锁失败
     }

如果tryAcquire(1)判断锁非空闲,则看是否为自己持有锁,若为自己持有,则重入。否则返回false,表示尝试获取锁失败,将自己加入到等待队列。(该方法分公平锁实现和非公平锁两种实现)

//判断自己是否需要排队
  public final boolean hasQueuedPredecessors() {
     Node h, s;
     //如果等待队列的head不为空
     if ((h = head) != null) {
         if ((s = h.next) == null || s.waitStatus > 0) {
             s = null; // traverse in case of concurrent cancellation
             for (Node p = tail; p != h && p != null; p = p.prev) {
                 if (p.waitStatus <= 0)
                     s = p;
             }
         }
         //判断是否有等待着的线程且不是自己
         if (s != null && s.thread != Thread.currentThread())
             return true;
     }
     //如果head为null,则不需要等待,因为没有等待队列
     return false;
 }

acquiredQueued(addWaiter(Node.EXECUSIVE),arg)会首先执行addWaiter()方法,该方法比较简单。

private Node addWaiter(Node mode) {
     Node node = new Node(mode);
   //大体逻辑就是判断等待队列是否为空,如果是空,则初始化之后再将自己插入,否则直接将自己插入队尾
  
     for (;;) {
         Node oldTail = tail;
         if (oldTail != null) {
             node.setPrevRelaxed(oldTail);
             if (compareAndSetTail(oldTail, node)) {
                 oldTail.next = node;
                 return node;
             }
         } else {
             initializeSyncQueue();
         }
     }
 }

然后再执行acquireQueued方法。首先判读自己是否是head的.next节点,如果是则tryAcquire(1)再次尝试获取锁,如果不是调用park()让自己睡眠。

final boolean acquireQueued(final Node node, int arg) {
     boolean interrupted = false;
     try {
         for (;;) {
             final Node p = node.predecessor();
             if (p == head && tryAcquire(arg)) {
                 setHead(node);
                 p.next = null; // help GC
                 return interrupted;
             }
             if (shouldParkAfterFailedAcquire(p, node)) //此处会多自旋一次
             //因为每个Node节点的waitStatus是系统默认值0,会返回false,自旋一次
             //即每一次当前节点会把前一个节点的状态改为-1,即SIGNAL状态
             //为啥不自己改自己呢?因为自己无法更改,如果在park前设置,但无法保证原子性
                 interrupted |= parkAndCheckInterrupt();
         }
     } catch (Throwable t) {
         cancelAcquire(node);
         if (interrupted)
             selfInterrupt();
         throw t;
     }
 }

非公平锁加锁流程

非公平锁和公平锁加锁过程最大的不同是tryAcquire(1)方法,非公平锁该方法的实现是调用了nonfairTryAcquire(acquires)。
即lock()—>Sync.acquire(1)---->tryAcquire(1)---->nonfairTryAcquire(acquires)。

@ReservedStackAccess
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            //非公平锁只要判断锁是空闲的,则直接尝试CAS获取锁,而不会判断自己是否需要排队
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

非公平锁如果用tryAcquire(1)获取锁失败,则后面的流程和公平锁一样。

你可能感兴趣的:(Android开发,android)