CC00082.spark——|Hadoop&Spark.V08|——|Spark.v08|Spark 原理 源码|Spark Context|

Unity中URP下的菲涅尔效果实现(个性化修改) 在上篇文章中,我们实现了 URP 下的菲涅尔基础效果,我们在这篇文章中,对其进行自定义化修改。 阅读详情
一、SparkContext启动流程
### --- sparkContext启动流程

~~~     SparkContext 涉及到的组件多,源码比较庞大。
~~~     有些边缘性的模块主要起到辅助的功能,暂时省略。
~~~     本文主要关心 SparkContext整体启动流程、三大组件的启动。
~~~     初始化部分的代码主要集中在 363 - 592 行(Spark版本2.4.5)
### --- 初始化步骤:

~~~     1. 初始设置
~~~     2. 创建 SparkEnv
~~~     3. 创建 SparkUI
~~~     4. Hadoop 相关配置
~~~     5. Executor 环境变量
~~~     6. 注册 HeartbeatReceiver 心跳接收器
~~~     7. 创建 TaskScheduler、SchedulerBackend
~~~     8. 创建和启动 DAGScheduler
~~~     9. 启动TaskScheduler、SchedulerBackend
~~~     10. 启动测量系统 MetricsSystem
~~~     11. 创建事件日志监听器
~~~     12. 创建和启动 ExecutorAllocationManager
~~~     13. ContextCleaner 的创建与启动
~~~     14. 自定义 SparkListener 与启动事件
~~~     15. Spark 环境更新
~~~     16. 投递应用程序启动事件
~~~     17. 测量系统添加Source
~~~     18. 将 SparkContext 标记为激活
二、SparkContext启动流程
### --- 初始设置

~~~     SparkContext默认只有一个实例。要在 SparkConf 中设置 allowMultipleContexts 为 true;
~~~     当存在多个active级别的SparkContext实例时Spark会发生警告,而不是抛出异常,要特别注意。
~~~     # 源码提取说明:SparkContext.scala
~~~     # 82行~85行

  // In order to prevent multiple SparkContexts from being active at the same time, mark this
  // context as having started construction.
  // NOTE: this must be placed at the beginning of the SparkContext constructor.
  SparkContext.markPartiallyConstructed(this, allowMultipleContexts)
