java之ReentrantLock

在讲RentrantLock之前需要先讲一下AQS和LockSupport,因为rentrantLock底层是用AQS实现的,而AQS中获取阻塞和唤醒底使用LockSupport实现的。

1、LockSupport实现

下面代码中,LockSupport.park方法是当前线程等待,直到获得许可,LockSupport.unpark方法则将线程作为参数传递,释放许可,让myThread能继续运行。

    static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println(Thread.currentThread() +": start park");
            LockSupport.park();
            System.out.println(Thread.currentThread() +": end park");
        }
    }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
        System.out.println(Thread.currentThread() +": start unpark");
        LockSupport.unpark(myThread);
        System.out.println(Thread.currentThread() +": end unpark");
    }

park和unpark方法类似于object默认的wait和notify,区别在于:

1、Object.wait需要在同步代码块中执行,而park则不需要

2、wait当中断时,则会响应中断抛出中断异常,park不需要

3、object.wait是对象才能调用,而park则任何线程中都能调用

正因为park和unpark是对线程的阻塞和唤醒。适合运用到 ReentrantLock的并发线程中,其他线程阻塞和唤醒中。

2、AQS

网上有很多讲解AQS机制的,都列出一大堆源码,这里都不在多说源码了,简单说一下基本原理,至于细节部分,可以直接看源码后细扣。AQS核心思想是:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制AQS是用CLH队列锁实现的,即将暂时获取不到锁的线程加入到队列中。

2.1 AQS的数据结构

AQS底层数据结构是一个CLH的虚拟双向队列,实际上是一个双向链表,而请求共享需要等待的线程则会加入同步队列中,如果使用condition,则会加入到等待队列中,每一个线程使用以下图中Node节点表示。Node节点包含pre,next,当前线程,waitStatus。

其中waitStatus包含四种状态:

// CANCELLED,值为1,表示当前的线程被取消
static final int CANCELLED =  1;
// SIGNAL,值为-1,表示当前节点的后继节点包含的线程需要运行,也就是unpark 
static final int SIGNAL    = -1;
// CONDITION,值为-2,表示当前节点在等待condition,也就是在condition队列中
static final int CONDITION = -2;
// PROPAGATE,值为-3,表示当前场景下后续的acquireShared能够得以执行 
static final int PROPAGATE = -3;
值为0,表示当前节点在sync队列中,等待着获取锁

3、 ReentrantLock实现原理

知道了上述两个知识点之后,lock.lock和lock.unlock方法内部到底是怎么实现的呢?

    public static void main(String[] args) {
        Lock lock = new ReentrantLock();
        MyThread t1 = new MyThread("t1", lock);
        MyThread t2 = new MyThread("t2", lock);
        t1.start();
        t2.start();
    }
   static class MyThread extends Thread {
        private Lock lock;
        public MyThread(String name, Lock lock) {
            super(name);
            this.lock = lock;
        }

        @Override
        public void run() {
            lock.lock();
            try {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                System.out.println("thread ==== " + Thread.currentThread() + " running");
            } finally {
                lock.unlock();
            }
        }
    }

上述代码中t1 和t2同时执行,当t1执行lock之后,t2则等待lock释放锁,等到t1执行unlock之后,t2则被唤醒执行下面操作。内部具体流程是怎么样的?

1、当t1执行lock之后,由于此时只有t1这一个线程,则直接将此线程设置为独占锁

2、当t2执行lock之后, 由于t1已经是独占锁了。所以此时t2则需要加入到同步队列中

(1)先初始化同步队列,创建一个head节点,

(2)将head指向t2线程

(3)将head节点状态设置为SIGAL,当前节点的后继节点包含的线程需要运行,可以执行unpark

(4)对t2执行LockSupport.park(),阻塞t2线程

3、t1执行unlock,除了释放自身的独占锁之后,后续对同步队列中的t2线程也有相关操作

