当前位置: 首页 > news >正文

并发-Executor框架笔记

Executor框架

jdk5开始,把工作单元与执行机制分离开来,工作单元包括Runable和Callable,执行机制由Executor框架来提供。

Executor框架简介

Executor框架的两级调度模型

  • Java线程被一对一映射为本地操作系统线程
    • java线程启动会创建一个本地操作系统线程
    • java线程终止操作系统线程也会被回收
    • 操作系统会调度所有线程并将它们分配给可用的cpu
  • 在上层,java多线程程序通常把应用分解为若干任务,然后使用用户级调度器将这些任务映射为固定数量的线程。在底层,操作系统内核将这些线程映射到硬件处理器上
  • 应用通过Executor框架控制上层调度,下层由操作系统内核控制,下层调度不受应用程序控制。

在这里插入图片描述

Executor框架的结构与成员

Executor框架结构
  • 主要由任务,任务执行和异步计算结果组成

    • 任务:包括被执行任务需要实现的接口:Runnable和Callable
    • 任务的执行:包括任务执行机制的核心接口Executor,以及继承自Executor的ExecutorServie接口。(ThreadPoolExecutor和ScheduledThreadPoolExecutor两个关键类实现了)
    • 异步计算的结果:包括接口Future和实现Future接口的FutureTask类
  • 类和接口

  • 在这里插入图片描述

    • Executor是一个接口,是Executor框架的基础,将任务的提交与任务的执行分离开来
    • ThreadPoolExecutor是线程池的核心实现类,用来执行被提交的任务
    • ScheduledThreadPoolExecutor是一个实现类,可以在给定的延迟后运行命令,或者定期执行命令。比Timer更灵活,功能更强大。
    • Future接口和实现Future接口的FutureTask类,代表异步计算的结果
    • Runnable接口和Callable接口的实现类,都可以被ThreadPoolExecutor或ScheduledThreadPoolExecutor执行
  • 使用:

    • 主线程创建实现Runnable或Callable接口的任务对象,工具类Executors可以把一个Runnable对象封装为一个Callable对象(Executors.callable(Runnable task)或Executors.callable(Runnable task,Object result))
    • 可以把Runnable对象直接交给ExecutorService执行(ExecutorService.execute(Runnable command)),或者吧Runnable对象或Callable对象提交给ExecutorService执行(ExecutorService.submit(Runnable task)或ExecutorService.submit(Callable task))
    • 执行ExecutorService.submit(…),将会返回一个实现Future接口的对象,也可以创建FutureTask然后直接交给ExecutorService执行
    • 主线程可以执行FutureTask.get()方法来等待任务执行完成。主线程也可以执行FutureTask.cancel来取消此任务
