详解AQS三:ReentrantLock非公平锁原理

Published on 2024-12-18 19:17 in 分类: 博客 with 狂盗一枝梅
分类: 博客

上一篇文章《详解AQS二:ReentrantLock公平锁原理》中,详细分析了ReentrantLock公平锁的AQS实现原理,本篇文章将会继续分析ReentrantLock非公平锁的实现原理。

首先看看非公平锁NonfairSync的源码,以方便分析和公平锁FairSync的区别

static final class NonfairSync extends Sync {
    private static final long serialVersionUID = 7316153563782823691L;
    
    final void lock() {
        /**
         * 区别一:获取锁的时候在调用acquire获取锁之前允许先使用CAS方式直接获取锁
         * 无需进入队列等待
         */
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }

    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }
}

nonfairTryAcquire方法调用的是Syn中的方法

final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        /**
         * 区别二:这里的if条件没有再判定!hasQueuedPredecessors(),
         * 这样即使节点前面有正在等待的节点,它也会不管不顾的去抢占锁资源
         */
        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;
}

上面的代码注释已经写的很清楚,ReentrantLock的公平锁和非公平锁的区别全部都在NonfairSyncFairSync的抢占锁代码的区别上:

  1. lock方法:非公平锁上来就尝试CAS抢占锁,不管现在AQS队列中到底有没有线程在排队。这显然对正在队列中等待获取锁的线程不公平。
  2. tryAcquire方法:这是AQS中定义的钩子方法,在当前锁空闲的情况下,非公平锁也是上来就CAS抢占锁丝毫不管正在排队的AQS队列中的线程,而公平锁却要先调用hasQueuedPredecessors方法判定当前节点前面还有没有线程在排队,如果有线程等在当前线程的前面,则不允许抢占锁,乖乖去排队。

所以非公平锁和公平锁和AQS无关,仅仅是实现类中lock方法和tryAcquire方法的实现区别。

那么,公平锁和非公平锁的效率谁更高?

使用JMH微基准测试(详情参考《微基准测试工具JMH》)测试使用ReentrantLock公平锁和非公平锁对Long类型自增一亿次所用时间,比较结果如下:

锁类型 自增一亿次所用时间(秒)
FairSync 2273.097(误差68.516秒)
NonfairSync 170.939(误差25.037秒)

可以看到公平锁效率虽然公平,但是它的执行效率在高并发效率下要比非公平锁效率低很多,非公平锁效率大概是公平锁效率的13倍。

由此可见,在代码的世界里,公平不一定是件好事啊。。。。


#java #多线程编程
复制 复制成功