(1)从后往前找,找到状态设置为SIGAL的节点,是head节点,然后对后续节点执行unpark操作,上述我们知道unpark,则是唤醒t2线程

(2)将head节点状态设置为0

4、由于之前t2在lock过程中,底层AQS代码是一个自旋,不断获取资源,t2线程被唤醒执行后,将t2自身将清空,head指向t2, next为null;最终达到的状态是sync queue中只剩下了一个结点,并且该节点除了状态为0外,其余均为null。

5、t2执行unlock,最后的状态和之前的状态是一样的,队列中有一个空节点,头节点为尾节点均指向它。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/370685.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

React Native学习记录

一、创建RN项目的时候是空文件夹的问题 1.使用npx react-native init RNDemos初始化项目的时候,会报错,模版错误,然后创建出来一个空的文件夹 2.如果出现这种情况,需要设置npm install -g react-native-cli 3.安装完成以后再次初…

Postgres与DynamoDB:选择哪个数据库

启动新项目时需要做出的决定之一是使用哪个数据库。如果您使用的是Django这样的包含电池的框架,那么没有理由再三考虑。选择一个受支持的数据库引擎,就可以了。另一方面,如果你使用像FastAPI或Flask这样的微框架,你需要自己做出这…

聚簇索引、回表与覆盖索引

聚簇索引一般指的是主键索引(如果存在主键索引的话)。 作为一个正常开发,建表时主键肯定是必须的。 而即使如果表中没有定义主键,InnoDB 会隐式选择一个唯一的非空索引代替。 所以我们就直接含糊点说: 聚簇索引就是…

crmebAI名片小程序全开源全端uniapp

应用介绍 AI名片小程序是一种基于人工智能技术的数字化智能名片,具有多种功能和特点。以下是AI名片小程序的简介: 智能化管理:AI名片小程序具备智能化的管理系统,用户可以方便地管理名片信息,包括个人信息、职位、公司…

jmeter-02切换中文,改为白色背景

文章目录 一、切换中文问题:jmeter设置中文后无法保存,下次启动还是英文 二、改为白色背景 一、切换中文 问题:jmeter设置中文后无法保存,下次启动还是英文 解决办法: 在jmeter路径下找到文件jmeter.bat开启编辑模式&…

如何在Shopee平台上进行手机类目选品?

在Shopee平台上进行手机类目的选品是一个关键而复杂的任务。卖家需要经过一系列的策略和步骤,以确保选品的成功和销售业绩的提升。下面将介绍一些有效的策略,帮助卖家在Shopee平台上进行手机类目选品。 先给大家推荐一款shopee知虾数据运营工具知虾免费…

指针的学习2

目录 数组名的理解 使用指针访问数组 一维数组传参的本质 冒泡排序 二级指针 指针数组 指针数组模拟二维数组 数组名的理解 数组名是数组首元素的地址 例外: sizeof(数组名),sizeof中单独放数组名,这里的数组名表示整个数组,计算的…

从零开始手写mmo游戏从框架到爆炸(三)— 服务启动接口与网络事件监听器

