Java多线程---ReentrantLock解析

Lock函数

ReentrantLock中有两种Sync,一种是NonfairSync另一种是FairSync。它两同时继承Sync类。可以在创建ReentrantLock的时候指定用那种锁。

在FairSync的lock方法中,会调用acquire(1),而acquire方法如下

 /**
 * Acquires in exclusive mode, ignoring interrupts.  Implemented
 * by invoking at least once {@link #tryAcquire},
 * returning on success.  Otherwise the thread is queued, possibly
 * repeatedly blocking and unblocking, invoking {@link
 * #tryAcquire} until success.  This method can be used
 * to implement method {@link Lock#lock}.
 *
 * @param arg the acquire argument.  This value is conveyed to
 *        {@link #tryAcquire} but is otherwise uninterpreted and
 *        can represent anything you like.
 */
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

acquire中会判断:

  1. !tryAcquire(arg):尝试去获取锁,但是获取失败
  2. acquireQueued(addWaiter(Node.EXCLUSIVE),arg):创建一个新的Node并且添加到链表尾部,再调用acquireQueued方法,判断该节点是否在waiting的状态,需要被interrupt。 如果满足的话,则会调用selfInterrupt,其中会调用Thread.currentThread().interrupt(),进行当前线程的中断操作

而在FairSync中重写了tryAcquire方法

 /**
     * Fair version of tryAcquire.  Don't grant access unless
     * recursive call or no waiters or is first.
     */
    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;
    }
}

在这个方法中:

  1. 首先获取当前尝试加锁的线程
  2. 获取当前锁的状态
  3. 判断当前是否有被加锁,如果没有的话,那么则判断队列中是否已经有等待的了,如果没有等待的话,再通过CAS操作赋值acquires,如果满足的话,那么调用setExclusiveOwnerThread,将持有锁的线程设置为当前线程
  4. 如果当前state不为0,也就是锁已经存在了的话,那么则判断尝试获取锁的线程是否为当前线程,如果为当前线程的话,那么则再将锁+1,然后设置锁状态返回true
  5. 否则返回false

在hasQueuedPredecessors函数中,会判断,如果头尾节点不相同,并且头节点的后继为空或者头节点的后继中线程不是当前线程,就说明等待队列不为空。

如果等待队列为空的话,那么就通过CAS操作设置state,如果设置成功的话,那么就将当前线程设置成持有锁的线程,并且返回true,说明已经成功获取锁了。

否则,如果state不为0的话,那么则判断当前线程是不是就是已经持有锁的线程,如果是的话,那么就把当前状态+请求的值(1),然后设置当前的State值,饭后返回true,说明获取锁成功。否则,返回false,说明获取锁失败。

只有当获取锁失败,并且成功添加到链表尾部,才会被中断。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏微信公众号:Java团长

synchronized与Lock的区别与使用详解

昨天在学习别人分享的面试经验时,看到Lock的使用。想起自己在上次面试也遇到了synchronized与Lock的区别与使用。于是,我整理了两者的区别和使用情况...

17020
来自专栏Java呓语

单元测试以及JUnit框架解析

我们都有个习惯,常常不乐意去写个简单的单元测试程序来验证自己的代码。对自己的程序一直非常有自信,或存在侥幸心理每次运行通过后就直接扔给测试组测试了。然而每次测试...

17520
来自专栏java 成神之路

CountDownLatch 源码分析

35170
来自专栏格子的个人博客

Java源码阅读之ReentrantLock - lock和unLock方法

如果需要使用或者了解ReentrantLock,证明已经步入并发编程领域了,这里理论基础不多提,需要的自行查阅资料。

10520
来自专栏JavaQ

高并发编程-ReentrantLock非公平锁深入解析

ReentrantLock是一个可重入的互斥锁,它不但具有synchronized实现的同步方法和同步代码块的基本行为和语义,而且具备很强的扩展性。Reentr...

12940
来自专栏Phoenix的Android之旅

你可能不了解的Synchonized和ReentrantLock

面试中经常会问到的一类问题是多线程相关的, 比如如何处理Android中的多线程通信,如何处理并发问题。归根结底,处理Java的并发,都离不开锁。 我们将花三到...

12420
来自专栏cmazxiaoma的架构师之路

JUC之CountDownLatch的源码和使用场景分析

最近工作不饱和,写写文章充充电。何以解忧,唯有Coding。后续更新的文章涉及的方向有:ThreadPoolExecutor、Spring、MyBatis、Re...

29710
来自专栏犀利豆的技术空间

徒手撸框架--实现 RPC 远程调用

微服务已经是每个互联网开发者必须掌握的一项技术。而 RPC 框架,是构成微服务最重要的组成部分之一。趁最近有时间。又看了看 dubbo 的源码。dubbo 为了...

16620
来自专栏猿天地

用aop加redis实现通用接口缓存

系统在高并发场景下,最有用的三个方法是缓存,限流,降级。 缓存就是其中之一,目前缓存基本上是用redis或者memcached。 redis和memcached...

36570
来自专栏我是攻城师

理解AbstractQueuedSynchronizer提供的独占锁和共享锁语义

Doug Lea前辈在JDK5中编写的AbstractQueuedSynchronizer抽象同步框架非常精辟,整个代码里没有使用像synchronized这样...

18920

扫码关注云+社区

领取腾讯云代金券