~~~     对SparkConf进行复制,然后对各种配置信息进行校验,
~~~     最主要的就是SparkConf必须指定 spark.master(用于设置部署模式)
~~~     和 spark.app.name(应用程序名称)属性,否则会抛出异常。
~~~     # 源码提取说明:SparkContext.scala
~~~     # 363行~372行

  try {
    _conf = config.clone()
    _conf.validateSettings()

    if (!_conf.contains("spark.master")) {
      throw new SparkException("A master URL must be set in your configuration")
    }
    if (!_conf.contains("spark.app.name")) {
      throw new SparkException("An application name must be set in your configuration")
    }
### --- 创建 SparkEnv

~~~     SparkEnv是Spark的执行环境对象,
~~~     SparkEnv存在于Driver或者CoarseGrainedExecutorBackend进程中。
~~~     # 源码提取说明:SparkContext.scala
~~~     # 423行~425行

    // Create the Spark execution environment (cache, map output tracker, etc)
    _env = createSparkEnv(_conf, isLocal, listenerBus)
    SparkEnv.set(_env)
### --- 创建 SparkUI

~~~     SparkUI 提供了用浏览器访问具有样式及布局并且提供丰富监控数据的页面。
~~~     其采用的是时间监听机制。发送的事件会存入缓存,
~~~     由定时调度器取出后分配给监听此事件的监听器对监控数据进行更新。
~~~     如果不需要SparkUI,则可以将spark.ui.enabled置为false。
~~~     # 源码提取说明:SparkContext.scala
~~~     # 442行~452行

    _ui =
      if (conf.getBoolean("spark.ui.enabled", true)) {
        Some(SparkUI.create(Some(this), _statusStore, _conf, _env.securityManager, appName, "",
          startTime))
      } else {
        // For tests, do not enable the UI
        None
      }
    // Bind the UI before starting the task scheduler to communicate
    // the bound port to the cluster manager properly
    _ui.foreach(_.bind())
### --- Hadoop相关配置

~~~     获取的配置信息包括:
~~~     将Amazon S3文件系统的AWS_ACCESS_KEY_ID和 AWS_SECRET_ACCESS_KEY
~~~     加载到Hadoop的Configuration;
~~~     将SparkConf中所有的以 spark.hadoop 开头的属性都赋值到Hadoop的Configuration;
~~~     将SparkConf的属性 spark.buffer.size 复制到Hadoop的Configuration的配置io.file.buffer.size;
~~~     # 源码提取说明:SparkContext.scala
~~~     # 454行

    _hadoopConfiguration = SparkHadoopUtil.get.newConfiguration(_conf)
### --- Executor 环境变量

~~~     ExecutorEnvs包含的环境变量将会注册应用程序的过程中发送给Master,
~~~     Master给Worker发送调度后,Worker最终使用ExecutorEnvs提供的信息启动Executor。 
~~~     通过配置 spark.executor.memory 指定 Executor 占用的内存的大小,
~~~     也可以配置系统变量SPARK_EXECUTOR_MEMORY或者SPARK_MEM设置其大小。
~~~     # 源码提取说明:SparkContext.scala
~~~     # 465行~485行

    _executorMemory = _conf.getOption("spark.executor.memory")
      .orElse(Option(System.getenv("SPARK_EXECUTOR_MEMORY")))
      .orElse(Option(System.getenv("SPARK_MEM"))
      .map(warnSparkMem))
      .map(Utils.memoryStringToMb)
      .getOrElse(1024)

    // Convert java options to env vars as a work around
    // since we can't set env vars directly in sbt.
    for { (envKey, propKey) <- Seq(("SPARK_TESTING", "spark.testing"))
      value <- Option(System.getenv(envKey)).orElse(Option(System.getProperty(propKey)))} {
      executorEnvs(envKey) = value
    }
    Option(System.getenv("SPARK_PREPEND_CLASSES")).foreach { v =>
      executorEnvs("SPARK_PREPEND_CLASSES") = v
    }
    // The Mesos scheduler backend relies on this environment variable to set executor memory.
    // TODO: Set this only in the Mesos scheduler.
    executorEnvs("SPARK_EXECUTOR_MEMORY") = executorMemory + "m"
    executorEnvs ++= _conf.getExecutorEnv
    executorEnvs("SPARK_USER") = sparkUser
### --- 注册 HeartbeatReceiver 心跳接收器

~~~     在 Spark 的实际生产环境中,Executor 是运行在不同的节点上的。
~~~     在 Local 模式 Driver 与 Executor 属于同一个进程,
~~~     所以 Dirver 与 Executor 可以直接使用本地调用交互,
~~~     当Executor 运行出现问题时,Driver 可以很方便地知道。
~~~     在生产环境中,Driver 与 Executor 通常不在同一个进程内,运行在不同的节点上,
~~~     甚至不同的机房里,为了能够掌控 Executor,在 Driver 中创建了这个心跳接收器。
~~~     # 源码提取说明:SparkContext.scala
~~~     # 487行~490行

    // We need to register "HeartbeatReceiver" before "createTaskScheduler" because Executor will
    // retrieve "HeartbeatReceiver" in the constructor. (SPARK-6640)
    _heartbeatReceiver = env.rpcEnv.setupEndpoint(
      HeartbeatReceiver.ENDPOINT_NAME, new HeartbeatReceiver(this))
### --- 创建和启动TaskScheduler、SchedulerBackend

~~~     TaskScheduler,负责任务的提交,并且负责发送任务到集群并运行它们,
~~~     任务失败的重试,以及慢任务的在其他节点上重试。 
~~~     其中给应用程序分配并运行 Executor为一级调度,而给任务分配 Executor 并运行任务则为二级调度。
~~~     另外 TaskScheduler 也可以看做任务调度的客户端。
~~~     为 TaskSet创建和维护一个TaskSetManager并追踪任务的本地性以及错误信息;
~~~     遇到Straggle 任务会方到其他的节点进行重试;
~~~     向DAGScheduler汇报执行情况, 包括在Shuffle输出lost的时候报告fetch failed 错误等信息;
~~~     SchedulerBackend负责与Master、Worker通信收集Worker上分配给该应用使用的资源情况。
~~~     # 源码提取说明:SparkContext.scala
~~~     # 492行~501行

    // Create and start the scheduler
    val (sched, ts) = SparkContext.createTaskScheduler(this, master, deployMode)
    _schedulerBackend = sched
    _taskScheduler = ts
    _dagScheduler = new DAGScheduler(this)
    _heartbeatReceiver.ask[Boolean](TaskSchedulerIsSet)

    // start TaskScheduler after taskScheduler sets DAGScheduler reference in DAGScheduler's
    // constructor
    _taskScheduler.start()
### --- 创建和启动 DAGScheduler

~~~     DAGScheduler主要用于在任务正式交给TaskScheduler提交之前做一些准备工作,
~~~     包括:创建Job,将DAG中的RDD划分到不同的Stage,提交Stage等。
~~~     DAGScheduler的数据结构主要维护 jobId 和 stageId 的关系、Stage、ActiveJob,
~~~     以及缓存的RDD的Partition的位置信息。
### --- 启动TaskScheduler、SchedulerBackend

~~~     # 源码提取说明:TaskSchedulerImpl.scala
~~~     # 180行~193行
  def newTaskId(): Long = nextTaskId.getAndIncrement()

  override def start() {
    backend.start()

    if (!isLocal && conf.getBoolean("spark.speculation", false)) {
      logInfo("Starting speculative execution thread")
      speculationScheduler.scheduleWithFixedDelay(new Runnable {
        override def run(): Unit = Utils.tryOrStopSparkContext(sc) {
          checkSpeculatableTasks()
        }
      }, SPECULATION_INTERVAL_MS, SPECULATION_INTERVAL_MS, TimeUnit.MILLISECONDS)
    }
  }
### --- 启动测量系统 MetricsSystem

~~~     # MetricsSystem中三个概念:
~~~     Instance: 指定了谁在使用测量系统;
~~~     # Spark按照Instance的不同,分为Master、Worker、Application、Driver和Executor
~~~     Source: 指定了从哪里收集测量数据;
~~~     # Source的有两种来源:Spark internal source: MasterSource / Worker Source等; 
~~~     # Common source:JvmSource

~~~     Sink:指定了往哪里输出测量数据; 
~~~     Spark目前提供的Sink有ConsoleSink、CsvSink、JmxSink、MetricsServlet、GraphiteSink等;
~~~     Spark使用MetricsServlet作为默认的Sink
~~~     # MetricsSystem的启动过程包括:

~~~     注册Sources
~~~     注册Sinks
~~~     将Sinks增加 Jetty 的ServletContextHandler
~~~     MetricsSystem启动完毕后,会遍历与Sinks有关的 ServletContextHandler,
~~~     并调用 attachHandler将它们绑定到Spark UI上
### --- 创建事件日志监听器

~~~     EventLoggingListener 是将事件持久化到存储的监听器,是 SparkContext 中可选组件。
~~~     当spark.eventLog.enabled属性为 true 时启动,默认为 false。
~~~     # 源码提取说明:sparkcontext.scala
~~~     # 518行~528行

    _eventLogger =
      if (isEventLogEnabled) {
        val logger =
          new EventLoggingListener(_applicationId, _applicationAttemptId, _eventLogDir.get,
            _conf, _hadoopConfiguration)
        logger.start()
        listenerBus.addToEventLogQueue(logger)
        Some(logger)
      } else {
        None
      }
### --- 创建和启动 ExecutorAllocationManager

~~~     可选的组件,用于对以分配的Executor进行管理。
~~~     默认情况下不会创建ExecutorAllocationManager,
~~~     可以修改属性spark.dynamicAllocation.enabled为true来创建。
~~~     ExecutorAllocationManager可以动态的分配最小Executor的数量、
~~~     动态分配最大Executor的数量、每个Executor可以运行的Task数量等配置信息,
~~~     并对配置信息进行校验。
~~~     start方法将ExecutorAllocationListener加入listenerBus中,
~~~     ExecutorAllocationListener通过监听listenerBus里的事件,动态的添加、删除Executor。
~~~     并且通过不断添加Executor,遍历Executor,将超时的Executor杀死并移除。
~~~     # 源码提取说明:sparkcontext.scala
~~~     # 530行~545行

    // Optionally scale number of executors dynamically based on workload. Exposed for testing.
    val dynamicAllocationEnabled = Utils.isDynamicAllocationEnabled(_conf)
    _executorAllocationManager =
      if (dynamicAllocationEnabled) {
        schedulerBackend match {
          case b: ExecutorAllocationClient =>
            Some(new ExecutorAllocationManager(
              schedulerBackend.asInstanceOf[ExecutorAllocationClient], listenerBus, _conf,
              _env.blockManager.master))
          case _ =>
            None
        }
      } else {
        None
      }
    _executorAllocationManager.foreach(_.start())
### --- ContextCleaner 的创建与启动

~~~     ContextCleaner用于清理超出应用范围的RDD、ShuffleDependency和Broadcast对象
~~~     referenceQueue: 缓存顶级的AnyRef引用
~~~     referenceBuff:缓存AnyRef的虚引用
~~~     listeners:缓存清理工作的监听器数组
~~~     cleaningThread:用于具体清理工作的线程
~~~     # 源码提取说明:sparkcontext.scala
~~~     # 547行~553行

    _cleaner =
      if (_conf.getBoolean("spark.cleaner.referenceTracking", true)) {
        Some(new ContextCleaner(this))
      } else {
        None
      }
    _cleaner.foreach(_.start())
### --- 自定义 SparkListener 与启动

~~~     添加用于自定义 SparkListener
~~~     # 注册config的spark.extraListeners属性中指定的监听器,并启动监听器总线
setupAndStartListenerBus()

~~~     # 环境更新
postEnvironmentUpdate()

~~~     # 投递应用程序启动事件
postApplicationStart()
~~~     # 源码提取说明:sparkcontext.scala
~~~     # 555行~557行

    setupAndStartListenerBus()
    postEnvironmentUpdate()
    postApplicationStart()
### --- Spark 环境更新

~~~     在SparkContext的初始化过程中,可能对其环境造成影响,处理步骤,所以需要更新环境。
~~~     通过调用 SparkEnv 的方法 environmentDetails,
~~~     将环境的 JVM 参数、Spark 属性、系统属性、classPath 等信息设置为环境明细信息
~~~     生成事件 SparkListenerEnvironmentUpdate(此事件携带环境明细信息),
~~~     并投递到事件总线 listenerBus,此事件最终被 EnvironmentListener 监听,
~~~     并影响 EnvironmentPage 页面中的输出内容。
### --- 投递应用程序启动事件

~~~     向listenerBus发送了SparkListenerApplicationStart事件
### --- 测量系统添加Source

~~~     先调用 taskScheduler.postStartHook 方法,等待backend就绪;
~~~     创建 DAGSchedulerSource、BlockManagerSource和 ExecutorAllocationManagerSource;
~~~     # 源码提取说明:sparkcontext.scala
~~~     # 559行~565行

    // Post init
    _taskScheduler.postStartHook()
    _env.metricsSystem.registerSource(_dagScheduler.metricsSource)
    _env.metricsSystem.registerSource(new BlockManagerSource(_env.blockManager))
    _executorAllocationManager.foreach { e =>
      _env.metricsSystem.registerSource(e.executorAllocationManagerSource)
    }
### --- 将 SparkContext 标记为激活

~~~     SparkContext初始化的最后将当前SparkContext的状态从contextBeingConstructed(正在构建中)
~~~     改为activeContext(已激活)。
~~~     # 源码提取说明:sparkcontext.scala
~~~     # 559行~565行

  // In order to prevent multiple SparkContexts from being active at the same time, mark this
  // context as having finished construction.
  // NOTE: this must be placed at the end of the SparkContext constructor.
  SparkContext.setActiveContext(this, allowMultipleContexts)
OCC WebGL案例编译实战:从FreeType配置到静态库生成 本文详细记录了将OCC(Open CASCADE Technology)3D图形库编译为WebAssembly(Wasm)并在浏览器中通过WebGL渲染的实战过程。重点解决了FreeType库的交叉编译配置、OCC核心库的裁剪与静态库生成,以及WebGL样例项目的CMake改造等关键步骤,为开发者提供了从环境搭建到最终集成的完整指南。 阅读详情

相关推荐

Java全栈面试宝典:从P6到P8-10

答案: CAP定理说一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)、分区容错性(Partition Tolerance)中的两个。C:所有节点在同一时刻看到的数据一样。你写了一个值,立刻读,不管从哪个节点读,都能读到最新值。A:每个请求都能得到非错误的响应,即使某些节点挂了。系统一直能对外服务,不会返回超时或拒绝。P:网络分区发生时,系统仍能继续工作。网络分区就是节点之间网络不通了,但节点本身还活着。CAP不是"三选二",而是当网络分区发生时,你必须在C和