Executor框架的成员
  • ThreadPoolExecutor:通常使用工厂类Executors创建

    • FixedThreadPool:创建固定线程数的FixedThreadPool

      • 适用于为了满足资源管理的需求,需要限制当前线程数量的应用场景,适用于负载比较重的服务器

      • public static ExecutorService newFixedThreadPool(int nThreads)
        public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
        
    • SingleThreadExecutor:创建单个线程

      • 适用于需要保证顺序地执行各个任务,并且在任意时间点,不会有多个线程是活动的应用场景

        public static ExecutorService newSingleThreadExecutor()
        public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)
        
    • CachedThreadPool:创建一个会根据需要创建新线程

      • 大小无界的线程池,适用于执行很多短期异步任务的小程序,或负载教轻的服务器

      • public static ExecutorService newCachedThreadPool()
        public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory)
        
  • ScheduledThreadPoolExecutor:通常使用工厂类Executors创建

    • 创建ScheduledThreadPoolExecutor:包含若干线程的ScheduledThreadPoolExecutor

      • 适用于需要多个后台线程执行周期任务,同时为了满足资源管理的需求需要限制后台线程数量的应用场景

      • public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
        public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)
        
    • 创建SingleThreadScheduledExecutor:包含一个线程的ScheduledThreadPoolExecutor

      • 适用于需要单个后台线程执行周期任务,同时需要保证顺序地执行各个任务的应用场景

      • public static ScheduledExecutorService newSingleThreadScheduledExecutor(int corePoolSize)
        public static ScheduledExecutorService newSingleThreadScheduledExecutor(int corePoolSize, ThreadFactory threadFactory)
        
  • Future接口

    • Future接口和Future接口的FutureTask类用来表示异步计算的结果

    • 把Runnable接口或Callable接口的实现类提交给ThreadPoolExecutors或ScheduledThreadPoolExecutors时,会返回给一个FutureTask对象

    • <T> Future<T> submit(Callable<T> task)
      <T> Future<T> submit(Runnable task, T result)
      Future<> submit(Runnable task)
      
  • Runnable接口和Callable接口

    • Runnable不会返回结果,Callable会返回结果

    • 可以把Runnable包装成Callable

    • public static Callable<Object> callable(Runnable task)
      
    • 可以把Runnable和一个待返回的结果包装成一个Callable

    • public static <T> Callable<T> callable(Runnable task, T result)
      
    • 把callable对象提交给执行时,submit会返回一个FutureTask对象

      • 执行get方法等待任务执行完成,任务执行完成后get方法将返回该任务的结果

ThreadPoolExecutor详解

构成组件

  • corePool:核心线程池大小
  • maximumPool:最大线程池大小
  • BlockingQueue:用来暂时保存任务的工作队列
  • RejectedExecutionHandler:当ThreadPoolExecutor已经关闭或者饱和时,execute方法将要调用的Handler

创建类型

  • FixedThreadPool
  • SingleThreadExecutor
  • CachedThreadPool

FixedThreadPool详解

固定线程数线程池

public static ExecutorService newFixedThreadPool(int nThreads){return new ThreadPoolExecutor(nThreads,nThreads, 0L,TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())
}
  • corePoolSize 和maximumPoolSize都被设置为创建FixedThreadPool时指定的参数
  • 当啊线程池中的线程数大于corePoolSize时,keepAliveTime为多余的空闲线程等待新任务的最长时间,超过这个时间后多余的线程将被终止
  • keepAliveTime设置为0,多余空闲线程会被立即终止

流程

  1. 如果当前运行线程数少于corePoolSize,则创建新线程来执行任务
  2. 在线程池完成预热后(当前运行的线程数等于corePoolSize),将任务加入LinkedBlockingQueue
  3. 线程执行完1中的任务后,会在循环中反复从LinkedBlockingQueue获取任务执行
  • 使用无界队列LinkedBlockingQueue作为线程池工作队列,使用无界队列作为工作队列会对线程池带来影响
    • 当线程池中的线程数达到corePoolSize后,新任务将在无界队列中等待,因此线程池中的线程数不会超过corePoolSize
    • 由于上条,使用无界队列时,maximumPoolSize将是一个无效参数
    • 由于上条和上上条,使用无界队列时keepAliveTIme将是一个无效参数
    • 由于使用无界队列,运行中的FixedThreadPool不会拒绝任务

SingleThreadExecutor详解

使用单个worker线程的Executor

public static ExecutorService newSingleThreadExecutor(){return new ThreadPoolExecutor(1,1, 0L,TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())
}
  • corePoolSize 和maximumPoolSize都被设置为1
  • keepAliveTime设置为0,多余空闲线程会被立即终止
  • 使用无界队列LinkedBlockingQueue作为线程池的工作队列

工作流程

  1. 如果当前运行的线程数少于corePoolSize,则创建一个新线程来执行任务
  2. 在线程池完成预热后,将任务加入LinkedBlockingQueue
  3. 线程执行完1中的任务后,会在一个无限循环中反复从LinkedBlockingQueue获取任务来执行

CachedThreadPool详解

根据需要创建新线程的线程池

