可重入排他锁ReentranLock源码浅析 Lock接口简介

1.引子

”ReentranLock“单词中的“Reentrant”就是“重入”的意思,这是一个支持重入的排他锁,即同一个线程中可以多次获得同步状态,常表现为lock()方法的嵌套使用(类似于synchronized代码类嵌套),而在AQS类注释的使用说明中的Mutex是一个不可重入的锁,只要一个线程获得了同步状态,再次tryAcquire(int)返回false。

另外ReentranLock还支持公平锁和非公平锁的的选择,公平锁是指等待时间长的线程优先获取锁,非公平锁则对所有线程一视同仁;synchronized关键字只支持非同步锁,这是由JVM的本地C++代码决定的。

公平锁虽能解决某些线程长久等待,减少“饥饿”的发生概率,但公平锁没有非公平锁的效率高,因为它要频繁地进行线程上下文切换,一般情况下使用非公平锁。ReentranLock可以通过设置构造方法的参数来决定使用公平锁或非公平锁,其默认的无参构造方法创建的是一个非公平锁。

ReentranLock与synchronized的区别对比在以前的帖子Lock接口简介中已经说明过了,这里不再赘述。

2.类结构

 由类结构图可以看出,ReentranLock类中有Sync FairSync NofairSync这三个静态内部类。Sync是一个继承于AQS的一个抽象类(AQS相关的内容在之前的帖子),它表示公平锁与非公平锁的通用或共同之处的抽象。FairSync 和NofairSync都继承自Sync,分别表示公平锁、非公平锁.它们两者的类定义差别很小,只有尝试获取锁的方法不同,FairSync使用自已定义的tryAcquire(int),而NotFairSync将tryAcquire(int)委托给父类Sync的nonfairTryAcquire(int)方法实现,而两者尝试释放锁的方法都是继承父类Sync的tryRelease(int)

ReentranLock的构造方法

ReentranLock有一个Sync类型的成员变量sync,这个成员变量在构造方法中被实例化。无参的构造方法,将sync实例化为一个NonfairSync对象,此时的ReentranLock表示一个非公平锁。带一个布尔型参数的构造方法,根据参数就会创建相应的公平锁/非公平锁。

    private final Sync sync;
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * Performs {@link Lock#lock}. The main reason for subclassing
         * is to allow fast path for nonfair version.
         */
        abstract void lock();

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

        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

        protected final boolean isHeldExclusively() {
            // While we must in general read state before owner,
            // we don't need to do so to check if current thread is owner
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        final ConditionObject newCondition() {
            return new ConditionObject();
        }

        // Methods relayed from outer class

        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }

        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }

        final boolean isLocked() {
            return getState() != 0;
        }

        /**
         * Reconstitutes the instance from a stream (that is, deserializes it).
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }
Sync源代码

 Sync的一些其他方法

        //当前线程是独占线程
        protected final boolean isHeldExclusively() {
           
            return getExclusiveOwnerThread() == Thread.currentThread(); 
        }
        //给当前锁绑定一个新的条件
        final ConditionObject newCondition() {
            return new ConditionObject();
        }

        //获得锁的线程
        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }
        //锁被当前线程获取重复获取的次数
        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }
        //锁否已经被某一线程获取到了
        final boolean isLocked() {
            return getState() != 0;
        }

        /**
         * Reconstitutes the instance from a stream (that is, deserializes it).
         */
        private void readObject(java.io.ObjectInputStream s)
                throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }

3.可重入的实现机制

锁的可重入是指,某线程在获取到锁之后还能获取到此锁而不会被此锁给阻塞。要保证这点要解决这两个方面的问题:

1) 线程再次获取锁。当要确定当前线程是否已经获取到了锁,如果是,那么再次获取锁也必须是成功的。代码的实现:每次获取锁将AQS的state属性自增,state表示锁被线程获取到的次数。

2) 锁释放。一线程获取了n次锁,那么也需要经过n次释放,锁才能完成审美观点释放,其他线程才能获取到此锁。代码实现思路:每次释放锁让AQS的state属性自减,当state为0时,表明锁被完全释放了。

非公平锁获取锁调用的底层方法nonfairTryAcquire(int)

        /**
         * 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)) {//cas成功,当前线程获取同步状态成功
                    setExclusiveOwnerThread(current);//设置当前线程为锁的独占线程
                    return true;
                }
            }
            /**
             *当前线程是独占线程,即当前线程之前已经获取到了同步状态.
             * 进入重入处理
             */
            else if (current == getExclusiveOwnerThread()) {
                /**
                 *  nonfairTryAcquire(int)方法的被调用链上层是acquire(1),这里的acquires为1
                 *  相当于state自增
                 */
                int nextc = c + acquires;
                if (nextc < 0) //nextc超过int类型表示的最大范围
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);//将state属性自增
                return true;
            }
            return false;
        }

非公平锁获取锁调用的底层方法tryAcquire(int)

protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            /*
             *与nonfairTryAcquire(int)方法相比,此处有些不同,
             * 只是多了"hasQueuedPredecessors()",没有前驱节点,才进行CAS更新state。
             * (每个节点代表一个线程)只有在没有其他线程比当前线程等待更久的情况下才尝试获取锁
             */
            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;
    }

公平锁和非公平锁的释放锁的方法unlock()都是调用父类Sync的tryAcquire(int)

        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;//传入的参数releases为1
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();//当前线程不是独占线程,即当前线程没获取到同步状态,怎么能释放同步状
            boolean free = false;
            if (c == 0) {
                /**
                 * 锁当前被重复获取的次数为0,锁已经疲彻底释放了,其他线程能获取此锁了
                 */
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);//state属性自减
            return free;
        }

参考:《Java并发编程的艺术》方腾飞

猜你喜欢

转载自www.cnblogs.com/gocode/p/SourceCodeAnalysisOfReentranLock.html