java并发包之ReentrantLock

2019-01-08  本文已影响0人  kokokokokoishi

在阅读本文前,需要对AQS有大概的了解

ReentrantLock,即重入锁,表示持有资源的锁的线程可对资源进行重复加锁,其支持公平和非公平两种模式,其默认使用非公平锁。
在ReentrantLock中,通过将加锁的操作委托给ReentrantLock$Sync来实现,Sync继承
AbstractQueuedSynchronizer,实现了tryRelease,同时定义了nonfairTryAcquire供其非公平实现NonfairSync调用。

ReentrantLock#lock

public void lock() {
        sync.lock(); //委托给sync
}

我们先来看一下非公平锁

/**
     * 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);
        }
    }

在lock时,如果对statecas成功,则当前线程直接获取锁,并把自己设置位锁的持有者,否则调用acquire, AQS 使用了模板方法

 public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

我们要关注的实际上是NonfairSync#tryAcquire,可以看到,这里直接调用了Sync提供的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;
        }

在这里,同样如果state 为0,则尝试cas,并把自己设置为锁的持有者,若state不为0,则检查自己是否为锁的持有者,若已持有,则state加一,可以看到这里使得ReentrantLock可重入,下面我们看一下其公平实现

static final class FairSync extends Sync {
        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;
        }
    }

这里唯一的区别是在尝试对state进行CAS操作前加上了!hasQueuedPredecessors()
这个判断,这是用来判断是否有线程排队在当前线程之前,若有,则当前线程进入AQS同步队列。而在非公平实现中,当前线程可越过排队的线程直接尝试获取锁。

那么为什么默认要使用非公平锁呢,因为在非公平锁中,一个线程在释放了锁之后,再次竞争锁的时候,很可能继续获得锁,虽然有可能导致线程饥饿,但减少了上下文的切换,如果使用公平锁,则不会出现某一线程连续竞争到锁的情况,但会加大上下文切换,减小吞吐量

上一篇 下一篇

猜你喜欢

热点阅读