java学习-reentrantlock-fair和unfair


关于reentrantLock 中 fair 和 unfair体现

对于 reentrantLock 其核心实际是利用AbstractQueueSynchronizer (AQS);

对于reentrant就是通过判断当前线程是否相等作为可重入条件

AQS 实际就是一个双向链表组成的队列,对于队列中存在的节点实际就是等待获取锁的线程;

对于AQS一般是设置在有效时间内获取到锁,当获取锁失败的情况下才会被添加到队列中,对于队列中的等待者实际就是通过循环一直尝试获取锁,当在尝试获取锁失败的情况下且未达到获取锁等待时间时,会尝试将当前线程(这里主要是针对的当前执行循环的线程)挂起,当在释放锁的情况下,会通知当前被挂起的线程,重新执行获取锁的过程; 直到获取锁成功或等待获取锁超时或竞争锁的线程消亡,节点才会被移除掉;

对于AQS实际队列的形式满足先进先出(FIFO)的特点;

对于reentrantLock 中的 fair 和 unfair 其主要体现在 当同时存在 未保存到队列中的竞争者 和 队列中排队等候的竞争者 在上一个线程释放锁之后,其获取锁的顺序优先级

  • 关于unfair,其核心就是在 当同时存在 未保存到队列中的竞争者 和 队列中排队等候的竞争者时,其并没有优先级的关系,属于公平竞争加锁过程,当使用cas加锁成功后,如果是不属于AQS中的加锁成功,则AQS中的节点会继续等待;如果是AQS中的head 加锁成功,则AQS中的head移除队列;而对于不存在与队列中的竞争者会被追加到链表的尾部作为新的tail节点
  • 关于fair,其核心就是 在执行加锁操作时,首先判断队列中是否存在等待的节点,如果存在等待的节点则会终止尝试加锁过程,而是直接追加到队列中;反之,则直接尝试加锁;
    public final boolean hasQueuedPredecessors() {
        // The correctness of this depends on head being initialized
        // before tail and on head.next being accurate if the current
        // thread is first in queue.
        Node t = tail; // Read fields in reverse initialization order
        Node h = head;
        Node s;
        return h != t && // 首先判断队列中是否存在数据,当 h!=t时说明队列中存在数据
           // 当队列中存在数据时,判断当前head节点是否已出队,当s==null说明已出队
          // 当s!=null时,需要判断s节点的线程是否是当前线程,
            //当其等于当前线程时,说明队列中下一个等待者就是当前线程
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }    
 protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() && // 首先判断队列中是否存在数据,以及存在的数据下一个等待者是否就是本身
                    compareAndSetState(0, acquires)) {
                    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;
        }

对于fair 中 hasQueuedPredecessors中出现的判断情况

  1. h !=t ,当结果为false时后续的判断都不需要执行,对于为false说明 h==t,代表队列为空,整体结果返回false;反之为true则表示队列中存在数据;
  2. (s=h.next) == null,当结果为true时表示当前head节点可能已出队,则后续的流程无需执行,整体结果返回true;当判断s节点不为空时,则继续执行后续的判断
  3. s.thread != Thread.currentThread(),判断当前head节点的后续节点是否为当前线程,如果为false说明是当前线程,则整体返回结果为false;如果为true,说明不是当前线程,则整体结果返回true;

因此对于fair  锁释放(state 为 0)情况下,非队列中的竞争者能直接进行尝试加锁的情况就只有以下两种情况

  1. 队列为空
  2. 当前请求(线程)存在于队列中,且就是下一个等待者节点

除以上两种情况外其余情况都会直接追加到AQS等待队列中

 简单总结一下,对于fair主要是针对AQS队列中元素的公平