美文网首页java
JUC.ReentrantLock

JUC.ReentrantLock

作者: 小明17 | 来源:发表于2019-06-03 18:49 被阅读0次

    ReentrantLock是JDK提供的一个可重入互斥锁,所谓可重入就是同一个锁允许被已经获得该锁的线程重新获得。可重入锁的好处可以在递归算法中使用锁,不可重入锁则导致无法在递归算法中使用锁。因为第二次递归时由于第一次递归已经占有锁,而导致死锁。

    1.默认构造函数是new一个非公平锁

    public ReentrantLock() {
            sync = new NonfairSync();
    }
    

    2.因为是独占式锁,需要实现AQS的tryAcquire函数和tryRelease函数

    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获得锁,成功则把占有锁的线程设置为当前线程,返回true。失败返回false。
    • 如果state不为0则说明该锁已经被其他线程获取,则检查获得锁的线程是否是当前线程以实现可重入特性,如果是,则更新state的值,并返回true。此处更新不需要CAS,因为只有当前线程可以操作state。
    • 其他情况返回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;
    }
    
    • 首先得到释放之后的状态值c
    • 检查当前释放锁的线程,如果不是已占有锁的线程则抛出异常,因为ReentrantLock是独占式锁,释放锁的线程一定是占有锁的线程
    • 如果c是等于0的,说明获取锁的所有函数都已经返回,则锁释放成功
    • 如果c不等于0,说明只是部分递归的函数返回,部分递归函数还未返回,则释放失败,锁依然被占有

    3.ReentrantLock的两个主要方法lock和unlock源码了解一下:

    public void lock() {
        sync.lock();
    }
    
    final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
    }
    

    该函数首先直接尝试CAS操作,成功则设置当前函数为占有锁的函数,返回,失败则调用acquire函数。acquire函数为AQS实现的模板方法,它尝试获得锁,成功则返回,不成功则进入等待队列直至获取成功。

    public void unlock() {
        sync.release(1);
    }
    
    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }
    

    调用tryRelease函数释放锁

    相关文章

      网友评论

        本文标题:JUC.ReentrantLock

        本文链接:https://www.haomeiwen.com/subject/kqjhxctx.html