上一章我们完成了netty服务启动的相关抽象(https://blog.csdn.net/money9sun/article/details/136025471),这一章我们再新增一个全局的服务启动类,方便后续扩展。 服务启动 新增的两个类如下: 定义一个接口IServer …

6款超好用的IDEA插件,开发必备!

今天给大家介绍几款开发必备的IDEA插件: JRebel 热部署插件,让你在修改完代码后,不用再重新启动,很实用!但是,不是免费的,需要大家继续发挥下自己的聪明才智才能happy的使用 Json Parser 厌倦…

Linux 多线程 | 线程的概念

线程的概念 线程是一个执行分支,执行粒度比进程更细,调度成本更低; 线程是进程内部的一个执行流; 线程是CPU调度的基本单位,进程是承担分配系统资源的基本实体。 之前我们学习过虚拟地址空间的知识,知道…

SpringFramework实战指南(五)

SpringFramework实战指南(五) 4.3 基于 注解 方式管理 Bean4.3.1 实验一: Bean注解标记和扫描 (IoC)4.3.2 实验二: 组件(Bean)作用域和周期方法注解4.3.3 实验三: Bean属性赋值:引用类型自动装配 (DI)4.3.4 实验四: Bean属性赋值:基本类型属性赋值 (DI)4.3.5 实验五:…

区块链游戏解说:Axie Infinity 是什么

数据源:Axie Infinity Dashboard 作者:lesleyfootprint.network 什么是 Axie Infinity Axie Infinity 是一个引人入胜的区块链游戏,让玩家可以探索一个充满独特且可收藏的 NFT 生物(称为 Axies)的世界。 Axie Infin…

[AIGC] 21世纪Java与Go的相爱相杀

在21世纪的软件开发领域中,Java和Go这两门编程语言可谓是相爱相杀的存在。它们各自拥有着强大的特点和独特的优势,同时也存在着一些明显的竞争和冲突。让我们来看看这两门语言的故事,以及它们之间的深远意义。 文章目录 Java的魅力Go的魅力相…

【Simulink系列】——动态系统仿真 之 简单系统

引入 不同的系统具有不同的输入与输出。一般来说,输入输出数目越多,系统越复杂。最简单的系统只要一个输入一个输出(SISO),且其任意时刻的输出只与当前时刻的输入有关。 一、简单系统定义 对于满足下列条件的系统&a…

Qt拖拽事件,实现控件内项的相互拖拽

文章目录 1拖拽演示2 步骤3 实现 这里主要以QTableview控件为例,实现表格内数据的相互拖拽。 1拖拽演示 2 步骤 自定以QTableView类,在自定义类中重写拖拽事件: void dropEvent(QDropEvent *event); void dragEnterEvent(QDragEnterEvent *…

【c++】友元

友元提供了一种突破封装的方式&#xff0c;有时提供了便利。但是友元会增加耦合度&#xff0c;破坏了封装&#xff0c;所以友元不宜多用 友元分为&#xff1a;友元函数和友元类 1.友元函数 问题&#xff1a;现在尝试去重载operator<<&#xff0c;然后发现没办法将ope…

北斗卫星在物联网时代的应用探索

北斗卫星在物联网时代的应用探索 在当今数字化时代&#xff0c;物联网的应用已经深入到人们的生活中的方方面面&#xff0c;让我们的生活更加智能便捷。而北斗卫星系统作为我国自主研发的卫星导航系统&#xff0c;正为物联网的发展提供了强有力的支撑和保障。本文将全面介绍北…

瑞_23种设计模式_工厂模式

文章目录 1 什么是工厂模式案例案例代码 2 简单工厂模式&#xff08;Simple Factory&#xff09;2.1 简单工厂模式的结构2.2 案例改进——简单工厂模式2.3 案例改进代码实现2.4 简单工厂模式优缺点2.5 拓展——静态工厂 3 工厂方法模式&#xff08;Factory Method&#xff09;★…

[学习笔记]刘知远团队大模型技术与交叉应用L6-基于大模型文本理解和生成介绍

介绍 NLP的下游运用可以分为&#xff1a;NLU(理解)和NLG(生成) 信息检索&#xff1a;NLU 文本生成&#xff1a;NLG 机器问答&#xff1a;NLUNLG 大模型在信息检索 大模型在机器问答 大模型在文本生成 信息检索-Information Retrieval (IR) 背景 谷歌搜索引擎目前同时集成了…

复旦大学NLP团队发布86页大模型Agent综述

复旦大学自然语言处理团队&#xff08;FudanNLP&#xff09;发布了一篇长达86页的综述论文&#xff0c;探讨了基于大型语言模型的智能代理的现状和未来。该论文从AI Agent的历史出发&#xff0c;全面梳理了基于大型语言模型的智能代理现状&#xff0c;包括LLM-based Agent的背景…