多线程AQS系列2 - Reentantlock源码解读

  • 扯皮:
    上篇的CountDownLatch可能太过简单的理论了,几乎0代码了。不太适合0开始学习的。这篇尽量详细一些,如果太详细全是代码的文章也很难受!所以写文章还真是个技术过。
    我只知道synschonized锁为什么还要知道ReentantLock呢?,就拿现实中的真锁来说,锁大门的 用大锁,锁小门的用小锁,锁文具盒的用迷你锁,没有真正的好,只有真正的适合!也就是没有一种锁适用于所有场景!
  • Reentantlock
  • Reentant:百度翻译 意思是:【再进去的】
  • 所以这个类起个名就是:可重入锁。但是synschonized也是具有可重入性,他叫啥名,他就叫synschonized。或者更准确些就是Reentantlock就叫Reentantlock,但是具有可重入性。
  • 分类(公平、不公平)

不公平锁:public static ReentrantLock lock = new ReentrantLock();
公平锁: public static ReentrantLock lock = new ReentrantLock(true);
为啥呢?直接看构造方法,不解释。在此不讨论公平不公平的事!后文继续研究!

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

用法很简单:加锁,解锁即可!
想用公平锁或非公平锁都行,根据业务场景由你定!
然后就保证了这段业务逻辑代码的多线程环境下的安全问题。
lock.lock();
业务逻辑代码区域…
finally {
lock.unlock();
}

  • 分析背后的源码,不公平锁为例

lock后,直接进入到这里。

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

1000个线程同时执行了lock.lock(); 然后进入到这个 方法里。
compareAndSetState(0, 1),AQS实现的CAS操作,最快的那个线程执行了这句话,把state的值设置为1了。然后返回true。setExclusiveOwnerThread(Thread.currentThread());把一个AQS的变量exclusiveOwnerThread设置为当前线程。然后这个线程就去执行业务逻辑代码了。
接下来剩余的999个线程执行 compareAndSetState(0, 1),执行失败,因为第一个线程把state设置为1了,希望他的值是0,无法执行成功,返回false。
剩下的999个线程执行acquire(1);

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

tryAcquire(arg):执行以下方法

final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            //假设现在第一个线程没有完成 当前c==1 所以无法进入
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            //刚刚线程1赋值的变量是线程1 假设我是剩下的999中的某个线程 所以在此无法进入
            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;
        }

假设线程1执行特别耗时的业务逻辑,一直没完成呢。所以这999个线程在上面的方法中只能返回false了。就到了上面的上面的acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
这两段代码总结一句话:这999个线程都得先后入队列,且都变成阻塞的状态 。只能等待被唤醒。不想把进入队列的代码粘贴过来了。

线程1终于完成了业务逻辑处理任务。
执行了lock.unlock(); 方法了。线程1依次执行以下两个方法。

public final boolean release(int arg) {
        if (tryRelease(arg)) {//线程1执行到这返回true
            Node h = head;
            if (h != null && h.waitStatus != 0)
            //唤醒操作,细节代码不粘了,就是要去唤醒那个队列 了,先唤醒第一个,队列第一个线程唤醒后,开始了类似于刚刚线程1的执行线路了
                unparkSuccessor(h);
            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);//把那个AQS的变量置空了
            }
            setState(c);//线程1终于把state的值设置为0了。
            return free;
        }
  • 还有一个问题
    唤醒第一个线程后,它接下来往哪执行?再看下整体的代码。
    所有的线程都是执行.lock()后进入阻塞队列的。被唤醒后肯定是接着往下执行业务逻辑代码了。白话:你当时执行到哪了,在哪进的队列(lock.lock()这个方法进去的),醒了后接着往下执行就是了。

lock.lock();
业务逻辑代码区域…
finally {
lock.unlock();
}

  • 独占功能是如何体现的
    在Node管理中:
    在唤醒队列中的线程时,唤醒头结点后,好的,头结点醒了,继续执行业务任务去,等头结点完事后再回来唤醒现在的头结点。而不同于共享式的CountDownLatch。唤醒时一连串的全部唤醒。

结束
好多细节代码依旧还是没有,只是一个整体的思路。有了整体的认识,具体的细节就比较好看了 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值