ReentrantLock的公平锁与非公平锁的实现

ReentrantLock是jdk中提供的一种用于多线程同步的锁机制,相对于Synchronizes,提供了更加精确的控制功能,ReentrantLock提供了两种Sync内部实现类,分别是NonfairSync和fairSync,都是继承类Sync,类Sync又继承与AbstractQueuedSynchronizer,AbstractQueuedSynchronizer提供了锁机制实现的大部分功能,两者的类图如下,

  

ReentrantLock中提供了公平锁和非公平锁两种实现,默认是非公平锁,因为线程在唤醒后需要重新触发抢锁的动作,如果在唤醒新的线程前,有线程可以抢到锁,那么就无需唤醒等待队列中的线程,这样可以避免线程的唤醒操作,提高系统的性能。

注意:

正常情况下,公平锁和非公平锁都提供了等待队列的功能,新的线程如果没有获取到锁,那么就按照顺序加入到等待队列中,正在运行的线程的释放锁后,从等待队列中顺序唤醒线程。但是非公平锁则允许‘插队’:当一个线程请求非公平锁时,如果在发出请求的同时该锁变成可用状态,那么这个线程会跳过队列中所有的等待线程而获得锁。

 

AbstractQueuedSynchronizer存在一个变量,state,表示当前的锁是否被占用,1表示有一个线程被占用,2表示有一个线程两次调用了Lock()方法,

state变量则通过volatile+CAS操作保证了变量的线程安全性。

公平锁的实现如下:

    /**
     * Sync object for fair locks
     */
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        final void lock() {
            acquire(1);
        }

        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        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;
        }
    }
acquire的函数会调用AbstractQueuedSynchronizer的acquire的函数,acquire中有会调用子类的tryAcquire方法,
public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

在公平锁的tryAcquire函数中,会调用hasQueuedPredecessors()函数判断等待队列是否为空,或者自己是第一个等待Node,如果是那么返回true,如果不是那么返回false,将自己加入到等待队列中。

hasQueuedPredecessors的实现如下:

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 &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }

非公平锁的实现如下:

/**
     * Sync object for non-fair locks
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }
nonfairTryAcquire的实现如下:
 /**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
         */
        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;
        }
在非公平锁的lock函数和nonfairTryAcquire的函数中,会调用compareAndSetState(0, 1)方法,这是个CAS函数,如果当前的state的值为0,那么表明锁没有被抢占,
那么就获取,如果两次都获取失败,那么就将自己放入等待队列,如果获取成功,那么就直接执行代码,不用进入等待队列,这样就实现了抢占锁的机制。
posted @ 2017-08-02 17:02  王久勇  阅读(648)  评论(0)    收藏  举报