可重入锁

可重入锁表示如果你已经获取了锁,如果你想再次获取该锁,依然能够正常获取到,不会因为之前已经获取过还没释放而阻塞。synchronized关键字是隐式的可重入锁,表现在synchronized修饰的同步方法内递归调用自己不会阻塞。jdk中实现Lock接口的可重入锁ReentrantLock是如何实现可重入的呢?在阅读这篇文章之前,我假设你已经读过Lock内的同步器,对锁的实现有一定的了解。

可重入锁实现要点

  • 获取锁后,再次获取该锁时;判断当前线程是否是已经获取锁的线程,若是,则通过;否则,阻塞。
  • 释放锁时,如果该线程获取了n(n>=1)次锁,则需要释放n次,才能释放成功,返回true;否则,返回false。

代码实现

  • 获取可重入锁(非公平锁)同步状态的局部代码如下:
        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;
        }

代码中发现,如果当前线程就是已经占有锁的线程,则同步状态值进行增加,并返回true。


  • 释放可重入锁(非公平锁)的局部代码如下:
        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;//同步状态值为初始值0时,返回true;否则,返回false
        }

代码中发现同步状态值0是锁是否成功释放的标志。


  • 获取可重入锁(公平锁)的局部代码如下:
        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;
        }

与非公平锁获取同步状态相比,唯一的区别是判断引用当前线程的当前节点是否有前驱节点,如果返回true,说明有更早的节点在等待获取锁,则当前节点需要等到前驱节点获取并释放锁后才能够继续获取锁。至于释放锁,与非公平锁并无区别。

参考

  1. 并发编程的艺术

你可能感兴趣的:(可重入锁)