_abab的专栏 81

Spring 源码系列(23): SpringApplication.run() 启动全流程

本文深入解析了SpringApplication.run()的核心流程,通过源码拆解揭示了从启动到容器就绪的完整生命周期。文章重点分析了三个关键阶段:prepareEnvironment的配置加载逻辑(系统属性>环境变量>配置文件)、createApplicationContext的容器类型推断机制(基于classpath判断Web/Reactive/普通应用),以及callRunners的启动后回调特性(按@Order执行初始化任务)。同时澄清了常见误区,如内嵌Tomcat实际在refresh阶段的onR

不才不才不不才的博客 345

华为OD机试真题精讲:求幸存数之和(Python/Java/C++多语言实现)

华为OD机试真题:求幸存数之和 问题概述 给定一个整数序列和淘汰步长k,按照约瑟夫环规则淘汰数字,直到剩余m个元素(m为原序列长度的一半,向下取整),计算剩余元素的和。 核心解法 约瑟夫环变种:循环计数并淘汰第k个元素,直到剩余元素数量达标 关键公式:(current_idx + k - 1) % len(arr)计算待淘汰元素索引 复杂度:O(n^2),符合题目要求 实现要点 Python:利用列表和取模运算简洁实现 Java:使用ArrayList处理元素删除 C++:通过vector高效操作序列 示例

