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学习)