JUC之ReentrantLock

JUC之ReentrantLock

前言

学习juc系列的可重入锁之前,可以先去看看aqs的实现,这个很关键,毕竟aqs是核心。
传送门:也是我写的嘿嘿嘿,写的很详细
学习了 synchronized的之后,面试肯定还会问到ReentrantLock
// 可以看到ReentrantLock这个类的构造函数 对FairSync,或者是NonfairSync这个类进行了一下初始化

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

    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

而Sync 这个类呢,就是继承了AstractQueueqSynchronizer 这个类,所以说aqs 真的很重要

NonfairSync

final void lock() {
// 如果线程只有一次请求,只需要执行setExclusiveOwnerThread 方法
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

如果你看懂了aqs,那么肯定知道,实现了aqs的类,肯定需要实现一个tryAcquire(int acquires) 方法,也就是这个方法,非公平的可重入锁,来看看它怎么写的吧。

   final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            // 前面的lock方法已经设置过了一次,这里再加上它,因为可能我进来的时候,上一个线程已经释放了锁了。
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            // 如果是同一个线程的话就对state进行增加
            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;
        }

看到了上面的代码 是不是觉得非公平的可重入锁,获取资源实在是太简单了 。没错就是很简单,如果你知道了彻底懂了aqs的话。
那么它为什么叫做非公平锁呢?
因为aqs中有一个addWaiter的方法,会将没有竞争到资源的线程加入到等待队列中,如果head结点释放资源了,就会去唤醒,后面存活的等待的结点。但是释放资源的同时呢,也把state置为呢0,那么新来的线程是不是执行lock 里面的compareAndSetState(0, 1),更加有优势呢,等待队列中的结点在acquireQueued方法中进行获取的时候,tryAcquire 进行会失败,并且将首节点标记位signal,然后它自己会继续挂起等待下去。

FairSync

可以看到对比非公平锁,我们这里多了一个方法hasQueuedPredecessors

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

// 这个呢 就是非公平锁,加这个方法的目的是什么,我们了解了非公平锁了对吧,那么就想想公平锁为什么需要加这个方法,公平锁就是为了保证顺序对吧,保证的是什么顺序呢,其实就是等待队列的顺序,也就是clh队列中的顺序,那么看代码就可以知道,如果队列中不是只有一个结点,并且首结点的下一个结点的线程不等于当前线程的话,它是必须返回true的,如果它刚好又不是独占线程的话,那么tryAcquire这个方法就会返回false,它就只能乖乖的加入到等待队列中去了。

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());
    }

最后来看看tryRelease(int arg) 方法
这个方法的关键就是什么时候返回true,去执行unparkSuccessor方法,如果state等于0了,那么就可以返回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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值