public static ExecutorService newCachedThreadPool(int nThreads){return new ThreadPoolExecutor(0,Integer.MAX_VALUE, 60L,TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>())
}
  • corePoolSize设置为0
  • maximumPoolSize被设置为Integer.MAX_VALUE
  • keepAliveTime设置为60L,线程池中的空闲线程等待新任务的最长时间是60秒,空闲线程超过60秒将会被终止
  • 使用没有容量的SynchronousQueue作为线程池的工作队列
  • 如果主线程提交的任务速度高于maximumPool中线程处理任务的速度时,CachedThreadPool会不断创建新线程,极端情况下,会因为创建过多线程为耗尽cpu和内存资源

流程:

  1. 首先执行SynchronousQueue.offer(Runnable task)。如果当前maximumPool中有空闲线程正则执行SynchronousQueue.poll,那么主线程执行offer操作与空闲线程执行的poll操作配对成功,主线程把任务交给空闲线程执行,execute()方法执行完成;否则执行步骤2
  2. 当初始maximumPool为空,或者maximumPool中当前没有空闲线程时,将没有线程执行SynchronousQueue.poll.这种情况下,步骤1 将失败,此时CachedThreadPool会创建一个新线程执行任务,execute方法执行完成
  3. 在步骤2中新创建将任务执行完后,会执行SynchronousQueue.poll,这个poll操作会让空闲线程最多在SynchronousQueue中等待60s,如果60s内主线程提交了一个新任务,那么这个空闲线程将执行主线程提交的新任务,否则这个空闲线程将终止。由于空闲60秒的空闲线程会被终止,因此长时间保持空闲的CachedThreadPool不会使用任何资源。

ScheduledThreadPoolExecutor详解

  • 继承自ThreadPoolExecutor
  • 主要用来在给定的延迟之后运行任务,会定期执行任务。
  • 可以在构造函数中指定多个对应的后台线程数

ScheduledThreadPoolExecutor运行机制

  • DelayQueue是一个无界队列。

主要两部分

  • 当调用ScheduledThreadPoolExecutor的scheduleAtFixedRate方法或者scheduleWithFixedDelay方法时,会向ScheduledThreadPoolExecutor的DelayQueue添加一个实现了RunnableScheduledFuture接口的ScheduledFutureTask
  • 线程池中的线程从DelayQueue中获取ScheduledFutureTask,然后执行任务。

ScheduledThreadPoolExecutor为了实现周期性的执行任务,对ThreadPoolExecutor做了如下修改

  • 使用DelayQueue作为任务队列
  • 获取任务的方式不同
  • 执行周期任务后,增加了额外的处理

ScheduledThreadPoolExecutor的实现

ScheduledFutureTask成员变量:

  • long time:表示这个任务将要被执行的具体时间
  • long sequenceNumber:表示这个任务被添加到ScheduledThreadPoolExecutor中的序号
  • long period:表示任务执行的间隔周期

DelayQueue封装了一个优先级队列,这个优先级队列会将队列的任务根据time排列,小的在前,如果time相同,比较sequenceNumber,小的在前

ScheduledThreadPoolExecutor执行某个周期任务步骤

  • 线程从DelayQueue中获取已到期的ScheduledFutureTask,到期任务是指ScheduledFutureTask的time大于等于当前时间
    • 获取Lock
    • 获取周期任务
      • 如果PriorityQueue为空,当前线程到Condition中等待
      • 如果PriorityQueue的头元素的time时间比当前时间大,到condition中等待到time时间
      • 获取PriorityQueue的头元素,如果不为空,则唤醒condition中等待的所有线程
    • 释放Lock
  • 线程执行ScheduledFutureTask
  • 线程修改ScheduledFutureTask的time后边变为下次将要被执行的时间
  • 线程把这个修改time之后的ScheduledFutureTask放回到DelayQueue中
    • 获取Lock
    • 添加任务
      • 向PriorityQueue添加任务
      • 如果添加的任务是头元素,唤醒Condition中等待的所有线程
    • 释放Lock

