架构系列——通过ReentrantLock源码分析给对象上锁的原理

简介: 架构系列——通过ReentrantLock源码分析给对象上锁的原理

一、整体结构

该类位于java.util.concurrent.locks包下

首先看一下结构:


ReentrantLock中:

3个类Sync、NonfairSync、FairSync

若干个方法:lock()、tryLock()、unlock()、acquireInterruptibly(int arg)等

具体流程

二、三个内部类

1.Sync

abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;
        //抽象lock方法
        abstract void lock();
        //该TryAquire默认给非公平锁使用
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            //判断锁的状态
            int c = getState();
            //锁为空闲
            if (c == 0) {
              //进行CAS操作,设置当前线程持有锁
                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;
        }
    //释放锁
        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            //释放锁的线程必须为持有锁的线程
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
              //state为0才能释放锁
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }
    //如果当前线程同步是以独占的方式进行的,则返回true
        protected final boolean isHeldExclusively() {
            // While we must in general read state before owner,
            // we don't need to do so to check if current thread is owner
            return getExclusiveOwnerThread() == Thread.currentThread();
        }
    //新生成的条件
        final ConditionObject newCondition() {
            return new ConditionObject();
        }
        // Methods relayed from outer class
    //获得占用同步状态的线程
        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }
    //获得当前线程持有锁的数量,即重入次数
        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }
    //是否被锁定
        final boolean isLocked() {
            return getState() != 0;
        }
         //自定义饭序列化逻辑
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }

2.NonfairSync

    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;
         //首先基于AQS进行CAS操作,将0->1.若成功,则获取锁成功
         //否则,执行AQS的正常同步状态获取逻辑
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

3.FairSync

static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;
        final void lock() {
            acquire(1);
        }
        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;
        }
    }

三、主要方法

注:流程图省略了其他相关类的一些方法,只讲ReentrantLock类里面的方法,比如AQS(AbstractQueuedSynchronizer)类里面的acquere方法中省略了acquireQueued()和selfInterrupt()。


如果tryAcquire(arg)返回成功,则说明当前线程成功获取了锁(第一次获取或者重入),由取反和&&可知,整个流程到这结束,只有当前线程获取锁失败才会执行后面的判断。addWaiter(Node.EXCLUSIVE)

部分代码描述了当线程获取锁失败时如何安全的加入同步等待队列。这部分代码可以说是整个加锁流程源码的精华,充分体现了并发编程的艺术性。

1.lock()方法

1. public void lock() {
2.         sync.lock();
3.     }

1.1 如果该lock是NonfairSync类的实例,则进入NonfairSync的lock()里:

最底层还是进入nonfairTryAcquire()方法里

1.2 如果该lock是FairSync类的实例,则进入FairSync的lock()里:

最底层是进入tryAcquire()方法里

2.tryLock()方法

1. public boolean tryLock() {
2. return sync.nonfairTryAcquire(1);
3.     }

一步到位,直接调用nonfairTryAcquire()方法


3.unlock()方法

1. public void unlock() {
2.         sync.release(1);
3.     }

4.lockInterruptibly()方法

    public void lockInterruptibly() throws InterruptedException {
        //调用父类AbstractQueuedSynchronizer里的方法
        sync.acquireInterruptibly(1);
    }
    //这是父类AbstractQueuedSynchronizer的方法
    public final void acquireInterruptibly(int arg)
            throws InterruptedException {
        //中断线程,如果成功中断,则抛出异常
        if (Thread.interrupted())
            throw new InterruptedException();
        if (!tryAcquire(arg))
            doAcquireInterruptibly(arg);
    }

这是Lock锁和synchronized锁相比独有的特性之一,获取锁的线程是可以被中断的,而且中断的时候抛出异常;

四、其它

由上面的图可知,ReentrantLock里面的最最基本的方法是tryAcquire()nonfairTryAcquire()tryRelease()

把这两个方法搞懂了,这个类也就明白很大一部分了

另外要理解两点:

1.公平锁与非公平锁的区别

FairSync中整个tryAcquire()代码只比nonfairTryAcquire()方法多了这么一行!!!

主要判断:是否有其它线程在队列的最前面。

以此来保证有序性,也就是先来后到!

这就是公平!

而不公平就是可以插队拿到锁!

2.重入锁的实现原理

1. 在线程获取锁的时候,如果已经获取锁的线程是当前线程的话则直接再次获取成功;

2. 由于锁会被获取n次,那么只有锁在被释放同样的n次之后,该锁才算是完全释放成功