bkspiderx的博客 33

简单讲解Java--queue--三组成对出现的方法的区别

操作类型异常派(失败抛异常)特殊值派(失败返null/false)核心选型原则插入add(e)offer(e)生产者:优先用offer做流控;初始化填充用add做断言取出remove()poll()消费者:永远用pollnull判断;原子操作且确定非空时才用remove查看element()peek()只读场景:99%情况用peek;需要强制非空前置条件时用element终极避坑指南不要用remove()element()做轮询——异常栈生成代价极高(填充StackTrace),比if。

HDZW_ZQBX___的博客 385

Java大厂面试实录:Spring Boot与微服务、Redis缓存、JWT安全、Prometheus监控全解析——记谢飞机的一次硬核面试

周六下午,互联网大厂“星河科技”的会议室里,阳光透过落地窗洒在长桌上。面试官李总眉头微蹙,翻看着眼前这位候选人的简历——谢飞机,三年Java开发经验,自我评价“精通全家桶”。对面,谢飞机正襟危坐,嘴角带着一丝自信到发光的微笑。李总推了推眼镜,语气平淡:“谢飞机先生,我们开始吧。今天聊电商后端场景,你平时写代码用什么Java版本?

2602_95996092的博客 270

Micrometer 系列【66】上下文传播工具库 | 案例演示