FutureTask详解

Future接口和实现Future接口的FutureTask类,代表异步计算的结果

简介

  • FutureTask除了实现Future接口外,还实现了Runnable接口。
  • FutureTask可以交给Executor执行,也可以由调用线程直接执行
  • FutureTask可以处于3种状态
    • 未启动:run方法还没有被执行前
      • 执行FutureTask.get将导致调用线程阻塞
      • 执行FutureTask.cancel将导致此任务永远不会被执行
    • 已启动:run方法被执行过程中
      • 执行FutureTask.get将导致调用线程阻塞
      • 执行FutureTask.cancel(true)将以中断执行此任务线程的方式来试图停止任务
      • 执行FutureTask.cancel(false)将不会对正在执行此任务的线程产生影响
    • 已完成:run方法执行完后正常结束,或被取消,或执行run方法时抛出异常而异常结束
      • 执行FutureTask.get将导致调用线程立即返回结果或抛出异常
      • 执行FutureTask.cancel()返回false

使用

  • 可以把FutureTask交给Executor执行
  • 可以通过ExecutorService.submit返回一个FutureTask,然后执行FutureTask.get或cancel方法
  • 也可以单独使用FutureTask

当一个线程需要等待另一个线程把某个任务执行完后才能执行,此时可以使用FutureTask

实现

  • 基于AQS实现,包含两种类型操作

    • 至少一个acquire操作,阻塞调用线程,除非直到AQS状态允许这线程继续执行,FutureTask的acquire操作为get方法调用
    • 至少一个release操作,这个操作改变AQS的状态,改变后的状态可以允许一个或多个阻塞线程被解除阻塞,FutureTask的release操作包括run和cancel
  • Sync是FutureTask的内部私有类,继承自AQS,FutureTask的所有公有方法都直接委托给了内部私有Sync

  • FutureTask.get方法会用AQS的acquireSharedInterruptibly方法,执行过程

    • 调用AQS的acquireSharedInterryptibly方法,
      • 回调在子类Sync中实现的tryAcquireShared()方法来判断acquire操作是否可以成功
        • 成功条件:state为执行完成状态RAN或已取消状态CANCELLED,且runner不为null
    • 如果成功则get方法立即返回,如果失败则到线程等待队列中去等待其他线程执行release操作
    • 当其他线程执行release操作唤醒当前线程后,当前线程再次执行tryAcquireShared()将返回正值1,当前线程将离开线程等待队列并唤醒它的后继线程
    • 最后返回计算的结果或抛出异常

    FutureTask.run方法

    • 执行在构造函数中指定的任务(Callable.call)
    • 以原子方式来更新同步,如果这个原则操作成功,就设置代表计算结果的变量result的值为callable.call的返回值,然后调用AQS.releaseShared
    • AQS.releaseShared首先会回调在子类Sync中实现的tryReleaseShared来执行release操作,AQS.releaseShared,然后唤醒线程等待队列中的第一个线程
    • 调用FutureTask.done1

相关文章:

并发-Executor框架笔记

Executor框架 jdk5开始&#xff0c;把工作单元与执行机制分离开来&#xff0c;工作单元包括Runable和Callable&#xff0c;执行机制由Executor框架来提供。 Executor框架简介 Executor框架的两级调度模型 Java线程被一对一映射为本地操作系统线程 java线程启动会创建一个本…...

【C进阶】分析 C/C++程序的内存开辟与柔性数组(内有干货)

前言&#xff1a; 本文是对于动态内存管理知识后续的补充&#xff0c;以及加深对其的理解。对于动态内存管理涉及的大部分知识在这篇文章中 ---- 【C进阶】 动态内存管理_Dream_Chaser&#xff5e;的博客-CSDN博客 本文涉及的知识内容主要在两方面&#xff1a; 简单解析C/C程序…...

