ReentrantLock非公平锁理解

一直理解,ReentrantLock支持公不锁与非公平锁,公平锁即先申请先得到锁,非公平锁相把,即锁释放时,所有线程同时竞争锁。今天读了ReentrantLock源码,发现自己解决的非公平锁与源码实现不同。非公平锁并不是所有线程同时竞争锁,而是新线程第一次竞争锁时,和线程步队列中的第一个线程进行竞争锁,从而达到非公平。 开始怀疑人生了,这也不是决对的非公平,于是上网查了一下,从一个博客下面,有一段描述,说的非常清楚


通过分析ReentrantLock中的公平锁和非公平锁的实现,其中tryAcquire是公平锁和非公平锁实现的区别,下面的两种类型的锁的tryAcquire的实现,从中我们可以看出在公平锁中,每一次的tryAcquire都会检查CLH队列中是否仍有前驱的元素,如果仍然有那么继续等待,通过这种方式来保证先来先服务的原则;而非公平锁,首先是检查并设置锁的状态,这种方式会出现即使队列中有等待的线程,但是新的线程仍然会与排队线程中的对头线程竞争(但是排队的线程是先来先服务的),所以新的线程可能会抢占已经在排队的线程的锁,这样就无法保证先来先服务,但是已经等待的线程们是仍然保证先来先服务的,所以总结一下公平锁和非公平锁的区别:

1、公平锁能保证:老的线程排队使用锁,新线程仍然排队使用锁。

2、非公平锁保证:老的线程排队使用锁;但是无法保证新线程抢占已经在排队的线程的锁


以下为类AbstractQueuedSynchronizer的方法队,ReentrantLock中的非公平锁获取失败的线程进行线程同步队列后,依靠下面的方法进行自旋再次获取锁,可以看到只有一个条件会从方法中返回,就是前驱节点是头点结点并且成功获取锁。

    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

猜你喜欢

转载自blog.csdn.net/tony820418/article/details/83583397