JAVA进阶之路-ReentrantLock的公平锁和非公平锁

Posted LuckyZhouStar

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA进阶之路-ReentrantLock的公平锁和非公平锁相关的知识,希望对你有一定的参考价值。

通过学习AQS的原理,我们了解到,AQS内部是通过一个FIFO同步队列来完成同步状态的管理。当线程获取当前状态的时候(内部其实就是更新操作),同步器会将当前的状态构建成一个node节点对象,将其放入到同步队列中,同时底层调用LockSupport.park(this)来阻塞当前线程,释放cpu。当同步状态释放的时候,会把首节点进行环形,使其再次尝试获取同步状态。

那么内部的公平和非公平是如何来实现的呢?

ReentrantLock 的构造函数

public ReentrantLock() 
        sync = new NonfairSync();
    

    /**
     * Creates an instance of @code ReentrantLock with the
     * given fairness policy.
     *
     * @param fair @code true if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) 
        sync = fair ? new FairSync() : new NonfairSync();
    

我们可以看到,默认使用的是非公平锁,除非构造函数中传递参数True。

公平锁和非公平锁的区别点

非公平锁

 final boolean nonfairTryAcquire(int acquires) 
            final Thread current = Thread.currentThread();
            int c = getState();
            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;
        

公平锁

  protected final boolean tryAcquire(int acquires) 
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) 
            // 1. 和非公平锁相比,这里多了一个判断:是否有线程在等待
                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;
        
    

//查询是否有其他的线程已经处于等待状态

  public final boolean hasQueuedPredecessors() 
        Node h, s;
        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;
        
        return false;
    

总结

非公平锁的实现在刚开始获取锁的时候,直接使用了一次CAS去尝试获取锁,不成功才会构建node节点。而在公平锁中会首先判断是否已经有等待中的线程。这就是公平锁与非公平锁的差异所在。

1.非公平锁在调用lock后,会首先进行CAS抢锁,如果这个时候抢占到了,就直接返回true了
2.相对来说,非公平所性能会比较好一点,吞吐量比较大。

以上是关于JAVA进阶之路-ReentrantLock的公平锁和非公平锁的主要内容,如果未能解决你的问题,请参考以下文章

java ReentrantLock 公平锁 非公平锁 测试

java中ReentrantLock实现,公平锁和非公平锁,AQS并发队列,

java多线程进阶LOCK锁及其原理

java多线程进阶LOCK锁及其原理

java多线程20 : ReentrantLock中的方法 ,公平锁和非公平锁

Java多线程12:ReentrantLock中的方法