深入理解 JVM 之——字节码指令与执行引擎

更好的阅读体验 \huge{\color{red}{更好的阅读体验}} 更好的阅读体验 类文件结构 Write Once&#xff0c;Run Anywhere 对于 C 语言从程序到运行需要经过编译的过程&#xff0c;只有经历了编译后&#xff0c;我们所编写的代码才能够翻译为机器可以直接运行的二进制代码&#x…...

C++:vector

目录 一、关于vector 二、vector的相关函数 三、相关函数的使用 ①构造函数 ②size ③[] ​编辑 ④push_back ⑤迭代器iterator ⑥reserve ⑦resize ⑧find ⑨insert ⑩erase ⑪sort 一、关于vector vector比较像数组 观察可知&#xff0c;vector有两个模板参数…...

Android Automotive编译

系统准备 安装系统 准备一台安装Ubuntu系统的机器&#xff08;windows系统的机器可以通过WSL安装ubuntu系统&#xff09; 安装docker 本文使用docker进行编译&#xff0c;因此提前安装docker。参考网络链接安装docker并设置为不使用sudo进行docker操作。 参考链接&#xff…...

什么是50ETF期权开户条件,怎么开期权交易权限?

50ETF期权是指上证50ETF期权&#xff0c;标的物是上证50ETF&#xff0c;代码是&#xff08;510500&#xff09;&#xff0c;期权是一种在上证50ETF基础上进行衍生品交易的金融工具&#xff0c;下文科普什么是50ETF期权开户条件&#xff0c;怎么开期权交易权限&#xff1f;本文来…...

React 从入门到精通——本文来自AI创作助手

React是一个流行的JavaScript库&#xff0c;用于构建用户界面。以下是React入门到精通的步骤&#xff1a; 入门 安装React 你可以在npm上下载React包&#xff0c;也可以使用其他包管理器。首先需要安装node.js&#xff0c;然后使用以下命令安装React&#xff1a; npm insta…...

【51单片机实验笔记】前篇(三) 模块功能封装汇总(持续更新)

文章目录 通用函数public.hpublic.c 延时函数delay.hdelay.c LED模块数码管模块smg.hsmg.c LED点阵模块独立按键模块矩阵按键模块外部中断模块定时器模块串口通讯模块ADC模块PWM模块 通用函数 包含常用头文件&#xff0c;宏定义&#xff0c;自定义类型&#xff0c;函数工具等。…...

Excel VSTO开发4 -其他事件

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 4 其他事件 针对插件的事件主要有Startup、Shutdown这两个事件&#xff0c;在第2节中已经讲解。在开发窗口中&#xff0c;选择对象…...

语音识别数据的采集方法:基本流程数据类型

“人工智能是一种模仿人类功能的产品。数据采集的方法需要针对特定的场景需求。”—–Mark Brayan (澳鹏CEO) 我们一直说&#xff0c;对于一个高质量的人工智能产品离不开高质量的训练数据。对于不同的人工智能我们需要不同的数据对其训练。要采集正确的数据去训练特定的模型才…...

oracle数据库给用户授权DBA权限Oracle查看哪些用户具有DBA权限

oracle数据库给用户授权DBA权限 步骤一&#xff1a;以sysdba身份登录到Oracle数据库 在授予DBA权限之前&#xff0c;我们首先要以sysdba身份登录到Oracle数据库。使用以下命令登录&#xff1a; sqlplus / as sysdba步骤二&#xff1a;创建用户&#xff08;如有用户跳过&#…...

024-从零搭建微服务-系统服务(六)

写在最前 如果这个项目让你有所收获&#xff0c;记得 Star 关注哦&#xff0c;这对我是非常不错的鼓励与支持。 源码地址&#xff08;后端&#xff09;&#xff1a;https://gitee.com/csps/mingyue 源码地址&#xff08;前端&#xff09;&#xff1a;https://gitee.com/csps…...