context-propagation 是 Micrometer 生态的跨线程上下文搬运协议层,本身零运行时依赖、不依赖 Spring、Micrometer 其他组件。

记录知识、锤炼自我 455

Java 并发灵魂拷问:notify/signal 唤醒顺序是规范还是实现?

本文探讨了Java中Object.notify()和Condition.signal()唤醒线程的顺序问题。关键结论如下: Object.notify(): JVM规范未规定唤醒顺序,HotSpot实现虽采用FIFO(从WaitSet头部取线程),但这属于实现细节而非规范要求 由于synchronized是非公平锁,被唤醒线程需重新竞争锁,最终执行顺序无法保证 严禁业务代码依赖该顺序 Condition.signal(): 严格按FIFO顺序唤醒(AQS等待队列头部线程) 是设计约定,业务可合理依赖该特性

weixin_68315058的博客 341

【Spring Cloud Alibaba】Sentinel(三)

这里有个关键点:不是 “前 10 秒”,是。

Blue_Pepsi_Cola的博客 266

[Java]-微服务面试题

服务降级是服务自我保护的一种方式,或者保护下游服务的一种方式,用于确保服务不会受请求突增影响变得不可用,确保服务不会崩溃。微服务的负载均衡主要使用了一个组件Ribbon,比如,我们在使用feign远程调用的过程中,底层的负载均衡就是。2,我们还在skywalking设置了告警规则,特别是在项目上线以后,如果报错,我们分别设置了可以给相关负责人。简历上写的微服务,只要是发生了多个服务之间的写操作,都需要进行分布式事务控制。2,在客户端的配置文件中,可以配置某一个服务调用的负载均衡策略(局部)