final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();//获取当前线程实例
    int c = getState();//获取state变量的值,即当前锁被重入的次数
    if (c == 0) {   //state为0,说明当前锁未被任何线程持有
        if (compareAndSetState(0, acquires)) { //以cas方式获取锁
            setExclusiveOwnerThread(current);  //将当前线程标记为持有锁的线程
            return true;//获取锁成功,非重入
        }
    }
    else if (current == getExclusiveOwnerThread()) { //当前线程就是持有锁的线程,说明该锁被重入了
        int nextc = c + acquires;//计算state变量要更新的值
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);//非同步方式更新state值
        return true;  //获取锁成功,重入
    }
    return false;     //走到这里说明尝试获取锁失败
}
相关文章
|
2月前
|
存储 监控 算法
园区导航系统技术架构实现与原理解构
本文聚焦园区导航场景中室内外定位精度不足、车辆调度路径规划低效、数据孤岛难以支撑决策等技术痛点,从架构设计到技术原理,对该系统从定位到数据中台进行技术拆解。
69 0
园区导航系统技术架构实现与原理解构
|
3月前
|
存储 消息中间件 canal
zk基础—2.架构原理和使用场景
ZooKeeper(ZK)是一个分布式协调服务,广泛应用于分布式系统中。它提供了分布式锁、元数据管理、Master选举及分布式协调等功能,适用于如Kafka、HDFS、Canal等开源分布式系统。ZK集群采用主从架构,具有顺序一致性、高性能、高可用和高并发等特点。其核心机制包括ZAB协议(保证数据一致性)、Watcher监听回调机制(实现通知功能)、以及基于临时顺序节点的分布式锁实现。ZK适合小规模集群部署,主要用于读多写少的场景。
|
4月前
|
存储 人工智能 自然语言处理
为什么混合专家模型(MoE)如此高效:从架构原理到技术实现全解析
本文深入探讨了混合专家(MoE)架构在大型语言模型中的应用与技术原理。MoE通过稀疏激活机制,在保持模型高效性的同时实现参数规模的大幅扩展,已成为LLM发展的关键趋势。文章分析了MoE的核心组件,包括专家网络与路由机制,并对比了密集与稀疏MoE的特点。同时,详细介绍了Mixtral、Grok、DBRX和DeepSeek等代表性模型的技术特点及创新。MoE不仅解决了传统模型扩展成本高昂的问题,还展现出专业化与适应性强的优势,未来有望推动AI工具更广泛的应用。
1197 4
为什么混合专家模型(MoE)如此高效:从架构原理到技术实现全解析
|
4月前
|
机器学习/深度学习 算法 测试技术
图神经网络在信息检索重排序中的应用:原理、架构与Python代码解析
本文探讨了基于图的重排序方法在信息检索领域的应用与前景。传统两阶段检索架构中,初始检索速度快但结果可能含噪声,重排序阶段通过强大语言模型提升精度,但仍面临复杂需求挑战
121 0
图神经网络在信息检索重排序中的应用:原理、架构与Python代码解析
|
9月前
|
存储 SQL 关系型数据库
MySQL进阶突击系列(03) MySQL架构原理solo九魂17环连问 | 给大厂面试官的一封信
本文介绍了MySQL架构原理、存储引擎和索引的相关知识点,涵盖查询和更新SQL的执行过程、MySQL各组件的作用、存储引擎的类型及特性、索引的建立和使用原则,以及二叉树、平衡二叉树和B树的区别。通过这些内容,帮助读者深入了解MySQL的工作机制,提高数据库管理和优化能力。
|
5月前
|
消息中间件 存储 设计模式
RocketMQ原理—5.高可用+高并发+高性能架构
本文主要从高可用架构、高并发架构、高性能架构三个方面来介绍RocketMQ的原理。
1034 21
RocketMQ原理—5.高可用+高并发+高性能架构
|
4月前
|
Java 开发者 Spring
Spring框架 - 深度揭秘Spring框架的基础架构与工作原理
所以,当你进入这个Spring的世界,看似一片混乱,但细看之下,你会发现这里有个牢固的结构支撑,一切皆有可能。不论你要建设的是一座宏大的城堡,还是个小巧的花园,只要你的工具箱里有Spring,你就能轻松搞定。
172 9
|
5月前
|
人工智能 自然语言处理 安全
基于LlamaIndex实现CodeAct Agent:代码执行工作流的技术架构与原理
CodeAct是一种先进的AI辅助系统范式,深度融合自然语言处理与代码执行能力。通过自定义代码执行代理,开发者可精准控制代码生成、执行及管理流程。本文基于LlamaIndex框架构建CodeAct Agent,解析其技术架构,包括代码执行环境、工作流定义系统、提示工程机制和状态管理系统。同时探讨安全性考量及应用场景,如软件开发、数据科学和教育领域。未来发展方向涵盖更精细的代码生成、多语言支持及更强的安全隔离机制,推动AI辅助编程边界拓展。
218 3
基于LlamaIndex实现CodeAct Agent:代码执行工作流的技术架构与原理
|
8月前
|
Java Linux C语言
《docker基础篇:2.Docker安装》包括前提说明、Docker的基本组成、Docker平台架构图解(架构版)、安装步骤、阿里云镜像加速、永远的HelloWorld、底层原理
《docker基础篇:2.Docker安装》包括前提说明、Docker的基本组成、Docker平台架构图解(架构版)、安装步骤、阿里云镜像加速、永远的HelloWorld、底层原理
733 90

热门文章

最新文章