Arduino驱动TCS3200传感器(颜色传感器篇)

目录 1、传感器特性 2、硬件原理图 3、控制器和传感器连线图 4、驱动程序 TCS3200颜色传感器是一款全彩的颜色检测器,包括了一块TAOS TCS3200RGB感应芯片和4个白色LED灯,TCS3200能在一定的范围内检测和测量几乎所有的可见光。TCS3200有大量的光检测器,每个都有红绿蓝和清…...

基于Matlab实现多个数字水印案例(附上源码+数据集)

数字水印是一种在数字图像或视频中嵌入特定信息的技术&#xff0c;以保护知识产权和防止盗版。在本文中&#xff0c;我们将介绍如何使用Matlab实现数字水印。 文章目录 实现步骤源码数据集下载 实现步骤 首先&#xff0c;我们需要选择一个用于嵌入水印的图像。这可以是原始图像…...

C语言之指针进阶篇(2)

目录 函数指针 函数名和&函数名 函数指针的定义 函数指针的使用 函数指针陷阱 代码1 代码2 注意 函数指针数组定义 函数指针数组的使用 指向函数指针数组的指针 书写 终于军训圆满结束了&#xff0c;首先回顾一下指针进阶篇&#xff08;1&#xff09;主要是…...

C++ 进制转化入门知识(1)

一、什么是进制 进制是一种用来表示数值的系统或方法&#xff0c;它是基于一个特定的基数来工作的。在我们常见的几种进制中&#xff0c;有&#xff1a; 1. **二进制&#xff08;基数 2&#xff09;**&#xff1a; 二进制只用两个数字&#xff1a;0和1。这是计算机内部使用…...

【React】React学习:从初级到高级(四)

React学习[四] 4 应急方案4.1 使用ref引用值4.1.1 给组件添加ref4.1.2 ref和state的不同之处4.1.3 何时使用ref 4.2 使用ref操作DOM4.2.1 获取指向节点的ref4.2.3 使用 ref 回调管理 ref 列表4.2.4 访问另一个组件的DOM节点4.2.5 用 flushSync 同步更新 state 4.3 使用Effect同…...

微信小程序登录问题(思路简略笔记)

配置问题 这是小程序登录问题&#xff0c;必要的两个配置。 流程思路 1. 微信小程序端&#xff0c;会返回一个code。 2. 查看需要返回给微信小程序端的数据。 3. 既然需要返回三个数据&#xff0c;先看openid如何拿到 WX-Login https://api.weixin.qq.com/sns/jscode2ses…...

Go 锁扩展

文章目录 TryLock统计 goroutine数量读写锁读锁写锁常见死锁情况写锁重入写锁中调用读锁循环依赖 TryLock 源码中自带的(我的go是 1.20版本)TryLock 会尝试获取锁&#xff0c;如果获取不到返回false&#xff0c;并不会进行休眠阻塞(和 Lock的主要区别) func (m *Mutex) TryLo…...

Docker的简介及安装

[shouce]http://shouce.jb51.net/docker_practice/栾一峰菜鸟教程参考文献 1 环境配置的难题 软件开发最大的麻烦事之一&#xff0c;就是环境配置。用户计算机的环境都不相同&#xff0c;你怎么知道自家的软件&#xff0c;能在那些机器跑起来&#xff1f; 用户必须保证两件事…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用

1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

基于TurtleBot3在Gazebo地图实现机器人远程控制

1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG

TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码&#xff1a;HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…...

【Linux】Linux安装并配置RabbitMQ

目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的&#xff0c;需要先安…...

JavaScript 标签加载

目录 JavaScript 标签加载script 标签的 async 和 defer 属性&#xff0c;分别代表什么&#xff0c;有什么区别1. 普通 script 标签2. async 属性3. defer 属性4. type"module"5. 各种加载方式的对比6. 使用建议 JavaScript 标签加载 script 标签的 async 和 defer …...