. 597

49.Java】JDK 21的虚拟线程(上):革命性的并发模型

本文深入解析JDK 21引入的虚拟线程(Virtual Threads)技术,从传统平台线程的资源瓶颈出发,阐述虚拟线程的轻量级特性、M:N调度模型及其工作原理。详细介绍了两种创建虚拟线程的方法,并通过性能对比实验展示其在I/O密集型场景下的显著优势。总结了虚拟线程的适用场景、使用注意事项以及与平台线程的核心差异,帮助开发者掌握这一革命性的并发编程工具。

gugucoding的博客 504

Java Spring 批量修改,实体、接口、方法的定义

本文描述了一个批量更新车辆类型的接口实现。该功能通过Controller层接收包含出库单ID列表和车辆类型的请求参数,调用Service层进行处理。实现层采用事务管理,首先验证参数有效性,然后查询对应出库单数据并批量更新车辆类型字段,最后返回操作结果(成功更新记录数或错误信息)。该接口主要用于快递业务中其他出库单的车辆类型批量修改操作,包含完整的参数校验、异常处理和事务管理机制。

LYBWWP 36

并发 13 · 异步编排

摘要:本文探讨了异步编排在秒杀下单场景中的应用,分析了传统Future的局限性,并介绍了CompletableFuture如何通过链式调用解决任务依赖与并行问题。文章详细讲解了创建异步任务、串联任务(thenApply/thenCompose)、合并任务(thenCombine/allOf)以及异常处理等核心方法,强调使用独立线程池避免阻塞公共资源。最后结合秒杀案例,展示了如何构建高效、清晰的异步流水线,优化响应时间。全文提供代码示例和选型建议,帮助开发者实现高性能异步流程编排。

记录后端技术的深水区:MySQL、并发、JVM、分布式。原理为主,实战为辅,能少踩一个坑是一个。 379

家政派单系统开发实战:架构设计与派单算法指南

家政派单系统是连接用户需求与上门服务人员的核心调度平台,其开发难点并不在于简单的CRUD,而是在于如何设计一套能支撑“多角色、多任务类型、高并发抢单”的架构,以及一套能让订单和师傅效率化的派单算法。一旦师傅手动拒绝系统派单,近1小时的接单权重下降50%,防止师傅只接高价单而忽略普通单,导致用户体验受损。建议优先搭建一个可配置化的规则引擎,将派单距离、服务类目、师傅等级做成后台可调整的配置项,这样后期运营调整策略时,无需修改代码。师傅接单后的轨迹追踪,是提升用户体验的关键,也是开发的难点。

zww8949111的博客 311

零信任架构实战:基于天远企业年报信息核验构建自动化供应商准入网关

破解供应商准入核查痛点:从传统人工资质初筛到自动化数据穿透 在大型 B2B 供应链采购平台的微服务架构中,供应商准入尽职调查(KYC)是保障平台交易生态健康的核心防线。传统的准入流程往往依赖业务人员手工收取企业营业执照、年度审计报告等纸质或电子扫描件,并登录多平台逐一核对。这种模式不仅流程繁琐、效率极低,而且难以实时防范非存续异常主体或信息不匹配资质的问题,

2501_94042197的博客 201

Helm Chart依赖管理实战

在kind: Podmetadata:spec:关键注解说明:标记为测试 Hook:测试成功后自动删除 Pod。

m0_52572472的博客 222

全国计算机二级Java选择题高频真题20道精选与试题解析

全国计算机等级考试二级Java语言程序设计选择题20道高频真题与标准试题解析,深度剖析二叉树度数计算、异常捕获匹配、多态向上转型、位运算、集合框架与多线程接口。

qq_39121450的博客 191

@Value与@ConfigurationProperties注解使用记录

本文探讨了从YAML配置文件中获取Map类型数据的两种方案:使用@Value注解和@ConfigurationProperties注解。作者首先尝试@Value方案,发现其无法直接注入Map且扩展性差,只能获取单个键值。随后转向@ConfigurationProperties方案,但遇到Map键中的冒号被自动过滤的问题。最终解决方案是调整YAML结构为列表形式,并创建包含key-value对的内部类Item,通过转换方法toMap()获取所需Map结构。文章强调了YAML配置项需采用kebab-case(短

AlickLbc的博客 138

Semaphore 源码解析

摘要: Semaphore是Java并发编程中的计数信号量工具,基于AQS(AbstractQueuedSynchronizer)实现,提供共享模式下的线程同步功能。其核心特性包括: 通过acquire/release方法获取/释放许可,许可数量可动态调整; 支持公平/非公平两种模式(FairSync/NonfairSync),公平模式保证先到先得; 内部使用CAS操作和自旋机制保证线程安全; 提供tryAcquire、drainPermits等扩展方法; 任何线程均可释放许可,不要求先获取许可。

赵丙双的博客 196

华为OD机试新系统真题【信道资源分配与掩码运算】

华为OD机试 新系统真题【信道资源分配与掩码运算】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试真题【信道资源分配与掩码运算】多语言题解。

qq_45776114的博客 286

Java微服务接大模型:3层架构、5个生产问题怎么答

脉脉上有一则Java后端面试复盘:问题从“微服务怎么接大模型”一路追到Agent分层、会话状态、流式响应、工具失败、可观测性和安全。真正的考点不是会不会调用Spring AI,而是能否把不稳定、昂贵且慢的模型调用纳入工程治理。

HanaYao的博客 173

MODBUS-RTU协议多机通信51单片机实现主机从机

MODBUS-RTU协议多机通信史上最容易看懂的代码!程序代码包含4个独立程序1台主机:读取从机湿度温度控制LED和继电器3台从机:从机1采集温度,从机2采集湿度,从机3控制继电器和LED流水花样主控89C52,显示液晶1602(另有STM32主从代码卖)主机发MODBUS-RTU协议指令去获取从机数据和控制LED和继电器主机对返回数据进行处理并显示在1602液晶上主机2个按键按下对应按键触发主机发送对应指令去控制LED和继电器程序易懂,宏定义和结构体很少用虽然多用宏定义和结构体显得程序高级但对新手理解不友好,提供解答另出售 型号stm32f103VET6单片机主站从站代码5元支持32个节点数的芯片:SN75176,SN75276,SN75179,SN75180,MAX485,MAX488,MAX490支持64个节点数的芯片:SN75LBC184支持128个节点数的芯片:MAX487,MAX1487支持256个节点数的芯片:MAX1482,MAX1483,MAX3080,MAX3089

上一篇: CC00079.spark——|Hadoop&Spark.V05|——|Spark.v05|Spark 原理 源码|Master Worker解析&模拟程序|
下一篇: CC00081.spark——|Hadoop&Spark.V07|——|Spark.v07|Spark 原理 源码|Spark Context|
yanqi_vip
博客等级 码龄7年 50粉丝 · 2636原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yanqi_vip

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值