<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>L1nker4&#39;s Blog | 格木观云</title>
    <link>http://localhost:1313/</link>
    <description>Recent content on L1nker4&#39;s Blog | 格木观云</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Sun, 01 Mar 2026 16:43:37 +0800</lastBuildDate>
    <atom:link href="http://localhost:1313/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>SIGMOD &#39;17 Amazon Aurora: Design Considerations for High Throughput Cloud-Native Relational Databases</title>
      <link>http://localhost:1313/posts/paper-reading/amazon-aurora/</link>
      <pubDate>Sun, 01 Mar 2026 16:43:37 +0800</pubDate>
      <guid>http://localhost:1313/posts/paper-reading/amazon-aurora/</guid>
      <description>&lt;h1 id=&#34;1-introduction&#34;&gt;1. Introduction&lt;/h1&gt;&#xA;&lt;p&gt;传统的关系数据库架构在云环境中遇到了根本性的性能瓶颈：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;网络I/O成为约束&lt;/strong&gt;：在云基础设施中，计算、内存、存储都已经可以弹性扩展，但数据库实例与存储之间的网络带宽成为了性能瓶颈&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;RDS MySQL镜像方案&lt;/strong&gt;：简单地将单机MySQL搬到云上，将本地磁盘替换为EBS，但写放大问题被直接映射到网络上，导致性能急剧下降&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;分布式复制协议&lt;/strong&gt;：如Raft、Paxos等通用协议，开销大，对数据库语义理解不足&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;写放大问题&lt;/strong&gt;：传统MySQL架构一次逻辑写操作涉及5次物理磁盘写：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Redo log写入&lt;/li&gt;&#xA;&lt;li&gt;Binlog写入&lt;/li&gt;&#xA;&lt;li&gt;数据Page写入（可能触发）&lt;/li&gt;&#xA;&lt;li&gt;Double-write buffer写入&lt;/li&gt;&#xA;&lt;li&gt;FRM文件写入&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;针对上述问题，Aurora论文中提出了一个架构理念：&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;&amp;ldquo;Log is the Database&amp;rdquo;&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;将数据库视为redo log流，存储层变成&amp;quot;日志处理服务&amp;quot;，网络上只传输redo log，其他所有工作（Page写入、检查点等）都下推到存储层异步完成。&lt;/p&gt;&#xA;&lt;h1 id=&#34;2-架构设计&#34;&gt;2. 架构设计&lt;/h1&gt;&#xA;&lt;h2 id=&#34;21-设计亮点the-log-is-the-database&#34;&gt;2.1. 设计亮点：The Log is the Database&lt;/h2&gt;&#xA;&lt;p&gt;传统MySQL镜像架构的存在五倍的写放大的情况，Aurora针对此情况做了如下改进：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;只通过网络传输redo log，其他所有写入都在存储层本地完成&lt;/li&gt;&#xA;&lt;li&gt;存储节点接收并持久化redo log，并异步将日志转换成数据Page，同时维护checkpoint和snapshot，并通过gossip协议检查并修复数据不一致的情况&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;strong&gt;数据流&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&#xA;DB Engine → Redo Log → Storage Service → Async Page Generation&#xA;&#xA;&#x9;&#x9;&#x9;(网络传输)    (分布式存储)         (后台异步)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;22-架构概览&#34;&gt;2.2. 架构概览&lt;/h2&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20260314171620592.png&#34; alt=&#34;arch.png&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;221-primary-node&#34;&gt;2.2.1. Primary Node&lt;/h3&gt;&#xA;&lt;p&gt;Primary写入节点核心职责：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;唯一写入节点：接受所有客户端的写请求（INSERT/UPDATE/DELETE）&lt;/li&gt;&#xA;&lt;li&gt;日志生成器：生成MySQL兼容的redo log，分配单调递增的LSN&lt;/li&gt;&#xA;&lt;li&gt;日志分发器：将redo log同时发送到两个目的地：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;存储层的6个Storage Node：用于持久化和Page生成&lt;/li&gt;&#xA;&lt;li&gt;所有Secondary Node：用于实时同步&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;事务协调器：管理事务提交，等待VDL推进后确认事务完成&lt;/li&gt;&#xA;&lt;li&gt;查询处理器：处理所有SQL查询（包括读和写）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;特点：&lt;/p&gt;</description>
    </item>
    <item>
      <title>OpenManus架构设计分析</title>
      <link>http://localhost:1313/posts/agents/openmanus/</link>
      <pubDate>Wed, 11 Feb 2026 18:31:56 +0800</pubDate>
      <guid>http://localhost:1313/posts/agents/openmanus/</guid>
      <description>&lt;h1 id=&#34;1-intro&#34;&gt;1. Intro&lt;/h1&gt;&#xA;&lt;p&gt;OpenManus 是一个基于大语言模型的 AI Agent Framework。它实现了一套完整的 Agent 系统，能够接收用户的自然语言指令，通过&amp;quot;思考-行动-观察&amp;quot;循环（ReAct 模式）自主调用各种工具来完成复杂任务。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;核心能力包括&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;通过 LLM 理解用户意图并规划执行步骤&lt;/li&gt;&#xA;&lt;li&gt;调用多种工具（Python 执行、Shell 命令、浏览器操作、网页搜索、文件编辑等）&lt;/li&gt;&#xA;&lt;li&gt;支持单 Agent 直接执行和多 Agent 协同的 Planning 流程&lt;/li&gt;&#xA;&lt;li&gt;支持 MCP（Model Context Protocol）协议，可动态连接外部工具服务&lt;/li&gt;&#xA;&lt;li&gt;支持 Docker 沙箱隔离执行&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h1 id=&#34;2-架构简述&#34;&gt;2. 架构简述&lt;/h1&gt;&#xA;&lt;p&gt;OpenManus 采用&lt;strong&gt;分层模块化架构&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;┌──────────────────────────────────────────────────────────┐&#xA;│                     入口层 (main.py 等)                   │&#xA;└──────────────────────────┬───────────────────────────────┘&#xA;                           │&#xA;         ┌─────────────────┼─────────────────┐&#xA;         ▼                 ▼                 ▼&#xA;   ┌───────────┐    ┌───────────┐    ┌───────────┐&#xA;   │   Agent   │    │   Flow    │    │  Config   │&#xA;   │  代理模块  │    │  流程编排  │    │  配置管理  │&#xA;   └─────┬─────┘    └─────┬─────┘    └───────────┘&#xA;         │                │&#xA;         ▼                ▼&#xA;   ┌───────────┐    ┌───────────┐&#xA;   │   Tool    │    │  Prompt   │&#xA;   │  工具模块  │    │  提示词    │&#xA;   └─────┬─────┘    └───────────┘&#xA;         │&#xA;   ┌─────┴─────┐&#xA;   │    LLM    │        ┌──────────┐&#xA;   │  模型封装  │        │  Schema  │&#xA;   └───────────┘        │  数据模型 │&#xA;                        └──────────┘&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;各个模块职责如下：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Semantic Caching（语意缓存）：AI应用降本增效利器</title>
      <link>http://localhost:1313/posts/agents/semantic-caching/</link>
      <pubDate>Sun, 01 Feb 2026 15:41:39 +0800</pubDate>
      <guid>http://localhost:1313/posts/agents/semantic-caching/</guid>
      <description>&lt;h1 id=&#34;1-intro&#34;&gt;1. Intro&lt;/h1&gt;&#xA;&lt;p&gt;传统缓存的核心逻辑是&lt;strong&gt;精确字符串匹配&lt;/strong&gt;：将查询作为 key完全一致时命中缓存。这种机制在静态内容分发、API 响应缓存等场景下运作良好，但在AI应用领域的表现较差，相似意图的Query无法精准命中。语义缓存（Semantic Caching）是一种利用Embedding向量化和向量相似度搜索来实现基于&lt;strong&gt;语义相似&lt;/strong&gt;进行缓存匹配的机制。&lt;/p&gt;&#xA;&lt;p&gt;语义缓存的工作流程可以概括为四个阶段：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&#xA;用户查询 → [1. Embedding 向量化] → [2. 向量相似度搜索] → Hit? → [3. 返回缓存结果]&#xA;&#xA;                                    ↓ Miss&#xA;&#xA;                                [4. 调用 LLM → 缓存结果]&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Embedding 向量化&lt;/strong&gt;：将用户的自然语言查询通过 Embedding 模型映射为高维向量。这一向量编码了查询的语义信息，使得含义相近的文本在向量空间中彼此接近。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;向量相似度搜索&lt;/strong&gt; ：将新查询的向量与向量数据库中已存储的缓存向量进行比较，使用余弦距离（Cosine Distance）等度量方式计算语义距离，找出最近邻。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;缓存命中判定&lt;/strong&gt; ：若最近邻的距离小于预设阈值（如 0.15），则判定为缓存命中，直接返回对应的 LLM 响应。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;缓存未命中处理&lt;/strong&gt; 若无满足阈值条件的缓存结果，则将查询发送至 LLM 获取响应，并将该查询的 Embedding 向量与 LLM 响应一起写入缓存，供后续请求复用。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;语义缓存在客服聊天机器人、企业内部知识库等场景中能够发挥显著价值，此类场景大量Query集中在少数高频问题中，使用语意缓存可以显著降低AI应用的token成本。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h1 id=&#34;2-基于redisvl实现语义缓存&#34;&gt;2. 基于RedisVL实现语义缓存&lt;/h1&gt;&#xA;&lt;h2 id=&#34;21-redisvl介绍&#34;&gt;2.1. RedisVL介绍&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;RedisVL（Redis Vector Library）&lt;/strong&gt; 是 Redis 官方提供的 Python 客户端库，专为 AI 应用场景设计。它在 Redis 核心的高性能数据存储能力之上，封装了向量索引管理、多种 Embedding 模型集成、向量相似度搜索等功能，使开发者无需直接操作底层的 RediSearch 命令即可构建向量检索应用。在语义缓存领域，RedisVL 提供了 &lt;code&gt;SemanticCache&lt;/code&gt; 类作为核心抽象，将索引创建、Embedding 向量化、KNN 搜索、阈值判定、TTL 管理等操作封装为简洁的 &lt;code&gt;check()&lt;/code&gt; / &lt;code&gt;store()&lt;/code&gt; API。同时，RedisVL 内置了对 OpenAI、HuggingFace、Cohere 等主流 Embedding Model的适配，并支持 Tag 和 Numeric 过滤实现多租户缓存隔离。&lt;/p&gt;</description>
    </item>
    <item>
      <title>EuroSys &#39;15 Large-scale cluster management at Google with Borg</title>
      <link>http://localhost:1313/posts/paper-reading/borg/</link>
      <pubDate>Wed, 22 Oct 2025 12:30:12 +0800</pubDate>
      <guid>http://localhost:1313/posts/paper-reading/borg/</guid>
      <description>&lt;h1 id=&#34;1-intro&#34;&gt;1. Intro&lt;/h1&gt;&#xA;&lt;p&gt;&lt;strong&gt;Borg&lt;/strong&gt; 是支持Google大规模数据中心计算的集群管理系统，其设计理念和工程实现对后来的 Kubernetes、Omega 等系统产生了深远影响。Borg 通过在共享集群上高效调度和管理成千上万的任务，实现了资源的高利用率、任务的高可靠性以及灵活的多租户隔离。论文介绍了 Borg 的整体架构、调度机制、容错设计和运维经验，揭示了支撑谷歌内部服务（如搜索、Gmail、YouTube）运行的关键技术。作为早期的超大规模集群管理系统，Brog提供了以下三个优势：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;隐藏底层资源管理和故障处理细节，使用户专注于应用开发。&lt;/li&gt;&#xA;&lt;li&gt;提供高可靠的集群管理系统&lt;/li&gt;&#xA;&lt;li&gt;支持上万台机器高效运行&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Borg 的创新在于将分布式资源抽象为可调度的统一资源池，并结合任务优先级、抢占机制、作业声明式配置等理念，为现代云计算和容器编排系统奠定了基础。&lt;/p&gt;&#xA;&lt;h1 id=&#34;2-架构设计&#34;&gt;2. 架构设计&lt;/h1&gt;&#xA;&lt;h2 id=&#34;21-架构简述&#34;&gt;2.1. 架构简述&lt;/h2&gt;&#xA;&lt;p&gt;Brog系统由以下组件构成，与Kubernetes架构几乎一致：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Cluster/Cell：一组机器集群，由大量worker节点（Borglet进程）和BorgMaster组成&lt;/li&gt;&#xA;&lt;li&gt;BorgMaster：Cell控制器，负责处理来自用户的所有请求，管理Cell中所有Borglet的状态，以及调度和启动任务。由集群组成，使用Paxos协议确保副本的数据一致性。&lt;/li&gt;&#xA;&lt;li&gt;Borglet：运行在每个worker节点上，运行BrogMaster分配的任务，负责监控本地任务的状态和资源使用情况，并定期上报给BrogMaster。&lt;/li&gt;&#xA;&lt;li&gt;Scheduler：当新Job被提交到BrogMaster后，Scheduler负责扫描待处理任务，并按照任务优先级，在Cell中寻找合适的Borglet来运行，找到Borglet后通知BorgMaster下发Job，通常Scheduler集成在BrogMaster中。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20251020155915796.png&#34; alt=&#34;Borg Arch&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;22-job--task&#34;&gt;2.2. Job / Task&lt;/h2&gt;&#xA;&lt;p&gt;用户以Job的形式提交给Borg，Job由一个或多个Task组成，每个Task对应着一组Linux进程，每个Job只运行在同一个Cell中。&lt;/p&gt;&#xA;&lt;p&gt;Cell主要运行两种Task：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;应该永不停止的、长期运行的服务，处理时间较短且对网络延迟敏感的请求。&lt;/li&gt;&#xA;&lt;li&gt;批处理作业，执行时间较长，例如MapReduce等&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Borg通过任务优先级和配额，合理分配集群资源，优先级表示Cell中运行的Job相对重要性，配额用来决定允许哪个作业可以被调度，配额是指特定时间段的资源使用数量。&lt;/p&gt;&#xA;&lt;p&gt;Borg 为每个Task创建了一个固定的 BNS 域名(Borg Name Service)，使得其他Task可以访问到该服务。&lt;/p&gt;&#xA;&lt;h2 id=&#34;23-borgmaster&#34;&gt;2.3. BorgMaster&lt;/h2&gt;&#xA;&lt;p&gt;BorgMaster由两个进程组成：BrogMaster主进程和scheduler进程，其中主进程负责处理client的RPC请求，并与Borglet通信，提供了Web UI，BorgMaster逻辑上是单个进程，实际上有五个replica，每个replica都在内存中维护了Cell的状态，replica基于Paxos协议组成了一个高可用的分布式系统，其中有一个Master节点，负责处理所有变更Cell状态的RPC请求。某个时刻BrogMaster会创建checkpoint，以定期快照和变更日志的形式，保存在Paxos存储中。&lt;/p&gt;&#xA;&lt;h2 id=&#34;24-调度&#34;&gt;2.4. 调度&lt;/h2&gt;&#xA;&lt;p&gt;当client提交一个Job后，BorgMaster会把它持久化道Paxos存储上，并将这个Job中所有的Task都加入到等待队列中，Scheduler会异步扫描等待队列，将Task分配到合适的机器上。Borg调度算法有两个步骤：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;可行性检查：找到可以运行Task的一批机器&lt;/li&gt;&#xA;&lt;li&gt;评分：从中选择合适的机器&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Borg早期使用优化后的E-PVM算法进行评分，这个算法会把负载分散到所有的机器，但是导致了资源的碎片化，对突如其来的大型任务支持性较差。最佳匹配算法与之相反，挨个对机器资源进行分配， 这样会有空闲机器来处理大型任务。&lt;/p&gt;&#xA;&lt;h2 id=&#34;25-borglet&#34;&gt;2.5. Borglet&lt;/h2&gt;&#xA;&lt;p&gt;Borglet是部署在每台机器上的proxy进程，负责启动、停止Task，并需要将本机状态上报给BorgMaster，每个BorgMaster replica会负责一个无状态的link shard来处理部分的Borglet的通信，来减少Master的更新负担。&lt;/p&gt;&#xA;&lt;h2 id=&#34;26-扩展性设计&#34;&gt;2.6. 扩展性设计&lt;/h2&gt;&#xA;&lt;p&gt;Borg支持使用单独的BorgMaster管理有着数千台机器的Cell，Cell可能每分钟有10K的任务被提交到集群。早期BorgMaster使用简单的同步循环实现scheduler，为了处理更多的任务，Borg的scheduler被分离为单独的进程，Scheduler会重复处理流程如下：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;从选举出来的BorgMaster获取状态变更数据&lt;/li&gt;&#xA;&lt;li&gt;更新自己的本地副本状态&lt;/li&gt;&#xA;&lt;li&gt;执行一轮调度来分配任务&lt;/li&gt;&#xA;&lt;li&gt;将分配信息发送给Master&lt;/li&gt;&#xA;&lt;li&gt;Master接受数据，如果分配计划不合理或者过时，会等待下一轮调度。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Borg在性能优化上的方法如下：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;缓存评分信息：Borg会缓存计算得出的机器评分，用于下次调度使用，如果机器属性更新，则会触发缓存失效&lt;/li&gt;&#xA;&lt;li&gt;任务等效类：一般来说，同一个Borg作业的任务都有相同的请求和约束，Borg只对等效类中的一个任务做可行性检查和评分，而不是遍历计算所有的任务&lt;/li&gt;&#xA;&lt;li&gt;适度随机：Scheduler可能会随机抽取机器，直到找到足够多的可用机器并完成评分，从中挑选最合适的分配任务&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;27-隔离&#34;&gt;2.7. 隔离&lt;/h2&gt;&#xA;&lt;p&gt;Borg使用Linux的chroot作为机器的安全隔离机制，Google的AppEngine使用VM和安全沙箱运行外部软件，每个运行在KVM进程的VM，作为一个Borg任务来运行。&lt;/p&gt;</description>
    </item>
    <item>
      <title>OSDI &#39;12 Spanner Google’s Globally-Distributed Database</title>
      <link>http://localhost:1313/posts/paper-reading/spanner/</link>
      <pubDate>Tue, 07 Oct 2025 16:30:12 +0800</pubDate>
      <guid>http://localhost:1313/posts/paper-reading/spanner/</guid>
      <description>&lt;h1 id=&#34;intro&#34;&gt;Intro&lt;/h1&gt;&#xA;&lt;p&gt;Google Spanner是一个全球性分布式数据库，提供了关系型数据库ACID语义的同时，兼顾了分布式系统的高扩展性，在Spanner之前，Google内部主要依赖两类存储系统：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;BigTable：不支持ACID的关系型大规模列式存储，无法支持强事务应用场景。&lt;/li&gt;&#xA;&lt;li&gt;MegaStore：支持ACID语义，但事务存在跨Entity Group时吞吐量较差， 难以支撑跨数据中心的分大规模事务场景。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Spanner的设计目标正是弥补上述缺陷：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;全球分布和扩展性：支持跨数据中心部署，并保证线性可扩展&lt;/li&gt;&#xA;&lt;li&gt;强一致事务：可以细粒度控制数据副本，支持跨数据中心的事务，改善MegaStore的事务限制&lt;/li&gt;&#xA;&lt;li&gt;一致性时间语义：通过TrueTime API，实现全球范围的外部一致性（线性）&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h1 id=&#34;架构设计&#34;&gt;架构设计&lt;/h1&gt;&#xA;&lt;p&gt;Spanner使用Zone作为一个部署服务的最小单元，每个Zone中包含以下三个组件：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;zone master：为spanserver分配数据&lt;/li&gt;&#xA;&lt;li&gt;spanserver：为client提供数据服务&lt;/li&gt;&#xA;&lt;li&gt;location proxy：负责分发client的请求&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;在Zone之外还有两个单例服务：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;universe master：显示所有Zone的状态信息，用于监控调试。&lt;/li&gt;&#xA;&lt;li&gt;placement driver：可以分钟级完成Zone间的自动化迁移，定期与spanserver通信获取需要迁移的数据，以满足数据负载均衡的需求。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20250908164640902.png&#34; alt=&#34;Spanner Arch&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;spanserver&#34;&gt;spanserver&lt;/h2&gt;&#xA;&lt;p&gt;Spanserver架构层次上来看，由下到上分别为：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;数据存储层（Colossus、BigTable Tablet）&lt;/li&gt;&#xA;&lt;li&gt;数据复制和一致性（Paxos）&lt;/li&gt;&#xA;&lt;li&gt;事务处理、并发控制、领导者选举&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20251016111712280.png&#34; alt=&#34;spanserver stack&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;数据存储层&#34;&gt;数据存储层&lt;/h3&gt;&#xA;&lt;p&gt;Tablet 是 Spanner 管理数据的基本单位，是一个逻辑结构，使用B-Tree和WAL进行管理，内部有timestamp，用于支持Spanner实现MVCC机制。Colossus作为底层的数据存储引擎，它是Google对GFS的优化项目，用于支撑Spanner大规模存储。所有的Tablet以文件形式存储在Colossus中。&lt;/p&gt;&#xA;&lt;h3 id=&#34;数据复制与一致性&#34;&gt;数据复制与一致性&lt;/h3&gt;&#xA;&lt;p&gt;为了防止意外情况导致的数据丢失，Spanner支持副本机制，每个Tablet上都实现了一个Paxos状态机，写操作由Tablet leader执行，读操作可以从任意在同步中的Tablet执行。&lt;/p&gt;&#xA;&lt;h2 id=&#34;directory&#34;&gt;Directory&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;Directory&lt;/strong&gt;是Spanner的逻辑分区，类似于bucket概念，一个Paxos Group可能包含多个directory，每个directory都对应一段key range。&lt;/p&gt;&#xA;&lt;h2 id=&#34;truetime&#34;&gt;TrueTime&lt;/h2&gt;&#xA;&lt;p&gt;Spanner为了实现全球范围的分布式事务和一致性，设计了TrueTime，来解决传统分布式系统的时钟问题：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;各节点时钟可能存在偏移问题&lt;/li&gt;&#xA;&lt;li&gt;仅靠NTP同步的时间，无法达到毫秒级一致&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;TrueTime能在即使物理时间存在偏差的情况下，也能保证严格的线性一致性。&lt;/p&gt;&#xA;&lt;p&gt;TrueTime API提供了以下三个方法：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20251016152052873.png&#34; alt=&#34;TrueTime API&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;TrueTime底层使用的参考时间为GPS和原子时钟两种模式，GPS模式通过数据中心的time server和每台机器的time slave daemon线程实现，其余的master使用原子时钟。&lt;/p&gt;&#xA;&lt;h2 id=&#34;事务管理和并发控制&#34;&gt;事务管理和并发控制&lt;/h2&gt;&#xA;&lt;p&gt;Spanner 支持 &lt;strong&gt;分布式事务（跨多个 Paxos group）&lt;/strong&gt;，其核心机制是：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;2PC：跨 Tablet 的事务使用 &lt;strong&gt;2PC&lt;/strong&gt; 协调提交&lt;/li&gt;&#xA;&lt;li&gt;时间戳分配与 TrueTime&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;每个leader副本中，都有一个lock table来实现并发控制，并且支持2PC，Spanner中各类读写情况对比如下：&lt;/p&gt;</description>
    </item>
    <item>
      <title>CIDR &#39;11 Megastore: Providing Scalable, Highly Available Storage for Interactive Services</title>
      <link>http://localhost:1313/posts/paper-reading/megastore/</link>
      <pubDate>Fri, 25 Jul 2025 14:23:12 +0800</pubDate>
      <guid>http://localhost:1313/posts/paper-reading/megastore/</guid>
      <description>&lt;h1 id=&#34;1-intro&#34;&gt;1. Intro&lt;/h1&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://research.google/pubs/megastore-providing-scalable-highly-available-storage-for-interactive-services/&#34;&gt;《Megastore: Providing Scalable, Highly Available Storage for Interactive Services》&lt;/a&gt;是Google于CIDR 2011上发表的一篇重要论文，该论文介绍了 Google 内部使用的一种分布式存储系统——&lt;strong&gt;Megastore&lt;/strong&gt;，它在&lt;strong&gt;强一致性&lt;/strong&gt;与&lt;strong&gt;高可用性&lt;/strong&gt;之间实现了权衡，构建于BigTable之上，引入了事务机制、同步复制、SQL查询接口等，它将RDB的事务机制、一致性和NoSQL高扩展性结合起来。MegaStore对数据进行分区，并对每个分区使用Paxos算法实现同步复制，在分区内支持完整的ACID语义。&lt;/p&gt;&#xA;&lt;h1 id=&#34;2-存储设计&#34;&gt;2. 存储设计&lt;/h1&gt;&#xA;&lt;h2 id=&#34;21-逻辑设计&#34;&gt;2.1. 逻辑设计&lt;/h2&gt;&#xA;&lt;p&gt;MegaStore将数据划分为多个Entity Groups，每个Entity Group都独立进行Paxos数据复制，并且该Group内部支持ACID语义。&lt;/p&gt;&#xA;&lt;p&gt;一个 &lt;strong&gt;Entity Group&lt;/strong&gt; 是一组相关联的数据实体（records），这些实体共享同一个 &lt;strong&gt;分布式事务边界&lt;/strong&gt; 和 &lt;strong&gt;Paxos日志&lt;/strong&gt;，在这个组内支持强一致的事务操作。&lt;/p&gt;&#xA;&lt;p&gt;例如一个Group可能同时包含两个Data Model：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;entitygroup&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;UserGroup&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;table&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;User&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;column&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user_id&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;key=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;column&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;table&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Settings&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;column&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user_id&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;key=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;column&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dark_mode&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/entitygroup&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20250724135714974.png&#34; alt=&#34;Scalable Replication&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;通过上文可知，Group越大，单个Group的Paxos日志负载越高，Group越小，跨Group事务越容易发生，性能越差，因此如何选定Entity Group的边界十分重要。论文中提到：Megastore 要求应用开发者根据访问模式来决定Entity Group边界。开发者需要遵循以下规则：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;高频事务操作的数据放在一个Entity Group&lt;/li&gt;&#xA;&lt;li&gt;跨Group的事务代价较高，尽量避免&lt;/li&gt;&#xA;&lt;li&gt;避免将大量数据放进一个Group，可能导致Paxos日志并发性能瓶颈&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;22-物理存储设计&#34;&gt;2.2. 物理存储设计&lt;/h2&gt;&#xA;&lt;p&gt;MegaStore的物理存储层使用BigTable实现，每个Entity Group的数据都存储在BigTable的连续行，来提高系统吞吐量和数据命中效率。&lt;/p&gt;&#xA;&lt;p&gt;Megastore 并不是从头开发一个全新的存储引擎，而是使用BigTable作为底层存储引擎，负责数据的持久化、分片以及数据中心内的存储和基本读写，跨数据中心的数据复制，则由MegaStore自行实现。&lt;/p&gt;&#xA;&lt;p&gt;Megastore 通过精心设计 row key规则，将一个 Entity Group 内的所有记录 &lt;strong&gt;编码为一组具有相同前缀的 row keys&lt;/strong&gt;，以实现数据局部性。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20250724162336516.png&#34; alt=&#34;sample data layout in BigTable&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>NSDI &#39;12 Resilient Distributed Datasets: A Fault-Tolerant Abstraction for In-Memory Cluster Computing</title>
      <link>http://localhost:1313/posts/paper-reading/spark-rdd-paper/</link>
      <pubDate>Tue, 22 Jul 2025 13:43:37 +0800</pubDate>
      <guid>http://localhost:1313/posts/paper-reading/spark-rdd-paper/</guid>
      <description>&lt;h1 id=&#34;1-intro&#34;&gt;1. Intro&lt;/h1&gt;&#xA;&lt;p&gt;在此之前的分布式计算框架，例如 MapReduce，缺乏对分布式内存的复用能力。在 MapReduce 中，每一轮 Map 和 Reduce 任务之间的中间结果都会被写入磁盘，随后再从磁盘中读取用于下一阶段的计算。这种设计带来了大量的磁盘 I/O、数据复制和对象序列化/反序列化的开销，从而在许多迭代式或交互式的大数据应用中成为性能瓶颈，占据了绝大部分的执行时间。&lt;/p&gt;&#xA;&lt;p&gt;为了解决上述问题，Spark 引入了弹性分布式数据集（Resilient Distributed Dataset，RDD）的抽象。RDD 是一个只读的分布式对象集合，可以并行操作，支持在内存中缓存中间计算结果，从而显著减少了 I/O 和序列化成本。RDD 提供了丰富的转换操作符（如 &lt;code&gt;map&lt;/code&gt;、&lt;code&gt;filter&lt;/code&gt;、&lt;code&gt;reduceByKey&lt;/code&gt;、&lt;code&gt;collect&lt;/code&gt; 等），使得开发人员能够以函数式编程方式，在大规模集群上构建高效、容错的内存计算任务。与此同时，RDD 通过血缘（lineage）信息来实现容错机制，即使节点失败也能基于操作链自动恢复数据，无需数据复制带来的额外存储成本。&lt;/p&gt;&#xA;&lt;h1 id=&#34;2-rdd模型设计&#34;&gt;2. RDD模型设计&lt;/h1&gt;&#xA;&lt;p&gt;RDD是一个只读，可分区、支持并行计算的数据集，可以通过操作符将RDD转换成新的RDD，并且两个RDD之间存在血缘关联。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20250721103248860.png&#34; alt=&#34;RDD lineage&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;RDD的弹性体现在：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;存储：内存不足时可以和磁盘进行数据交换&lt;/li&gt;&#xA;&lt;li&gt;计算：计算出错时支持重试&lt;/li&gt;&#xA;&lt;li&gt;容错：数据丢失可以自动恢复&lt;/li&gt;&#xA;&lt;li&gt;分区：支持重新分区&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;下面是一个从HDFS读取文本文件，并执行计算的案例：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lines &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; spark&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;textFile&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hdfs://...&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;errors &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; lines&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;filter&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;startsWith&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ERROR&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;errors&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;persist&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Count errors mentioning MySQL:  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;errors&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;filter&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;contains&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;MySQL&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)).&lt;/span&gt;count&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Return the time fields of errors mentioning  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// HDFS as an array (assuming time is field  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// number 3 in a tab-separated format):  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;errors&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;filter&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;contains&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HDFS&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;map&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;split&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;’&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;\t&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;’&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)(&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;collect&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;下图是上述案例中RDD血缘关系图，不同的RDD之间通过转换操作符进行连接。&lt;/p&gt;</description>
    </item>
    <item>
      <title>OSDI &#39;06 Bigtable A Distributed Storage System for Structured Data</title>
      <link>http://localhost:1313/posts/paper-reading/bigtable/</link>
      <pubDate>Mon, 07 Jul 2025 14:23:12 +0800</pubDate>
      <guid>http://localhost:1313/posts/paper-reading/bigtable/</guid>
      <description>&lt;h1 id=&#34;1-intro&#34;&gt;1. Intro&lt;/h1&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://storage.googleapis.com/gweb-research2023-media/pubtools/4443.pdf&#34;&gt;Bigtable: A Distributed Storage System for Structured Data&lt;/a&gt;是Google发布于ODDI 2006的一篇论文，介绍了当时Google内部大规模使用的结构化分布式存储系统BigTable的设计与实现。BigTable 被广泛应用于 Google 内部多个核心产品中，如 Google Analytics、Google Earth等产品。&lt;/p&gt;&#xA;&lt;p&gt;与传统RDB产品相比，BigTable参考了很多实现方案，但它不支持完整的关系数据模型，而是通过一个稀疏的多维映射结构，在性能、可扩展性和容错性之间取得了良好平衡。设计中的BigTable支持扩展到PB级数据量和上千数据节点，实现了高性能、高可用性等设计目标。BigTable 构建于 Google 自身的基础设施之上，使用GFS完成数据存储，使用 Chubby 锁完成分布式协调。本文将围绕论文中数据模型、架构设计、容错机制等方面进行分析。&lt;/p&gt;&#xA;&lt;h1 id=&#34;2-数据模型设计&#34;&gt;2. 数据模型设计&lt;/h1&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;A Bigtable is a sparse, distributed, persistent multidimensional sorted map.&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;BigTable是一个稀疏、分布式、持久化存储的多维Map结构，主要体现在：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Sparse：于关系模型约束严格的RDB相比，BigTable每一行数据的Column组成可能不同，行与行之间可以是不同的列。&lt;/li&gt;&#xA;&lt;li&gt;Distributed：Map会被切分成多个分区，在多个机器上分布存储。&lt;/li&gt;&#xA;&lt;li&gt;Persistent：Map中所有记录都会被持久化存储。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;数据结构特点：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;数据通过row key、column key和一个timestamp进行索引&lt;/li&gt;&#xA;&lt;li&gt;表中每个数据项都是字节数组&lt;/li&gt;&#xA;&lt;li&gt;映射关系为：$(row:string, column:string, time:int64) → string$&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20250706222938.png&#34; alt=&#34;data model&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;以下图为例：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;row key：逆序URL，方便按照主机名排序，加速查询&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;contents：&lt;/code&gt;列：存储HTML页面信息，存在三个版本，对应时间戳为t3、t5、t6&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;anchor:&lt;/code&gt;：这是一个column family（列族）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20250703195329880.png&#34; alt=&#34;BigTable Model&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;BigTable不支持完整的关系型数据模型：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;提供客户端的是一个简单数据模型&lt;/li&gt;&#xA;&lt;li&gt;支持动态控制数据格式，允许client推测数据在底层存储中的locality特性&lt;/li&gt;&#xA;&lt;li&gt;数据使用行名和列名进行索引&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;21-row&#34;&gt;2.1. Row&lt;/h2&gt;&#xA;&lt;p&gt;Row是BigTable的基本数据单位，可以类比RDB中的Row，每个Row通过唯一的Row Key来标识，实际上按照Row Key字典序进行存储，BigTable动态分区规则也是根据Row Key进行切分，每个分区被称为&lt;strong&gt;Tablet&lt;/strong&gt;，这是基本物理存储单元。&lt;/p&gt;</description>
    </item>
    <item>
      <title>OSDI &#39;04 MapReduce Simplified Data Processing on Large Clusters</title>
      <link>http://localhost:1313/posts/paper-reading/mapreduce-note/</link>
      <pubDate>Wed, 02 Jul 2025 15:43:37 +0800</pubDate>
      <guid>http://localhost:1313/posts/paper-reading/mapreduce-note/</guid>
      <description>&lt;h1 id=&#34;1-intro&#34;&gt;1. Intro&lt;/h1&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://research.google/pubs/mapreduce-simplified-data-processing-on-large-clusters/&#34;&gt;《MapReduce: Simplified Data Processing on Large Clusters》&lt;/a&gt;是Google发布于 OSDI 2004的一篇分布式计算领域论文，奠定了大规模数据处理的基础架构范式，是大数据领域的里程碑式工作。该论文系统性地提出了一种简洁的编程模型，使开发者可以方便地在大规模分布式系统中进行并行计算，而无需关注底层的容错、调度、数据分片等复杂问题。通过将任务划分为 Map 和 Reduce 两个阶段，系统自动完成任务调度、节点容错与数据传输，大幅提升了开发效率与系统可扩展性。&lt;/p&gt;&#xA;&lt;h1 id=&#34;2-编程模型设计&#34;&gt;2. 编程模型设计&lt;/h1&gt;&#xA;&lt;p&gt;计算任务大都可以被抽象为map和reduce操作，首先对输入数据中每条逻辑记录应用map操作以计算出一系列的中间键值对，然后对所有键相同的值应用reduce操作以合理地整合这些派生数据。&lt;/p&gt;&#xA;&lt;p&gt;MapReduce执行过程可以简单理解为：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;利用一个输入的&lt;strong&gt;key/value pair&lt;/strong&gt;集合来产生一个输出的&lt;strong&gt;key/value pair&lt;/strong&gt;集合。&lt;/li&gt;&#xA;&lt;li&gt;自定义的Map函数接受一个&lt;strong&gt;key/value pair&lt;/strong&gt;输入，然后产生一个中间&lt;strong&gt;key/value pair&lt;/strong&gt;集合。会将相同key和对应多个value值集合在一起传递给reduce函数。&lt;/li&gt;&#xA;&lt;li&gt;自定义的Reduce函数接受上面的集合，合并这些value值，形成一个新的value值集合。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Map Reduce函数可以抽象成以下形式：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;map(k1, v1) -&amp;gt; list(k2, v2)&#xA;reduce(k2, list(v2)) -&amp;gt; list(v2)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;21-以wordcount为例&#34;&gt;2.1. 以wordcount为例&lt;/h2&gt;&#xA;&lt;p&gt;考虑一个业务场景：需要统计大批量文件中每个单词的出现次数，开发者编写的伪代码如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;map(String key, String value):&#xA;  // key: document name&#xA;  // value: document contents&#xA;  for each word w in value:&#xA;    EmitIntermediate(w, &amp;#34;1&amp;#34;);&#xA;&#xA;reduce(String key, Iterator values):&#xA;  // key: a word&#xA;  // values: a list of counts&#xA;  int result = 0;&#xA;  for each v in values:&#xA;    result += ParseInt(v);&#xA;  Emit(AsString(result));&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;通过两阶段任务，将原始计算需求拆分为：先计算每个单词出现的次数，再通过reduce阶段合并计算每个单词出现次数总和。&lt;/p&gt;</description>
    </item>
    <item>
      <title>SOSP &#39;03 The Google File System</title>
      <link>http://localhost:1313/posts/paper-reading/the-google-file-system/</link>
      <pubDate>Thu, 26 Jun 2025 11:43:37 +0800</pubDate>
      <guid>http://localhost:1313/posts/paper-reading/the-google-file-system/</guid>
      <description>&lt;h1 id=&#34;1-intro&#34;&gt;1. Intro&lt;/h1&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://research.google.com/archive/gfs-sosp2003.pdf&#34;&gt;《The Google File System》&lt;/a&gt;（GFS）是Google于2003年在ACM SOSP（Symposium on Operating Systems Principles）上发表的一篇论文。它首次系统性地介绍了Google内部为应对大规模数据处理而设计的分布式文件系统架构。&lt;/p&gt;&#xA;&lt;p&gt;在21世纪初，随着互联网的爆发式发展，Google需要存储并处理海量的网页、图片等数据，传统File System无论在性能、容错性、可靠性等方面都无法满足需求，因此Google设计了GFS以解决大规模文件存储和管理的需求。&lt;/p&gt;&#xA;&lt;h1 id=&#34;2-设计概览&#34;&gt;2. 设计概览&lt;/h1&gt;&#xA;&lt;h2 id=&#34;21-设计目标&#34;&gt;2.1. 设计目标&lt;/h2&gt;&#xA;&lt;p&gt;GFS的主要设计目标包括：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;性能&lt;/li&gt;&#xA;&lt;li&gt;可用性&lt;/li&gt;&#xA;&lt;li&gt;可伸缩性&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;需要满足的需求：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;系统由大量廉价的存储介质构成，需要考虑监控、容错、快速回复能力&lt;/li&gt;&#xA;&lt;li&gt;需要解决大量文件存储和管理。&lt;/li&gt;&#xA;&lt;li&gt;读取场景：大规模的顺序读，小规模的随机读&lt;/li&gt;&#xA;&lt;li&gt;写入场景：大规模的顺序写，极少数的小规模随机写&lt;/li&gt;&#xA;&lt;li&gt;并发支持：支持多Client并发写入同一个文件的场景&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;22-集群概览&#34;&gt;2.2. 集群概览&lt;/h2&gt;&#xA;&lt;p&gt;GFS集群从架构上看，节点分成两个类型：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Master：整个集群的Master节点，负责以下职责：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;维护所有Chunk Server节点的metadata&lt;/li&gt;&#xA;&lt;li&gt;回收废弃chunk&lt;/li&gt;&#xA;&lt;li&gt;Chunk Server之间chunk迁移&lt;/li&gt;&#xA;&lt;li&gt;与Chunk Server进行HeartBeat&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Chunk Server：文件会被切分成chunk存储到节点中，每个chunk存在三个备份。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20250620165217900.png&#34; alt=&#34;GFS Architecture&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;存储文件时，GFS会将文件切分成若干个固定大小的Chunk块并存储，Master会为每个Chunk块分配一个唯一Hash key（论文中成为handle），并将它们交由Chunk Server存储，Chunk Server以普通文件的形式将每个Chunk存储在本地磁盘上，并存储多Replica以保证数据可靠性。&lt;/p&gt;&#xA;&lt;p&gt;Client从GFS读取文件的步骤划分为：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Client在本地通过文件名和byte offset转换为chunk index&lt;/li&gt;&#xA;&lt;li&gt;Client向Master发送携带filename和chunk index的请求，以获取chunk的唯一标识chunk handle和chunk replica所在的Chunk Server地址&lt;/li&gt;&#xA;&lt;li&gt;Client向最近的Chunk Server请求chunk数据&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;23-chunk-size&#34;&gt;2.3. Chunk Size&lt;/h2&gt;&#xA;&lt;p&gt;Chunk Size是分布式文件存储系统中一个重要的性能指标，在参数选择上需要取舍以下因素：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;因素&lt;/th&gt;&#xA;          &lt;th&gt;Chunk 越大&lt;/th&gt;&#xA;          &lt;th&gt;Chunk 越小&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;元数据压力&lt;/td&gt;&#xA;          &lt;td&gt;减少&lt;/td&gt;&#xA;          &lt;td&gt;增加&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;随机访问延迟&lt;/td&gt;&#xA;          &lt;td&gt;增加（加载较大 chunk耗时）&lt;/td&gt;&#xA;          &lt;td&gt;降低&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;顺序访问吞吐&lt;/td&gt;&#xA;          &lt;td&gt;更高&lt;/td&gt;&#xA;          &lt;td&gt;更低&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;负载均衡灵活性&lt;/td&gt;&#xA;          &lt;td&gt;降低（数据倾斜）&lt;/td&gt;&#xA;          &lt;td&gt;更好&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;容错恢复代价&lt;/td&gt;&#xA;          &lt;td&gt;更大（单个 chunk 损坏数据多）&lt;/td&gt;&#xA;          &lt;td&gt;更小&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;网络带宽利用效率&lt;/td&gt;&#xA;          &lt;td&gt;更高&lt;/td&gt;&#xA;          &lt;td&gt;更低（小文件碎片化）&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;GFS的chunk size选取为64MB，论文中提到选取大chunk的原因如下：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kafka设计简析</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-design/</link>
      <pubDate>Thu, 29 May 2025 14:43:37 +0800</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-design/</guid>
      <description>&lt;h1 id=&#34;1-intro&#34;&gt;1. Intro&lt;/h1&gt;&#xA;&lt;p&gt;​Apache Kafka是一个分布式事件存储和流处理平台，最初由LinkedIn公司开发，旨在解决其内部大规模实时数据流存储的问题。​在2011年初，LinkedIn将Kafka作为开源项目发布，并于2012年10月23日，Kafka从Apache孵化器毕业，成为Apache软件基金会的顶级项目。2014年11月，几位曾在LinkedIn参与Kafka开发的工程师，包括Jay Kreps、Neha Narkhede和Jun Rao，离开LinkedIn创立了Confluent公司，专注于提供与Kafka相关的企业级支持和服务。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20250324161806.png&#34; alt=&#34;AutoMQ&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;11-设计亮点&#34;&gt;1.1. 设计亮点&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th style=&#34;text-align: center&#34;&gt;方案&lt;/th&gt;&#xA;          &lt;th style=&#34;text-align: left&#34;&gt;细节&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;磁盘存储+pagecache替代内存缓存&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: left&#34;&gt;JVM语言操作内存成本较高，并且Kafka为重网络I/O应用，顺序读写+pagecache场景下磁盘I/O并不会成为性能瓶颈&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;合适的数据结构&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: left&#34;&gt;数据存储系统通常使用Btree进行持久化存储，而message system通常为尾端I/O，使用queue可以实现O(1)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;异步batch I/O&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: left&#34;&gt;producer端积攒一批消息，使用一次网络I/O传输到broker，降低多次small I/O的次数&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;文件零拷贝&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: left&#34;&gt;broker向client返回log数据时，使用mmap内存映射避免多次&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;消息压缩&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: left&#34;&gt;端到端传输/存储时，会对原始消息进行压缩&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;broker负载均衡&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: left&#34;&gt;topic再次物理划分partition，producer写入请求均衡打到各个partition所在broker&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;ISR机制&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: left&#34;&gt;基于多副本机制，实现集群容错和高可用&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;broker端网络模式&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: left&#34;&gt;使用Reactor网络模式，按职责划分为：接受请求的acceptor，实际处理逻辑的processor，提升了broker端吞吐量&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;exactly once语义&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: left&#34;&gt;producer端：开启幂等性后，每条消息都会附带sequence number，broker端严格接受递增sequence number，确保不会存在重复数据。&lt;br&gt;consumer端：实现消费-处理-提交 offset 的原子性（事务实现）&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h2 id=&#34;12-消息模型&#34;&gt;1.2. 消息模型&lt;/h2&gt;&#xA;&lt;h3 id=&#34;121-queue-modelpeer-to-peer&#34;&gt;1.2.1. Queue Model（peer to peer）&lt;/h3&gt;&#xA;&lt;p&gt;生产者将消息发送到Queue时会进行暂时存储，当消费者完成消费或者消息TTL到期，将会从队列中移除，每条消息只有一个consumer进行消费。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20250326135759.png&#34; alt=&#34;p2p&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;案例：redis queue、Amazon SQS、RabbitMQ、activeMQ等&lt;/p&gt;&#xA;&lt;h3 id=&#34;122-pubsub-model&#34;&gt;1.2.2. Pub/Sub Model&lt;/h3&gt;&#xA;&lt;p&gt;​发布/订阅（Pub/Sub）模型是一种异步消息传递模式，旨在实现应用程序组件之间的解耦。​在这种模式中，消息发布者Publisher将消息发布到特定的Topic，而消息订阅者Subscriber则订阅感兴趣的主题，以接收相关消息。​这种方式使得发布者和订阅者彼此独立，不直接通信，从而提高系统的灵活性和可扩展性。&lt;/p&gt;&#xA;&lt;p&gt;案例：Kafka、AutoMQ、Pulsar等&lt;/p&gt;&#xA;&lt;h2 id=&#34;13-streaming-storage-platform选型&#34;&gt;1.3. Streaming Storage Platform选型&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;维度&lt;/th&gt;&#xA;          &lt;th&gt;ActiveMQ&lt;/th&gt;&#xA;          &lt;th&gt;RabbitMQ&lt;/th&gt;&#xA;          &lt;th&gt;RocketMQ&lt;/th&gt;&#xA;          &lt;th&gt;Kafka&lt;/th&gt;&#xA;          &lt;th&gt;Pulsar&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;单机吞吐量&lt;/td&gt;&#xA;          &lt;td&gt;较低(万级)&lt;/td&gt;&#xA;          &lt;td&gt;一般（万级）&lt;/td&gt;&#xA;          &lt;td&gt;高（十万级）&lt;/td&gt;&#xA;          &lt;td&gt;高（十万级）&lt;/td&gt;&#xA;          &lt;td&gt;高（十万级）&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;开发语言&lt;/td&gt;&#xA;          &lt;td&gt;Java&lt;/td&gt;&#xA;          &lt;td&gt;Erlang&lt;/td&gt;&#xA;          &lt;td&gt;Java&lt;/td&gt;&#xA;          &lt;td&gt;Java/Scala&lt;/td&gt;&#xA;          &lt;td&gt;Java&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;维护者&lt;/td&gt;&#xA;          &lt;td&gt;Apache&lt;/td&gt;&#xA;          &lt;td&gt;Spring&lt;/td&gt;&#xA;          &lt;td&gt;Apache（Alibaba）&lt;/td&gt;&#xA;          &lt;td&gt;Apache（Confluent）&lt;/td&gt;&#xA;          &lt;td&gt;Apache（StreamNative）&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;社区活跃度&lt;/td&gt;&#xA;          &lt;td&gt;低&lt;/td&gt;&#xA;          &lt;td&gt;高&lt;/td&gt;&#xA;          &lt;td&gt;高&lt;/td&gt;&#xA;          &lt;td&gt;高&lt;/td&gt;&#xA;          &lt;td&gt;高&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;消费模式&lt;/td&gt;&#xA;          &lt;td&gt;P2P、Pub-Sub&lt;/td&gt;&#xA;          &lt;td&gt;direct、topic、Headers、fanout&lt;/td&gt;&#xA;          &lt;td&gt;基于 Topic 和 MessageTag 的的 Pub-Sub&lt;/td&gt;&#xA;          &lt;td&gt;基于 Topic 的 Pub-Sub&lt;/td&gt;&#xA;          &lt;td&gt;基于 Topic 的 Pub-Sub，支持独占（exclusive）、共享（shared）、灾备（failover）、key 共享（key_shared）4 种模式&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;持久化&lt;/td&gt;&#xA;          &lt;td&gt;支持（小）&lt;/td&gt;&#xA;          &lt;td&gt;支持（小）&lt;/td&gt;&#xA;          &lt;td&gt;支持（大）&lt;/td&gt;&#xA;          &lt;td&gt;支持（大）&lt;/td&gt;&#xA;          &lt;td&gt;支持（大）&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;顺序消息&lt;/td&gt;&#xA;          &lt;td&gt;不支持&lt;/td&gt;&#xA;          &lt;td&gt;不支持&lt;/td&gt;&#xA;          &lt;td&gt;支持&lt;/td&gt;&#xA;          &lt;td&gt;支持&lt;/td&gt;&#xA;          &lt;td&gt;支持&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;集群支持&lt;/td&gt;&#xA;          &lt;td&gt;主备模式&lt;/td&gt;&#xA;          &lt;td&gt;复制模式&lt;/td&gt;&#xA;          &lt;td&gt;主备模式&lt;/td&gt;&#xA;          &lt;td&gt;Leader-Slave 每台既是 master 也是 slave，集群可扩展性强&lt;/td&gt;&#xA;          &lt;td&gt;集群模式，broker 无状态，易迁移，支持跨数据中心&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;存算分离&lt;/td&gt;&#xA;          &lt;td&gt;不支持&lt;/td&gt;&#xA;          &lt;td&gt;不支持&lt;/td&gt;&#xA;          &lt;td&gt;支持&lt;/td&gt;&#xA;          &lt;td&gt;支持&lt;/td&gt;&#xA;          &lt;td&gt;支持&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;AMQP 支持&lt;/td&gt;&#xA;          &lt;td&gt;支持&lt;/td&gt;&#xA;          &lt;td&gt;支持&lt;/td&gt;&#xA;          &lt;td&gt;支持&lt;/td&gt;&#xA;          &lt;td&gt;不完全支持&lt;/td&gt;&#xA;          &lt;td&gt;不完全支持&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h2 id=&#34;14-相关术语介绍&#34;&gt;1.4. 相关术语介绍&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Kafka Broker：服务端由被称为&lt;code&gt;Broker&lt;/code&gt;的服务进程构成，&lt;code&gt;Broker&lt;/code&gt;负责接受和处理客户端请求，以及对消息进行持久化。&lt;/li&gt;&#xA;&lt;li&gt;Kafka Controller：集群metadata的管理节点&lt;/li&gt;&#xA;&lt;li&gt;Producer：客户端节点，消息生产方。&lt;/li&gt;&#xA;&lt;li&gt;Customer：客户端节点，消息消费方。&lt;/li&gt;&#xA;&lt;li&gt;Customer Group：消费者组内每个消费者负责消费不同分区的数据。一个分区只能由组内一个消费者消费，不同消费组之间互不影响。&lt;/li&gt;&#xA;&lt;li&gt;&lt;del&gt;Zookeeper集群：负责元数据管理，集群选举。&lt;/del&gt;近期发布（2025.03）的4.0版本已经移除Zookeeper依赖，使用内置KRaft模式管理metadata。&lt;/li&gt;&#xA;&lt;li&gt;Topic：Kafka中消息以topic为单位进行分类，生产者将消息发送到特定的topic，消费者订阅topic进行消费。&lt;/li&gt;&#xA;&lt;li&gt;Partition：针对Topic维度按照消息key的分区，均衡分布到Kafka集群中的各个节点，对数据存储做到均匀分布。&lt;/li&gt;&#xA;&lt;li&gt;Replica：针对Partition维度的副本数据，实现数据备份的功能。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h1 id=&#34;2-client&#34;&gt;2. Client&lt;/h1&gt;&#xA;&lt;p&gt;Kafka clients有5个核心API：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kafka源码分析(十)- KRaft实现细节</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-source-code-10-kraft-detail/</link>
      <pubDate>Mon, 14 Apr 2025 10:49:53 +0800</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-source-code-10-kraft-detail/</guid>
      <description>&lt;h1 id=&#34;1-intro&#34;&gt;1. Intro&lt;/h1&gt;&#xA;&lt;p&gt;上文介绍了KRaft架构的优势与基本组件，本文对Raft协议在Kafka中的实现做简单分析。&lt;/p&gt;&#xA;&lt;h1 id=&#34;2-核心属性&#34;&gt;2. 核心属性&lt;/h1&gt;&#xA;&lt;h2 id=&#34;21-quorumstate&#34;&gt;2.1. QuorumState&lt;/h2&gt;&#xA;&lt;p&gt;QuorumState用于存储KRaft节点状态，并处理状态转换，状态机图如下（引用自&lt;a href=&#34;https://cwiki.apache.org/confluence/display/KAFKA/KIP-595%3A+A+Raft+Protocol+for+the+Metadata+Quorum#KIP595:ARaftProtocolfortheMetadataQuorum-ParentKIP&#34;&gt;KIP-595&lt;/a&gt;）：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20250326133343.png&#34; alt=&#34;image.png&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;核心属性：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//节点id  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; OptionalInt localId;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//目录id  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; Uuid localDirectoryId;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; Time time;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; Logger log;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//用于选举信息存储，JSON格式  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; QuorumStateStore store;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//kraft状态机  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; KRaftControlRecordStateMachine partitionState;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//各个listener endpoint节点信息  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; Endpoints localListeners;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//kraft版本信息  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; SupportedVersionRange localSupportedKRaftVersion;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; Random random;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//选举超时时间  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; electionTimeoutMs;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//fetch超时时间  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; fetchTimeoutMs;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//日志上下文  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; LogContext logContext;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//节点状态对象  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;volatile&lt;/span&gt; EpochState state;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中EpochState接口是对节点状态的抽象，不同节点类型有对应的实现对象：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20250324153811.png&#34; alt=&#34;image.png&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kafka源码分析(九)- KRaft架构简析</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-source-code-9-kraft-basic/</link>
      <pubDate>Wed, 09 Apr 2025 09:51:53 +0800</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-source-code-9-kraft-basic/</guid>
      <description>&lt;h1 id=&#34;1-intro&#34;&gt;1. Intro&lt;/h1&gt;&#xA;&lt;p&gt;Kafka属于单Master多Worker结构，Zookeeper主要提供了metadata存储、分布式同步、集群Leader选举等功能。&lt;/p&gt;&#xA;&lt;p&gt;至于为何当下Kafka抛弃Zookeeper转而选择自建Raft代替，也是一个老生常谈的问题：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Zookeeper作为单独的分布式系统，加大了Kafka集群的部署、运维成本。&lt;/li&gt;&#xA;&lt;li&gt;Zookeeper存在性能瓶颈，无法支撑更大的集群规模，而自建KRaft支持更大数据量级的分区元数据管理。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20250408102752344.png&#34; alt=&#34;image.png&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;下文会对Kafka提出的KRaft架构做简要分析。&lt;/p&gt;&#xA;&lt;h1 id=&#34;2-raft算法回顾&#34;&gt;2. Raft算法回顾&lt;/h1&gt;&#xA;&lt;p&gt;Raft算法是一种用于保证分布式集群中数据一致性算法，在&lt;a href=&#34;https://raft.github.io/raft.pdf&#34;&gt;Raft论文&lt;/a&gt; 中也明确提出：正是因为Paxos算法较为复杂，并且不易于应用到工业界，所以构建了更易于理解的Raft算法来解决分布式系统中的一致性问题。&lt;/p&gt;&#xA;&lt;p&gt;Raft集群中只有三种角色：领导者、候选者、跟随者。Raft算法中每一段任期只有一个领导者节点，每一段任期从一次选举开始，一个或多个候选者参加选举，赢得选举将在接下来的任期充当领导者。跟随者只响应其他服务器的请求。下图为三种状态的转换关系：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20250316162555.png&#34; alt=&#34;image.png&#34;&gt;&lt;/p&gt;&#xA;&lt;h1 id=&#34;3-架构简析&#34;&gt;3. 架构简析&lt;/h1&gt;&#xA;&lt;p&gt;在KRaft架构之前，整个Kafka集群通过Zookeeper来实现元数据存储、选举等目的，通过Zookeeper来选举是通过创建临时节点来实现的，架构实现可以参考下图（&lt;a href=&#34;https://developer.confluent.io/courses/architecture/control-plane/&#34;&gt;confluent&lt;/a&gt;）：&#xA;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20250312134915.png&#34; alt=&#34;image.png&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;KRaft模式中，会选取其中部分Broker作为Controller来完成metadata存储和集群管理，但某个时间段只能有一个active Controller，它负责处理整个集群中的RPC请求，其他用作热备的Controller会从active节点同步数据。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20250312135841.png&#34; alt=&#34;image.png&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;需要注意的是，在日志复制的实现上，KRaft并没有完全采用原生Raft的方式：Leader节点主动往Follower节点推送，而是让Follower主动从Leader执行Fetch。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20250408102655411.png&#34; alt=&#34;message-model&#34;&gt;&lt;/p&gt;&#xA;&lt;h1 id=&#34;4-kraft-基本结构&#34;&gt;4. KRaft 基本结构&lt;/h1&gt;&#xA;&lt;p&gt;KRaft相关提案：&lt;/p&gt;&#xA;&lt;p&gt;KRaft概述：&lt;a href=&#34;https://cwiki.apache.org/confluence/display/KAFKA/KIP-500%3A+Replace+ZooKeeper+with+a+Self-Managed+Metadata+Quorum&#34;&gt;KIP-500&lt;/a&gt;&#xA;KRaft复制/quorum维护协议规范：&lt;a href=&#34;https://cwiki.apache.org/confluence/display/KAFKA/KIP-595%3A+A+Raft+Protocol+for+the+Metadata+Quorum#KIP595:ARaftProtocolfortheMetadataQuorum-ParentKIP&#34;&gt;KIP-595&lt;/a&gt;&#xA;日志压缩：&lt;a href=&#34;https://cwiki.apache.org/confluence/display/KAFKA/KIP-630%3A+Kafka+Raft+Snapshot&#34;&gt;KIP-630&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;KRaft具体实现位于&lt;code&gt;org.apache.kafka.raft&lt;/code&gt;，snapshot被拆分到&lt;code&gt;org.apache.kafka.snapshot&lt;/code&gt;中。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;KafkaRaftManager：KRaft管理与入口类，封装了dir manager、register listener、handleRequest等接口，内部实现通过调用KafkaRaftClient和KafkaRaftClientDriver完成。&lt;/li&gt;&#xA;&lt;li&gt;KafkaRaftClientDriver：Thread类，负责运行、管理KafkaRaftClient的生命周期。&lt;/li&gt;&#xA;&lt;li&gt;KafkaRaftClient：Kafka Raft协议的具体实现，实现RaftClient接口，选举策略采用原生Raft协议，日志复制是follower主动从leader拉取（符合Kafka语义）。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;KRaft提供了Listener接口，提供了commit、snapshot等事件的回调接口。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Listener&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;handleCommit&lt;/span&gt;(BatchReader&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; reader);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;handleLoadSnapshot&lt;/span&gt;(SnapshotReader&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; reader);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;handleLeaderChange&lt;/span&gt;(LeaderAndEpoch leader) {}  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;beginShutdown&lt;/span&gt;() {}  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;RaftClient抽取的通用方法如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;register&lt;/span&gt;(Listener&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; listener);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;unregister&lt;/span&gt;(Listener&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; listener);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;prepareAppend&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; epoch, List&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; records);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;schedulePreparedAppend&lt;/span&gt;();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CompletableFuture&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Void&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;shutdown&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; timeoutMs);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;resign&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; epoch);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Optional&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;SnapshotWriter&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;T&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;createSnapshot&lt;/span&gt;(OffsetAndEpoch snapshotId, &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; lastContainedLogTime);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;41-listener注册逻辑&#34;&gt;4.1. listener注册逻辑&lt;/h2&gt;&#xA;&lt;p&gt;listener采用lazy-register方式，在消费RaftMessage的前置处理中，将一个时间段内的listener进行注册。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kafka源码分析(八)- KafkaController管理(ZK架构)</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-source-code-8-kafka-controller-zk/</link>
      <pubDate>Tue, 08 Apr 2025 10:38:13 +0800</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-source-code-8-kafka-controller-zk/</guid>
      <description>&lt;h1 id=&#34;1-intro&#34;&gt;1. Intro&lt;/h1&gt;&#xA;&lt;p&gt;Controller节点作为Kafka集群的管理节点，它负责为所有partition选举leader副本，并且负责存储和管理集群metadata。本文主要对core模块kafka.controller作简要分析。&lt;/p&gt;&#xA;&lt;p&gt;核心属性如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;controllerContext&lt;/strong&gt;：集群metadata对象&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;controllerChannelManager&lt;/strong&gt;：Controller端channel管理器，负责向其他Broker发送请求&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;kafkaScheduler&lt;/strong&gt;：定时调度器&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;eventManager&lt;/strong&gt;：Controller事件管理器，负责管理事件处理线程。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;replicaStateMachine&lt;/strong&gt;：副本状态机，负责副本状态转换。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;partitionStateMachine&lt;/strong&gt;：分区状态机，负责分区状态转换。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;topicDeletionManager&lt;/strong&gt;：主题删除管理器，负责删除主题及日志。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; controllerContext &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ControllerContext&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; controllerChannelManager &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ControllerChannelManager&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;=&amp;gt;&lt;/span&gt; controllerContext&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;epoch&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  config&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  time&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  metrics&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  stateChangeLogger&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  threadNamePrefix  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// have a separate scheduler for the controller to be able to start and stop independently of the kafka server  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// visible for testing  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;controller&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; kafkaScheduler &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;KafkaScheduler&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// visible for testing  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;controller&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; eventManager &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ControllerEventManager&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;config&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;brokerId&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; time&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  controllerContext&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;stats&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rateAndTimeMetrics&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; brokerRequestBatch &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ControllerBrokerRequestBatch&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;config&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; controllerChannelManager&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  eventManager&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; controllerContext&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; stateChangeLogger&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; replicaStateMachine&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;ReplicaStateMachine&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ZkReplicaStateMachine&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;config&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; stateChangeLogger&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; controllerContext&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; zkClient&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ControllerBrokerRequestBatch&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;config&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; controllerChannelManager&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; eventManager&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; controllerContext&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; stateChangeLogger&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; partitionStateMachine&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;PartitionStateMachine&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ZkPartitionStateMachine&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;config&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; stateChangeLogger&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; controllerContext&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; zkClient&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ControllerBrokerRequestBatch&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;config&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; controllerChannelManager&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; eventManager&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; controllerContext&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; stateChangeLogger&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; topicDeletionManager &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;TopicDeletionManager&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;config&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; controllerContext&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; replicaStateMachine&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  partitionStateMachine&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ControllerDeletionClient&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; zkClient&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;2-metadata管理&#34;&gt;2. metadata管理&lt;/h1&gt;&#xA;&lt;p&gt;通过kafka.controller.ControllerContext可以看到集群的所有metadata信息，核心字段如下：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kafka源码分析(七) - 事务设计</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-source-code-7-transaction-design/</link>
      <pubDate>Sat, 05 Apr 2025 11:25:13 +0800</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-source-code-7-transaction-design/</guid>
      <description>&lt;h1 id=&#34;1-intro&#34;&gt;1. Intro&lt;/h1&gt;&#xA;&lt;p&gt;Kafka事务主要适用于以下两种场景：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;multi-produce场景：Producer需要将多批次消息进行原子性提交。&lt;/li&gt;&#xA;&lt;li&gt;consume-transform-produce场景：消费上游数据后，经过处理，生产下游数据。该场景实现可以参考&lt;code&gt;kafka.examples.ExactlyOnceMessageProcessor&lt;/code&gt;，事务可以保证消费和生产的原子性。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20250402110429.png&#34; alt=&#34;consume-transform-produce场景&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;consume-transform-produce场景案例：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;run&lt;/span&gt;() {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; retries &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; processedRecords &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; remainingRecords &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Long.&lt;span style=&#34;color:#a6e22e&#34;&gt;MAX_VALUE&lt;/span&gt;;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// it is recommended to have a relatively short txn timeout in order to clear pending offsets faster  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; transactionTimeoutMs &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 10_000;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// consumer must be in read_committed mode, which means it won&amp;#39;t be able to read uncommitted data  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; readCommitted &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; (KafkaProducer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Integer, String&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; producer &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Producer(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;processor-producer&amp;#34;&lt;/span&gt;, bootstrapServers, outputTopic,  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;, transactionalId, &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;1, transactionTimeoutMs, &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;createKafkaProducer&lt;/span&gt;();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         KafkaConsumer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Integer, String&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; consumer &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Consumer(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;processor-consumer&amp;#34;&lt;/span&gt;, bootstrapServers, inputTopic,  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;processor-group&amp;#34;&lt;/span&gt;, Optional.&lt;span style=&#34;color:#a6e22e&#34;&gt;of&lt;/span&gt;(groupInstanceId), readCommitted, &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;1, &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;createKafkaConsumer&lt;/span&gt;()) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// called first and once to fence zombies and abort any pending transaction  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        producer.&lt;span style=&#34;color:#a6e22e&#34;&gt;initTransactions&lt;/span&gt;();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        consumer.&lt;span style=&#34;color:#a6e22e&#34;&gt;subscribe&lt;/span&gt;(singleton(inputTopic), &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Utils.&lt;span style=&#34;color:#a6e22e&#34;&gt;printOut&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Processing new records&amp;#34;&lt;/span&gt;);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;closed &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; remainingRecords &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; 0) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                ConsumerRecords&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Integer, String&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; records &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; consumer.&lt;span style=&#34;color:#a6e22e&#34;&gt;poll&lt;/span&gt;(ofMillis(200));  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;records.&lt;span style=&#34;color:#a6e22e&#34;&gt;isEmpty&lt;/span&gt;()) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#75715e&#34;&gt;// begin a new transaction session  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    producer.&lt;span style=&#34;color:#a6e22e&#34;&gt;beginTransaction&lt;/span&gt;();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (ConsumerRecord&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Integer, String&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; record : records) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#75715e&#34;&gt;// process the record and send downstream  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        ProducerRecord&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Integer, String&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; newRecord &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ProducerRecord&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt;(outputTopic, record.&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt;(), record.&lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-ok&amp;#34;&lt;/span&gt;);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        producer.&lt;span style=&#34;color:#a6e22e&#34;&gt;send&lt;/span&gt;(newRecord);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#75715e&#34;&gt;// checkpoint the progress by sending offsets to group coordinator broker  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#75715e&#34;&gt;// note that this API is only available for broker &amp;gt;= 2.5                    &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;            producer.&lt;span style=&#34;color:#a6e22e&#34;&gt;sendOffsetsToTransaction&lt;/span&gt;(getOffsetsToCommit(consumer), consumer.&lt;span style=&#34;color:#a6e22e&#34;&gt;groupMetadata&lt;/span&gt;());  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#75715e&#34;&gt;// commit the transaction including offsets  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    producer.&lt;span style=&#34;color:#a6e22e&#34;&gt;commitTransaction&lt;/span&gt;();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    processedRecords &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; records.&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    retries &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (AuthorizationException &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; UnsupportedVersionException &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; ProducerFencedException  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; FencedInstanceIdException &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; OutOfOrderSequenceException &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; SerializationException e) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;// we can&amp;#39;t recover from these exceptions  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                Utils.&lt;span style=&#34;color:#a6e22e&#34;&gt;printErr&lt;/span&gt;(e.&lt;span style=&#34;color:#a6e22e&#34;&gt;getMessage&lt;/span&gt;());  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                shutdown();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (OffsetOutOfRangeException &lt;span style=&#34;color:#f92672&#34;&gt;|&lt;/span&gt; NoOffsetForPartitionException e) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;// invalid or no offset found without auto.reset.policy  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                Utils.&lt;span style=&#34;color:#a6e22e&#34;&gt;printOut&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Invalid or no offset found, using latest&amp;#34;&lt;/span&gt;);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                consumer.&lt;span style=&#34;color:#a6e22e&#34;&gt;seekToEnd&lt;/span&gt;(emptyList());  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                consumer.&lt;span style=&#34;color:#a6e22e&#34;&gt;commitSync&lt;/span&gt;();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                retries &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (KafkaException e) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;// abort the transaction  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                Utils.&lt;span style=&#34;color:#a6e22e&#34;&gt;printOut&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Aborting transaction: %s&amp;#34;&lt;/span&gt;, e.&lt;span style=&#34;color:#a6e22e&#34;&gt;getMessage&lt;/span&gt;());  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                producer.&lt;span style=&#34;color:#a6e22e&#34;&gt;abortTransaction&lt;/span&gt;();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                retries &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; maybeRetry(retries, consumer);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            remainingRecords &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; getRemainingRecords(consumer);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (remainingRecords &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; Long.&lt;span style=&#34;color:#a6e22e&#34;&gt;MAX_VALUE&lt;/span&gt;) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                Utils.&lt;span style=&#34;color:#a6e22e&#34;&gt;printOut&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Remaining records: %d&amp;#34;&lt;/span&gt;, remainingRecords);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (Throwable e) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Utils.&lt;span style=&#34;color:#a6e22e&#34;&gt;printErr&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Unhandled exception&amp;#34;&lt;/span&gt;);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        e.&lt;span style=&#34;color:#a6e22e&#34;&gt;printStackTrace&lt;/span&gt;();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Utils.&lt;span style=&#34;color:#a6e22e&#34;&gt;printOut&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Processed %d records&amp;#34;&lt;/span&gt;, processedRecords);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    shutdown();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;11-客户端配置项&#34;&gt;1.1. 客户端配置项&lt;/h2&gt;&#xA;&lt;p&gt;Producer配置项：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kafka源码分析(六) - 网络通信模块设计</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-source-code-6-network-model/</link>
      <pubDate>Sun, 02 Mar 2025 18:10:12 +0800</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-source-code-6-network-model/</guid>
      <description>&lt;h1 id=&#34;intro&#34;&gt;Intro&lt;/h1&gt;&#xA;&lt;p&gt;Kafka的网络通信设计如图所示（图片引用自&lt;a href=&#34;https://www.automq.com/blog/understand-kafka-network-communication-and-thread-model&#34;&gt;AutoMQ&lt;/a&gt;）：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20250319145048.png&#34; alt=&#34;image.png&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;其中&lt;strong&gt;SocketServer&lt;/strong&gt;负责处理外部连接，并将处理结果封装到Response返回。&lt;strong&gt;KafkaRequestHandlerPool&lt;/strong&gt;作为I/O处理线程池，执行请求的具体逻辑。二者之间通过RequestChannel进行交互。&lt;/p&gt;&#xA;&lt;h1 id=&#34;socketserver&#34;&gt;SocketServer&lt;/h1&gt;&#xA;&lt;p&gt;SocketServer负责处理各个Broker之间的通信channel，采用Reactor处理模型，Acceptor负责从socket接受request，Handler负责处理接收来的request，这也是Kafka中的设计亮点之一。&lt;/p&gt;&#xA;&lt;p&gt;在实现上，分为data-plane和control-plane，防止数据类请求阻塞控制类请求：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// data-plane  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;network&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; dataPlaneAcceptors &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ConcurrentHashMap&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;EndPoint&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;DataPlaneAcceptor&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]()&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; dataPlaneRequestChannel &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;RequestChannel&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;maxQueuedRequests&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DataPlaneAcceptor&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;MetricPrefix&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; time&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; apiVersionManager&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;newRequestMetrics&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// control-plane  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;network&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; controlPlaneAcceptorOpt&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Option&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;ControlPlaneAcceptor&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;None&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; controlPlaneRequestChannelOpt&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Option&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;RequestChannel&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; config&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;controlPlaneListenerName&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;map&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;=&amp;gt;&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;RequestChannel&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ControlPlaneAcceptor&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;MetricPrefix&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; time&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; apiVersionManager&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;newRequestMetrics&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;network&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; processors &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ArrayBuffer&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;Processor&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从上述定义可以看出control-plane的线程数只有一个，这是因为控制类的请求数量较数据类请求少。&lt;/p&gt;&#xA;&lt;p&gt;初始化逻辑如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; createDataPlaneAcceptorAndProcessors&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;endpoint&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;EndPoint&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Unit&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; synchronized &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;stopped&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;RuntimeException&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Can&amp;#39;t create new data plane acceptor and processors: SocketServer is stopped.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; parsedConfigs &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; config&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;valuesFromThisConfigWithPrefixOverride&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;endpoint&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;listenerName&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;configPrefix&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  connectionQuotas&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;addListener&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;config&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; endpoint&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;listenerName&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; isPrivilegedListener &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; controlPlaneRequestChannelOpt&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;isEmpty &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    config&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;interBrokerListenerName &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; endpoint&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;listenerName  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; dataPlaneAcceptor &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; createDataPlaneAcceptor&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;endpoint&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; isPrivilegedListener&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; dataPlaneRequestChannel&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  config&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;addReconfigurable&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;dataPlaneAcceptor&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  dataPlaneAcceptor&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;configure&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;parsedConfigs&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  dataPlaneAcceptors&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;put&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;endpoint&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; dataPlaneAcceptor&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  info&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;s&amp;#34;Created data-plane acceptor and processors for endpoint : &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;endpoint&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;listenerName&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; createControlPlaneAcceptorAndProcessor&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;endpoint&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;EndPoint&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Unit&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; synchronized &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;stopped&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;RuntimeException&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Can&amp;#39;t create new control plane acceptor and processor: SocketServer is stopped.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  connectionQuotas&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;addListener&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;config&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; endpoint&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;listenerName&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; controlPlaneAcceptor &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; createControlPlaneAcceptor&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;endpoint&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; controlPlaneRequestChannelOpt&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;get&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  controlPlaneAcceptor&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;addProcessors&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  controlPlaneAcceptorOpt &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Some&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;controlPlaneAcceptor&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  info&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;s&amp;#34;Created control-plane acceptor and processor for endpoint : &lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;endpoint&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;listenerName&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;acceptor&#34;&gt;Acceptor&lt;/h2&gt;&#xA;&lt;p&gt;Acceptor线程通过Selector + Channel轮询获取acceptable connection，将接收的连接信息传递给下游Processor处理，作为Runnable任务，每个endpoint指定一个acceptor。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kafka源码分析(五) - 索引细节</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-source-code-5-index-details/</link>
      <pubDate>Sat, 15 Feb 2025 10:30:12 +0800</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-source-code-5-index-details/</guid>
      <description>&lt;h1 id=&#34;intro&#34;&gt;Intro&lt;/h1&gt;&#xA;&lt;p&gt;LogSegment日志对象管理以下三种Index：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;位移索引文件(.index)&lt;/li&gt;&#xA;&lt;li&gt;时间戳索引文件(.timeindex)&lt;/li&gt;&#xA;&lt;li&gt;已中止事物的索引文件(.txnindex)&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; LazyIndex&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;OffsetIndex&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; lazyOffsetIndex;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; LazyIndex&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;TimeIndex&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; lazyTimeIndex;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; TransactionIndex txnIndex;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;abstractindex&#34;&gt;AbstractIndex&lt;/h1&gt;&#xA;&lt;p&gt;AbstractIndex作为索引中的顶层抽象接口，封装索引结构中一些通用的属性和处理逻辑：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; ReentrantLock lock &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ReentrantLock();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//当前文件的开始offset  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; baseOffset;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//最大索引大小  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; maxIndexSize;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//是否可写  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; writable;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//映射索引文件  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;volatile&lt;/span&gt; File file;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 索引文件长度  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;volatile&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; length;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//mmap 内存映射buffer  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;volatile&lt;/span&gt; MappedByteBuffer mmap;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//最大索引entry数量  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;volatile&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; maxEntries;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//索引entry数量  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;volatile&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; entries;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;抽象方法：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/**  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * Do a basic sanity check on this index to detect obvious problems * &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @throws CorruptIndexException if any problems are found  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sanityCheck&lt;/span&gt;();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/**  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * Remove all entries from the index which have an offset greater than or equal to the given offset. &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * Truncating to an offset larger than the largest in the index has no effect. */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;truncateTo&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; offset);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/**  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * Remove all the entries from the index. &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;truncate&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//不同entry大小&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;entrySize&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/**  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * To parse an entry in the index. * &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @param buffer the buffer of this memory mapped index.  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @param n the slot  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @return the index entry stored in the given slot.  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; IndexEntry &lt;span style=&#34;color:#a6e22e&#34;&gt;parseEntry&lt;/span&gt;(ByteBuffer buffer, &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; n);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;初始化逻辑&#34;&gt;初始化逻辑&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;AbstractIndex&lt;/span&gt;(File file, &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; baseOffset, &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; maxIndexSize, &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; writable) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; IOException {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Objects.&lt;span style=&#34;color:#a6e22e&#34;&gt;requireNonNull&lt;/span&gt;(file);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;file&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; file;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;baseOffset&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; baseOffset;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;maxIndexSize&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; maxIndexSize;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;writable&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; writable;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    createAndAssignMmap();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;maxEntries&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; mmap.&lt;span style=&#34;color:#a6e22e&#34;&gt;limit&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; entrySize();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;entries&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; mmap.&lt;span style=&#34;color:#a6e22e&#34;&gt;position&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; entrySize();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;createAndAssignMmap方法会初始化file和mmap对象，实际加载index文件使用mmap方式，将内核buffer映射到用户buffer，减少了内存拷贝的开销，这也是Kafka较为重要的优化点之一：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kafka源码分析(四) - 日志读写流程</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-source-code-4-log-rw/</link>
      <pubDate>Mon, 10 Feb 2025 12:51:12 +0800</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-source-code-4-log-rw/</guid>
      <description>&lt;h1 id=&#34;intro&#34;&gt;Intro&lt;/h1&gt;&#xA;&lt;p&gt;上文介绍了Kafka日志加载的基本流程，本文主要分析Kafka日志的读写流程。&lt;/p&gt;&#xA;&lt;p&gt;日志写入的场景主要有以下几种：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;生产者向Leader replica写入消息（包含事务消息）&lt;/li&gt;&#xA;&lt;li&gt;Follow replica拉取消息并写入&lt;/li&gt;&#xA;&lt;li&gt;消费者组写入组信息&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h1 id=&#34;日志写入&#34;&gt;日志写入&lt;/h1&gt;&#xA;&lt;p&gt;从KafkaApis入口类中可以看到produce的处理动作：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ApiKeys&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;PRODUCE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;=&amp;gt;&lt;/span&gt; handleProduceRequest&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;request&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; requestLocal&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里重点关注日志的写入逻辑，handleProduceRequest()中会调用replicaManager执行append：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// call the replica manager to append messages to the replicas  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;replicaManager&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;handleProduceAppend&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  timeout &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; produceRequest&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;timeout&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;toLong&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  requiredAcks &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; produceRequest&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;acks&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  internalTopicsAllowed &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; internalTopicsAllowed&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  transactionalId &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; produceRequest&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;transactionalId&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  entriesPerPartition &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; authorizedRequestInfo&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  responseCallback &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; sendResponseCallback&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  recordValidationStatsCallback &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; processingStatsCallback&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  requestLocal &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; requestLocal&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  transactionSupportedOperation &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; transactionSupportedOperation&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;appendrecords&#34;&gt;appendRecords&lt;/h2&gt;&#xA;&lt;p&gt;在ReplicaManager中会调用appendRecords()将其追加到消息对应partition的leader replica中，并且等待leader将其同步到其他replica中。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/**  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * Handles the produce request by starting any transactional verification before appending. * * @param timeout                       maximum time we will wait to append before returning  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @param requiredAcks                  number of replicas who must acknowledge the append before sending the response  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @param internalTopicsAllowed         boolean indicating whether internal topics can be appended to  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @param transactionalId               the transactional ID for the produce request or null if there is none.  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @param entriesPerPartition           the records per partition to be appended  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @param responseCallback              callback for sending the response  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @param recordValidationStatsCallback callback for updating stats on record conversions  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @param requestLocal                  container for the stateful instances scoped to this request -- this must correspond to the  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; *                                      thread calling this method * @param actionQueue                   the action queue to use. ReplicaManager#defaultActionQueue is used by default.  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @param transactionSupportedOperation determines the supported Operation based on the client&amp;#39;s Request api version  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * * The responseCallback is wrapped so that it is scheduled on a request handler thread. There, it should be called with * that request handler thread&amp;#39;s thread local and not the one supplied to this method. */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; handleProduceAppend&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;timeout&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Long&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        requiredAcks&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Short&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        internalTopicsAllowed&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Boolean&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        transactionalId&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;String&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        entriesPerPartition&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Map&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;TopicPartition&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;MemoryRecords&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;],&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        responseCallback&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Map&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;TopicPartition&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;PartitionResponse&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Unit&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        recordValidationStatsCallback&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Map&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;TopicPartition&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;RecordValidationStats&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Unit&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(),&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        requestLocal&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;RequestLocal&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;RequestLocal&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;NoCaching&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        actionQueue&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;ActionQueue&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;defaultActionQueue&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        transactionSupportedOperation&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;TransactionSupportedOperation&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Unit&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;appendRecords&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;  timeout &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; timeout&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;  requiredAcks &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; requiredAcks&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;  internalTopicsAllowed &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; internalTopicsAllowed&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;  origin &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;AppendOrigin&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;CLIENT&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;  entriesPerPartition &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; entriesWithoutErrorsPerPartition&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;  responseCallback &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; newResponseCallback&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;  recordValidationStatsCallback &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; recordValidationStatsCallback&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;  requestLocal &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; newRequestLocal&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;  actionQueue &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; actionQueue&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;  verificationGuards &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; verificationGuards  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;传入的参数较多，重要参数的含义如下：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kafka源码分析(三) - 日志加载流程</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-source-code-3-log-startup/</link>
      <pubDate>Tue, 04 Feb 2025 17:51:13 +0800</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-source-code-3-log-startup/</guid>
      <description>&lt;p&gt;Kafka Log由多个LogSegment构成，每个LogSegment对应一个分区，每个LogSegment对象都会在磁盘中创建一组文件：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;日志消息文件(.log)&lt;/li&gt;&#xA;&lt;li&gt;位移索引文件(.index)&lt;/li&gt;&#xA;&lt;li&gt;时间戳索引文件(.timeindex)&lt;/li&gt;&#xA;&lt;li&gt;已中止十五的索引文件(.txnindex)&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;logmanager&#34;&gt;LogManager&lt;/h2&gt;&#xA;&lt;p&gt;LogManager作为Kafka Log管理的入口点，负责日志创建、检索、清理，所有的读写操作都会委托给对应的日志实例。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; currentLogs &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Pool&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;TopicPartition&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;UnifiedLog&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_liveLogDirs&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;ConcurrentLinkedQueue&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;File&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; createAndValidateLogDirs&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;logDirs&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; initialOfflineDirs&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;currentLogs字段是用于存储分区和UnifiedLog映射的map结构，Pool内部使用ConcurrentHashMap作为存储。&lt;/p&gt;&#xA;&lt;p&gt;liveLogDirs用于存储log路径下所有有效的File对象，存储结构使用ConcurrentLinkedQueue。createAndValidateLogDirs()方法用来检查并追加有效路径到队列中。&lt;/p&gt;&#xA;&lt;h3 id=&#34;startup启动流程&#34;&gt;startup启动流程&lt;/h3&gt;&#xA;&lt;p&gt;KafkaServer的startup()方法中会调用logManager的startup()方法，用来加载所有的日志。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;logManager&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;startup&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;zkClient&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;getAllTopicsInCluster&lt;span style=&#34;color:#f92672&#34;&gt;())&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;startup的第一个参数是topic名称集合，第二个可选参数isStray通过metadata计算当前UnifiedLog是否需要当前broker加载（kafka.log.LogManager.isStrayKraftReplica）&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/**  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; *  Start the background threads to flush logs and do log cleanup */&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; startup&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;topicNames&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Set&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;String&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;],&lt;/span&gt; isStray&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;UnifiedLog&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Boolean&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Unit&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// ensure consistency between default config and overrides  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;val&lt;/span&gt; defaultConfig &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; currentDefaultConfig  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  startupWithConfigOverrides&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;defaultConfig&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; fetchTopicConfigOverrides&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;defaultConfig&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; topicNames&lt;span style=&#34;color:#f92672&#34;&gt;),&lt;/span&gt; isStray&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;s&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;fetchTopicConfigOverrides()方法用于检查topic是否存在自定义配置并覆盖。接下来看startupWithConfigOverrides()的具体实现。&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;调用loadLogs()加载所有log&lt;/li&gt;&#xA;&lt;li&gt;启动以下定时调度任务：&#xA;&lt;ol&gt;&#xA;&lt;li&gt;日志清理任务&lt;/li&gt;&#xA;&lt;li&gt;日志刷盘任务&lt;/li&gt;&#xA;&lt;li&gt;日志checkpoint更新任务&lt;/li&gt;&#xA;&lt;li&gt;log start offset属性checkpoint更新任务&lt;/li&gt;&#xA;&lt;li&gt;日志删除任务&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;检查&lt;code&gt;log.cleaner.enable&lt;/code&gt;参数，true则配置LogCleaner&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;scheduler定时调度&#34;&gt;scheduler定时调度&lt;/h3&gt;&#xA;&lt;p&gt;scheduler定时调度使用内部封装的&lt;code&gt;org.apache.kafka.server.util.KafkaScheduler&lt;/code&gt;，它是对ScheduledThreadPoolExecutor的简单封装。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;log&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; startupWithConfigOverrides&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  defaultConfig&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;LogConfig&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  topicConfigOverrides&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Map&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;String&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;LogConfig&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;],&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  isStray&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;UnifiedLog&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Boolean&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;Unit&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  loadLogs&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;defaultConfig&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; topicConfigOverrides&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; isStray&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// this could take a while if shutdown was not clean  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;/* Schedule the cleanup task to delete old logs */&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;scheduler &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    info&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Starting log cleanup with a period of %d ms.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;format&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;retentionCheckMs&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    scheduler&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;schedule&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kafka-log-retention&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;=&amp;gt;&lt;/span&gt; cleanupLogs&lt;span style=&#34;color:#f92672&#34;&gt;(),&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       initialTaskDelayMs&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       retentionCheckMs&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    info&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Starting log flusher with a default period of %d ms.&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;format&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;flushCheckMs&lt;span style=&#34;color:#f92672&#34;&gt;))&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    scheduler&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;schedule&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kafka-log-flusher&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;=&amp;gt;&lt;/span&gt; flushDirtyLogs&lt;span style=&#34;color:#f92672&#34;&gt;(),&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       initialTaskDelayMs&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       flushCheckMs&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    scheduler&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;schedule&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kafka-recovery-point-checkpoint&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;=&amp;gt;&lt;/span&gt; checkpointLogRecoveryOffsets&lt;span style=&#34;color:#f92672&#34;&gt;(),&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       initialTaskDelayMs&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       flushRecoveryOffsetCheckpointMs&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    scheduler&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;schedule&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kafka-log-start-offset-checkpoint&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       &lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;=&amp;gt;&lt;/span&gt; checkpointLogStartOffsets&lt;span style=&#34;color:#f92672&#34;&gt;(),&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       initialTaskDelayMs&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       flushStartOffsetCheckpointMs&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    scheduler&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;scheduleOnce&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kafka-delete-logs&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// will be rescheduled after each delete logs with a dynamic period  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;                       &lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;=&amp;gt;&lt;/span&gt; deleteLogs&lt;span style=&#34;color:#f92672&#34;&gt;(),&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                       initialTaskDelayMs&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;cleanerConfig&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;enableCleaner&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;_cleaner&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;LogCleaner&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;cleanerConfig&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; liveLogDirs&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; currentLogs&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; logDirFailureChannel&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; time &lt;span style=&#34;color:#66d9ef&#34;&gt;=&lt;/span&gt; time&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;_cleaner&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;startup&lt;span style=&#34;color:#f92672&#34;&gt;()&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;loadlogs流程&#34;&gt;loadLogs流程&lt;/h3&gt;&#xA;&lt;p&gt;loadLogs()方法作为实际加载Log数据的入口，逻辑链路较长，首先看下方法中使用到的类属性：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kafka源码分析(二)- Consumer消费逻辑</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-source-code-2-consumer/</link>
      <pubDate>Sat, 18 Jan 2025 15:51:13 +0800</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-source-code-2-consumer/</guid>
      <description>&lt;h2 id=&#34;consumer&#34;&gt;Consumer&lt;/h2&gt;&#xA;&lt;p&gt;Consumer作为Kafka Clients中的消费者，继承关系如下图所示：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/AsyncKafkaConsumer.png&#34; alt=&#34;AsyncKafkaConsumer.png&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;KafkaConsumer作为Facade类，提供API供clients使用，而ConsumerDelegate作为实现类接口，提供了两种实现方式，通过配置&lt;code&gt;group.protocol&lt;/code&gt;进行控制，其中ClassicKafkaConsumer所有的线程都会处理网络IO请求，AsyncKafkaConsumer则是基于Reactor模式，使用单独线程处理网络IO，以事件驱动模式处理任务，具体细节见 &lt;a href=&#34;https://cwiki.apache.org/confluence/display/KAFKA/Consumer+threading+refactor+design&#34;&gt;Consumer threading refactor design&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;p&gt;本次分析也以AsyncKafkaConsumer为例。&lt;/p&gt;&#xA;&lt;p&gt;KafkaConsumer内置的成员变量如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//用于创建delegate的工厂类  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; ConsumerDelegateCreator CREATOR &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ConsumerDelegateCreator();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//consumer具体的实现类  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; ConsumerDelegate&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K, V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; delegate;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;初始化方法：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;KafkaConsumer(ConsumerConfig config, Deserializer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; keyDeserializer, Deserializer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; valueDeserializer) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    delegate &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; CREATOR.&lt;span style=&#34;color:#a6e22e&#34;&gt;create&lt;/span&gt;(config, keyDeserializer, valueDeserializer);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K, V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; ConsumerDelegate&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K, V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;create&lt;/span&gt;(ConsumerConfig config,  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                            Deserializer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; keyDeserializer,  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                            Deserializer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; valueDeserializer) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//根据配置选取对应的实现类&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        GroupProtocol groupProtocol &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; GroupProtocol.&lt;span style=&#34;color:#a6e22e&#34;&gt;valueOf&lt;/span&gt;(config.&lt;span style=&#34;color:#a6e22e&#34;&gt;getString&lt;/span&gt;(ConsumerConfig.&lt;span style=&#34;color:#a6e22e&#34;&gt;GROUP_PROTOCOL_CONFIG&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;toUpperCase&lt;/span&gt;(Locale.&lt;span style=&#34;color:#a6e22e&#34;&gt;ROOT&lt;/span&gt;));  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (groupProtocol &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; GroupProtocol.&lt;span style=&#34;color:#a6e22e&#34;&gt;CONSUMER&lt;/span&gt;)  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; AsyncKafkaConsumer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt;(config, keyDeserializer, valueDeserializer);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ClassicKafkaConsumer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt;(config, keyDeserializer, valueDeserializer);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (KafkaException e) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; e;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (Throwable t) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; KafkaException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Failed to construct Kafka consumer&amp;#34;&lt;/span&gt;, t);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;事件处理逻辑&#34;&gt;事件处理逻辑&lt;/h3&gt;&#xA;&lt;p&gt;AsyncKafkaConsumer的核心使用事件驱动模式来处理各类事件，具体事件类型见org.apache.kafka.clients.consumer.internals.events.ApplicationEvent&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kafka源码分析(一)- Producer生产逻辑</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-source-code-1-producer/</link>
      <pubDate>Sun, 05 Jan 2025 21:47:13 +0800</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka-source-code-1-producer/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;clients模块是Kafka官方提供的默认Java客户端，该模块分为三部分：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Admin：提供了管理topic、partition、config的相关API&lt;/li&gt;&#xA;&lt;li&gt;Consumer：提供了消费topic的API&lt;/li&gt;&#xA;&lt;li&gt;Producer：提供了向topic投递消息的功能&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;源码以Kafka 3.9为例。&lt;/p&gt;&#xA;&lt;h2 id=&#34;producer&#34;&gt;Producer&lt;/h2&gt;&#xA;&lt;p&gt;Producer作为Kafka client中的消息生产者，提供send()方法用于写入消息，并有后台sender线程定时发送消息。&lt;/p&gt;&#xA;&lt;h3 id=&#34;send流程&#34;&gt;send流程&lt;/h3&gt;&#xA;&lt;p&gt;核心send方法提供了以下两种异步方式：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/**  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * See {@link KafkaProducer#send(ProducerRecord)}  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; */&lt;/span&gt;Future&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;RecordMetadata&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;send&lt;/span&gt;(ProducerRecord&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K, V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; record);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/**  支持回调方法&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * See {@link KafkaProducer#send(ProducerRecord, Callback)}  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; */&lt;/span&gt;Future&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;RecordMetadata&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;send&lt;/span&gt;(ProducerRecord&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K, V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; record, Callback callback);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;interceptor机制&#34;&gt;interceptor机制&lt;/h4&gt;&#xA;&lt;p&gt;send流程中首先会检查用户是否自定义interceptor实现，用于处理send前置逻辑，具体业务场景不多赘述。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Future&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;RecordMetadata&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;send&lt;/span&gt;(ProducerRecord&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K, V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; record, Callback callback) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 拦截器前置send动作  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ProducerRecord&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K, V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; interceptedRecord &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;interceptors&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onSend&lt;/span&gt;(record);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; doSend(interceptedRecord, callback);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中ProducerInterceptor提供了以下接口：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;ProducerRecord&amp;lt;K, V&amp;gt; onSend(ProducerRecord&amp;lt;K, V&amp;gt; record)：send前置处理逻辑&lt;/li&gt;&#xA;&lt;li&gt;onAcknowledgement(RecordMetadata metadata, Exception exception)：消息被应答之后或发送消息失败时调用。&lt;/li&gt;&#xA;&lt;li&gt;close()：用于关闭interceptor资源。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;自定义interceptor需要考虑线程安全。&lt;/p&gt;&#xA;&lt;h4 id=&#34;dosend流程&#34;&gt;doSend流程&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Future&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;RecordMetadata&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doSend&lt;/span&gt;(ProducerRecord&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K, V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; record, Callback callback) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 1.1 创建callback对象  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    AppendCallbacks appendCallbacks &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; AppendCallbacks(callback, &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;interceptors&lt;/span&gt;, record);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//1.2 检查producer是否被close  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        throwIfProducerClosed();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// first make sure the metadata for the topic is available  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; nowMs &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; time.&lt;span style=&#34;color:#a6e22e&#34;&gt;milliseconds&lt;/span&gt;();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ClusterAndWaitTime clusterAndWaitTime;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//1.3 拉取指定topic、分区的元数据，和等待时间  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            clusterAndWaitTime &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; waitOnMetadata(record.&lt;span style=&#34;color:#a6e22e&#34;&gt;topic&lt;/span&gt;(), record.&lt;span style=&#34;color:#a6e22e&#34;&gt;partition&lt;/span&gt;(), nowMs, maxBlockTimeMs);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (KafkaException e) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (metadata.&lt;span style=&#34;color:#a6e22e&#34;&gt;isClosed&lt;/span&gt;())  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; KafkaException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Producer closed while send in progress&amp;#34;&lt;/span&gt;, e);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; e;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        nowMs &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; clusterAndWaitTime.&lt;span style=&#34;color:#a6e22e&#34;&gt;waitedOnMetadataMs&lt;/span&gt;;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; remainingWaitMs &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Math.&lt;span style=&#34;color:#a6e22e&#34;&gt;max&lt;/span&gt;(0, maxBlockTimeMs &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; clusterAndWaitTime.&lt;span style=&#34;color:#a6e22e&#34;&gt;waitedOnMetadataMs&lt;/span&gt;);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Cluster cluster &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; clusterAndWaitTime.&lt;span style=&#34;color:#a6e22e&#34;&gt;cluster&lt;/span&gt;;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//1.4 key value进行序列化  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; serializedKey;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            serializedKey &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; keySerializer.&lt;span style=&#34;color:#a6e22e&#34;&gt;serialize&lt;/span&gt;(record.&lt;span style=&#34;color:#a6e22e&#34;&gt;topic&lt;/span&gt;(), record.&lt;span style=&#34;color:#a6e22e&#34;&gt;headers&lt;/span&gt;(), record.&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt;());  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (ClassCastException cce) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; SerializationException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Can&amp;#39;t convert key of class &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; record.&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;getClass&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;getName&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; to class &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; producerConfig.&lt;span style=&#34;color:#a6e22e&#34;&gt;getClass&lt;/span&gt;(ProducerConfig.&lt;span style=&#34;color:#a6e22e&#34;&gt;KEY_SERIALIZER_CLASS_CONFIG&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;getName&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; specified in key.serializer&amp;#34;&lt;/span&gt;, cce);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; serializedValue;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            serializedValue &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; valueSerializer.&lt;span style=&#34;color:#a6e22e&#34;&gt;serialize&lt;/span&gt;(record.&lt;span style=&#34;color:#a6e22e&#34;&gt;topic&lt;/span&gt;(), record.&lt;span style=&#34;color:#a6e22e&#34;&gt;headers&lt;/span&gt;(), record.&lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;());  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (ClassCastException cce) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; SerializationException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Can&amp;#39;t convert value of class &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; record.&lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;getClass&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;getName&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; to class &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; producerConfig.&lt;span style=&#34;color:#a6e22e&#34;&gt;getClass&lt;/span&gt;(ProducerConfig.&lt;span style=&#34;color:#a6e22e&#34;&gt;VALUE_SERIALIZER_CLASS_CONFIG&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;getName&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; specified in value.serializer&amp;#34;&lt;/span&gt;, cce);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 1.5 计算当前消息所属的partition  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; partition &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; partition(record, serializedKey, serializedValue, cluster);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 1.6 设置消息header为readOnly  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        setReadOnly(record.&lt;span style=&#34;color:#a6e22e&#34;&gt;headers&lt;/span&gt;());  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Header&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; headers &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; record.&lt;span style=&#34;color:#a6e22e&#34;&gt;headers&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;toArray&lt;/span&gt;();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//1.7 检查消息大小是否符合  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; serializedSize &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; AbstractRecords.&lt;span style=&#34;color:#a6e22e&#34;&gt;estimateSizeInBytesUpperBound&lt;/span&gt;(apiVersions.&lt;span style=&#34;color:#a6e22e&#34;&gt;maxUsableProduceMagic&lt;/span&gt;(),  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                compression.&lt;span style=&#34;color:#a6e22e&#34;&gt;type&lt;/span&gt;(), serializedKey, serializedValue, headers);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ensureValidRecordSize(serializedSize);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; timestamp &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; record.&lt;span style=&#34;color:#a6e22e&#34;&gt;timestamp&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; nowMs : record.&lt;span style=&#34;color:#a6e22e&#34;&gt;timestamp&lt;/span&gt;();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 自定义partitioner  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; abortOnNewBatch &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; partitioner &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 1.8 将消息追加到accumulator中  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        RecordAccumulator.&lt;span style=&#34;color:#a6e22e&#34;&gt;RecordAppendResult&lt;/span&gt; result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; accumulator.&lt;span style=&#34;color:#a6e22e&#34;&gt;append&lt;/span&gt;(record.&lt;span style=&#34;color:#a6e22e&#34;&gt;topic&lt;/span&gt;(), partition, timestamp, serializedKey,  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                serializedValue, headers, appendCallbacks, remainingWaitMs, abortOnNewBatch, nowMs, cluster);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;assert&lt;/span&gt; appendCallbacks.&lt;span style=&#34;color:#a6e22e&#34;&gt;getPartition&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; RecordMetadata.&lt;span style=&#34;color:#a6e22e&#34;&gt;UNKNOWN_PARTITION&lt;/span&gt;;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 1.9 消息入新batch的情况  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (result.&lt;span style=&#34;color:#a6e22e&#34;&gt;abortForNewBatch&lt;/span&gt;) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; prevPartition &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; partition;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            onNewBatch(record.&lt;span style=&#34;color:#a6e22e&#34;&gt;topic&lt;/span&gt;(), cluster, prevPartition);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            partition &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; partition(record, serializedKey, serializedValue, cluster);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (log.&lt;span style=&#34;color:#a6e22e&#34;&gt;isTraceEnabled&lt;/span&gt;()) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                log.&lt;span style=&#34;color:#a6e22e&#34;&gt;trace&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Retrying append due to new batch creation for topic {} partition {}. The old partition was {}&amp;#34;&lt;/span&gt;, record.&lt;span style=&#34;color:#a6e22e&#34;&gt;topic&lt;/span&gt;(), partition, prevPartition);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; accumulator.&lt;span style=&#34;color:#a6e22e&#34;&gt;append&lt;/span&gt;(record.&lt;span style=&#34;color:#a6e22e&#34;&gt;topic&lt;/span&gt;(), partition, timestamp, serializedKey,  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                serializedValue, headers, appendCallbacks, remainingWaitMs, &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;, nowMs, cluster);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 2.1 开启事务的情况  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (transactionManager &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            transactionManager.&lt;span style=&#34;color:#a6e22e&#34;&gt;maybeAddPartition&lt;/span&gt;(appendCallbacks.&lt;span style=&#34;color:#a6e22e&#34;&gt;topicPartition&lt;/span&gt;());  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 2.2 如果batch满了，或者新batch被创建，唤醒后台sender线程  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (result.&lt;span style=&#34;color:#a6e22e&#34;&gt;batchIsFull&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; result.&lt;span style=&#34;color:#a6e22e&#34;&gt;newBatchCreated&lt;/span&gt;) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            log.&lt;span style=&#34;color:#a6e22e&#34;&gt;trace&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Waking up the sender since topic {} partition {} is either full or getting a new batch&amp;#34;&lt;/span&gt;, record.&lt;span style=&#34;color:#a6e22e&#34;&gt;topic&lt;/span&gt;(), appendCallbacks.&lt;span style=&#34;color:#a6e22e&#34;&gt;getPartition&lt;/span&gt;());  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;sender&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;wakeup&lt;/span&gt;();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; result.&lt;span style=&#34;color:#a6e22e&#34;&gt;future&lt;/span&gt;;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// handling exceptions and record the errors;  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// for API exceptions return them in the future,        // for other exceptions throw directly    } catch (ApiException e) {  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        log.&lt;span style=&#34;color:#a6e22e&#34;&gt;debug&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Exception occurred during message send:&amp;#34;&lt;/span&gt;, e);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (callback &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            TopicPartition tp &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; appendCallbacks.&lt;span style=&#34;color:#a6e22e&#34;&gt;topicPartition&lt;/span&gt;();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            RecordMetadata nullMetadata &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; RecordMetadata(tp, &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;1, &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;1, RecordBatch.&lt;span style=&#34;color:#a6e22e&#34;&gt;NO_TIMESTAMP&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;1, &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;1);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            callback.&lt;span style=&#34;color:#a6e22e&#34;&gt;onCompletion&lt;/span&gt;(nullMetadata, e);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;errors&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;record&lt;/span&gt;();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;interceptors&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onSendError&lt;/span&gt;(record, appendCallbacks.&lt;span style=&#34;color:#a6e22e&#34;&gt;topicPartition&lt;/span&gt;(), e);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (transactionManager &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            transactionManager.&lt;span style=&#34;color:#a6e22e&#34;&gt;maybeTransitionToErrorState&lt;/span&gt;(e);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; FutureFailure(e);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (InterruptedException e) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;errors&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;record&lt;/span&gt;();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;interceptors&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onSendError&lt;/span&gt;(record, appendCallbacks.&lt;span style=&#34;color:#a6e22e&#34;&gt;topicPartition&lt;/span&gt;(), e);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; InterruptException(e);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (KafkaException e) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;errors&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;record&lt;/span&gt;();  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;interceptors&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onSendError&lt;/span&gt;(record, appendCallbacks.&lt;span style=&#34;color:#a6e22e&#34;&gt;topicPartition&lt;/span&gt;(), e);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; e;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (Exception e) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// we notify interceptor about all exceptions, since onSend is called before anything else in this method  &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;interceptors&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;onSendError&lt;/span&gt;(record, appendCallbacks.&lt;span style=&#34;color:#a6e22e&#34;&gt;topicPartition&lt;/span&gt;(), e);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; e;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;partition机制&#34;&gt;partition机制&lt;/h4&gt;&#xA;&lt;p&gt;Producer中计算消息partition的流程较为简单：&lt;/p&gt;</description>
    </item>
    <item>
      <title>读《中国官僚政治研究》</title>
      <link>http://localhost:1313/posts/%E9%9A%8F%E7%AC%94/%E4%B8%AD%E5%9B%BD%E5%AE%98%E5%83%9A%E6%94%BF%E6%B2%BB%E7%A0%94%E7%A9%B6/</link>
      <pubDate>Wed, 01 Jan 2025 23:14:50 +0800</pubDate>
      <guid>http://localhost:1313/posts/%E9%9A%8F%E7%AC%94/%E4%B8%AD%E5%9B%BD%E5%AE%98%E5%83%9A%E6%94%BF%E6%B2%BB%E7%A0%94%E7%A9%B6/</guid>
      <description>&lt;p&gt;该书作者王亚南老师是建国初期著名的经济学家，曾翻译《资本论》、《国富论》等著名的经济学著作。本书从经济角度切入，剖析了中国秦代至民国的官僚政治的形成、发展演变。指出官僚政治的专制性质是导致中国社会长期停滞的主要原因。&lt;/p&gt;&#xA;&lt;p&gt;他在书中多次指出：决定社会形态的是经济，换而言之，经济基础决定中国封建社会性质。&lt;/p&gt;&#xA;&lt;p&gt;书中着重提出统治阶级想要巩固自己的统治地位，需要做到以下两点：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;控制社会基本的生产资料（物质生产手段：土地）&lt;/li&gt;&#xA;&lt;li&gt;控制精神生产手段（思想、意识形态）&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;统治阶级通过将官僚政治与儒家思想结合，控制上述两类资料，从而达成统治中国政治文化两千多年。因此历朝历代的变革，大都围绕以上两点进行：物质生产手段的田制税法改革、精神生产手段的科举制。&lt;/p&gt;&#xA;&lt;p&gt;书中的一些重要观点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;知识的垄断推动了官僚阶层固化。&lt;/li&gt;&#xA;&lt;li&gt;两税制和科举制是推动官僚政治高度发展的两个重要因素。&lt;/li&gt;&#xA;&lt;li&gt;每个新王朝最初几代君主官僚为了收买人心、增加生产，还能保持一些戒慎恐惧的精神，等到经济高度发展后，官场腐败现象不期而然地发生。&lt;/li&gt;&#xA;&lt;li&gt;中国农民具备极强的忍耐性，这是由宗法社会组织、伦理教义、以及一再再生产出来的那种同形态的统治方式，把他们教育、锻炼出来的。&lt;/li&gt;&#xA;&lt;li&gt;战争的集权模式，促进了官僚政治体制的发展。&lt;/li&gt;&#xA;&lt;li&gt;官僚政治通过政治特权，在一定名义下管制人民、以达成权势者自私自利的目的。&lt;/li&gt;&#xA;&lt;li&gt;如何摆脱官僚政治&#xA;&lt;ol&gt;&#xA;&lt;li&gt;人民自觉参与并主导政治革新运动&lt;/li&gt;&#xA;&lt;li&gt;民主手段革新官僚政治&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;值得注意的是，作者作为马克思主义经济学家，在书中多次对于苏联的预测，都与事实大相径庭。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Spark入门</title>
      <link>http://localhost:1313/posts/big-data/spark-start/</link>
      <pubDate>Tue, 12 Nov 2024 15:37:52 +0800</pubDate>
      <guid>http://localhost:1313/posts/big-data/spark-start/</guid>
      <description>&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;&#xA;&lt;p&gt;Apache Spark是一个分布式计算系统，具备以下特点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;使用RDD(Resilient Distributed Datasets)，提供了比MapReduce更为丰富的模型&lt;/li&gt;&#xA;&lt;li&gt;基于内存计算，性能比MapReduce模型高&lt;/li&gt;&#xA;&lt;li&gt;集成离线计算、实时计算、机器学习、图计算等模块&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;核心模块：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Spark Core：提供Spark核心功能，是SQL、Streaming等模块实现的基础。&lt;/li&gt;&#xA;&lt;li&gt;Spark SQL：提供SQL进行数据查询的组件&lt;/li&gt;&#xA;&lt;li&gt;Spark Streaming：提供流式计算的组件&lt;/li&gt;&#xA;&lt;li&gt;MLlib：Spark平台的机器学习算法库&lt;/li&gt;&#xA;&lt;li&gt;GraphX：面向图计算的组件&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Spark名词解释：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;&lt;strong&gt;名称&lt;/strong&gt;&lt;/th&gt;&#xA;          &lt;th&gt;&lt;strong&gt;含义&lt;/strong&gt;&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Application&lt;/td&gt;&#xA;          &lt;td&gt;指用户提交的 Spark 应用程序&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Job&lt;/td&gt;&#xA;          &lt;td&gt;指 Spark 作业，是 Application 的子集，由行动算子（action）触发&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Stage&lt;/td&gt;&#xA;          &lt;td&gt;指 Spark 阶段，是 Job 的子集，以 RDD 的宽依赖为界&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Task&lt;/td&gt;&#xA;          &lt;td&gt;指 Spark 任务，是 Stage 的子集，Spark 中最基本的任务执行单元，对应单个线程，会被封装成 TaskDescription 对象提交到 Executor 的线程池中执行&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Driver&lt;/td&gt;&#xA;          &lt;td&gt;运行用户程序&lt;code&gt;main()&lt;/code&gt;方法并创建SparkContext的实例&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Cluster Manager&lt;/td&gt;&#xA;          &lt;td&gt;集群管理器，例如Yarn、Mesos、Kubernetes等&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20240729135117.png&#34; alt=&#34;image.png&#34;&gt;&lt;/td&gt;&#xA;          &lt;td&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;Spark运行过程：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Driver执行用户程序的main方法，并创建SparkContext，与Cluster Manager建立连接。&lt;/li&gt;&#xA;&lt;li&gt;Cluster Manager为用户程序分配计算资源，返回可使用的Executor列表。&lt;/li&gt;&#xA;&lt;li&gt;获取Executor资源后，Spark会将用户程序代码以及依赖包，发送给Executor&lt;/li&gt;&#xA;&lt;li&gt;SparkContext发送task到Executor，由executor执行计算任务。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;demo&#34;&gt;Demo&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.spark&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spark-core_2.12&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.1.2&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;provided&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.apache.spark.SparkConf;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.apache.spark.api.java.JavaPairRDD;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.apache.spark.api.java.JavaRDD;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; org.apache.spark.api.java.JavaSparkContext;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; scala.Tuple2;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; java.util.Arrays;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;WordCountDemo&lt;/span&gt; {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;wordCount&lt;/span&gt;(String fileName) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        SparkConf sparkConf &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; SparkConf().&lt;span style=&#34;color:#a6e22e&#34;&gt;setMaster&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;local&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;setAppName&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JD Word Counter&amp;#34;&lt;/span&gt;);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        JavaSparkContext sparkContext &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; JavaSparkContext(sparkConf);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        JavaRDD&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;String&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; inputFile &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; sparkContext.&lt;span style=&#34;color:#a6e22e&#34;&gt;textFile&lt;/span&gt;(fileName);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        JavaRDD&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;String&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; wordsFromFile &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; inputFile.&lt;span style=&#34;color:#a6e22e&#34;&gt;flatMap&lt;/span&gt;(content &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Arrays.&lt;span style=&#34;color:#a6e22e&#34;&gt;asList&lt;/span&gt;(content.&lt;span style=&#34;color:#a6e22e&#34;&gt;split&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;)).&lt;span style=&#34;color:#a6e22e&#34;&gt;iterator&lt;/span&gt;());  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        JavaPairRDD countData &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; wordsFromFile.&lt;span style=&#34;color:#a6e22e&#34;&gt;mapToPair&lt;/span&gt;(t &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Tuple2(t, 1)).&lt;span style=&#34;color:#a6e22e&#34;&gt;reduceByKey&lt;/span&gt;((x, y) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) x &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) y);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        countData.&lt;span style=&#34;color:#a6e22e&#34;&gt;saveAsTextFile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CountData&amp;#34;&lt;/span&gt;);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;(String&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; args) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (args.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; 0) {  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;No files provided.&amp;#34;&lt;/span&gt;);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            System.&lt;span style=&#34;color:#a6e22e&#34;&gt;exit&lt;/span&gt;(0);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        wordCount(args&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;);  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;提交应用：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Flink入门</title>
      <link>http://localhost:1313/posts/big-data/flink-start/</link>
      <pubDate>Fri, 11 Oct 2024 21:37:41 +0800</pubDate>
      <guid>http://localhost:1313/posts/big-data/flink-start/</guid>
      <description>&lt;h1 id=&#34;简介&#34;&gt;简介&lt;/h1&gt;&#xA;&lt;p&gt;Apache Flink是一个用于有状态的并行数据流的分布式计算系统，同时支持流式处理和批量处理。&lt;/p&gt;&#xA;&lt;p&gt;实际数据分析应用都是面向无限数据流，三类通常使用有状态流处理实现的应用程序：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;事件驱动应用程序：使用特定的业务逻辑来提取事件流并处理事件。&#xA;&lt;ol&gt;&#xA;&lt;li&gt;实时推荐、行为模式检测、异常检测&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;数据管道应用程序：将数据从A组件复制到B组件的ETL流程，pipeline包括多个源（source）和接收器（sink）。&#xA;3. 实时数据仓库：数据实时清洗、归并、结构化&lt;/li&gt;&#xA;&lt;li&gt;数据流式分析应用程序：连续地提取事件流数据，并计算出最新结果并存储，用于查询。&#xA;&lt;ol&gt;&#xA;&lt;li&gt;用户行为等实时数据分析&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;常见的流式处理框架对比：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;&lt;/th&gt;&#xA;          &lt;th&gt;Flink&lt;/th&gt;&#xA;          &lt;th&gt;Spark Streaming&lt;/th&gt;&#xA;          &lt;th&gt;Apache Storm&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;架构&lt;/td&gt;&#xA;          &lt;td&gt;主从模式&lt;/td&gt;&#xA;          &lt;td&gt;主从模式，依赖Spark，每个Batch处理都依赖主节点&lt;/td&gt;&#xA;          &lt;td&gt;主从模式，依赖ZK&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;处理方式&lt;/td&gt;&#xA;          &lt;td&gt;Native&lt;/td&gt;&#xA;          &lt;td&gt;Micro-Batch&lt;/td&gt;&#xA;          &lt;td&gt;Native&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;容错&lt;/td&gt;&#xA;          &lt;td&gt;基于Chandy-Lamport distributed snapshots checkpoint机制&lt;/td&gt;&#xA;          &lt;td&gt;WAL与RDD机制&lt;/td&gt;&#xA;          &lt;td&gt;Record&amp;rsquo;s ACK&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;处理模式&lt;/td&gt;&#xA;          &lt;td&gt;单条事件处理、时间窗口划分的所有事件&lt;/td&gt;&#xA;          &lt;td&gt;时间窗口内的所有时间&lt;/td&gt;&#xA;          &lt;td&gt;单条事件处理&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;数据保证&lt;/td&gt;&#xA;          &lt;td&gt;exactly once&lt;/td&gt;&#xA;          &lt;td&gt;exactly once&lt;/td&gt;&#xA;          &lt;td&gt;at least once&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;API支持&lt;/td&gt;&#xA;          &lt;td&gt;high&lt;/td&gt;&#xA;          &lt;td&gt;high&lt;/td&gt;&#xA;          &lt;td&gt;low&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;社区活跃度&lt;/td&gt;&#xA;          &lt;td&gt;high&lt;/td&gt;&#xA;          &lt;td&gt;high&lt;/td&gt;&#xA;          &lt;td&gt;medium&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;部署性&lt;/td&gt;&#xA;          &lt;td&gt;部署简单，仅依赖JRE&lt;/td&gt;&#xA;          &lt;td&gt;部署简单，仅依赖JRE&lt;/td&gt;&#xA;          &lt;td&gt;依赖JRE和Zookeeper&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;Flink优点：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;毫秒级延迟&lt;/li&gt;&#xA;&lt;li&gt;统一数据处理组件栈，可以处理不同类型的数据需求&lt;/li&gt;&#xA;&lt;li&gt;支持事件时间、接入时间、处理时间等概念&lt;/li&gt;&#xA;&lt;li&gt;基于轻量级分布式快照实现的容错&lt;/li&gt;&#xA;&lt;li&gt;支持有状态计算，灵活的state-backend（HDFS、内存、RocksDB）&lt;/li&gt;&#xA;&lt;li&gt;满足Exactly-once需求&lt;/li&gt;&#xA;&lt;li&gt;支持高度灵活的window操作&lt;/li&gt;&#xA;&lt;li&gt;带反压的连续流模型&lt;/li&gt;&#xA;&lt;li&gt;每秒千万级吞吐量&lt;/li&gt;&#xA;&lt;li&gt;易用性：提供了SQL、Table API、Stream API等方式&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;流式计算的时间窗口，涉及处理时间和事件时间，主要有以下区别：&lt;/p&gt;</description>
    </item>
    <item>
      <title>JVM内存问题排查流程</title>
      <link>http://localhost:1313/posts/jvm/jvm%E5%86%85%E5%AD%98%E9%97%AE%E9%A2%98%E6%8E%92%E6%9F%A5%E6%B5%81%E7%A8%8B/</link>
      <pubDate>Sun, 03 Mar 2024 21:34:49 +0000</pubDate>
      <guid>http://localhost:1313/posts/jvm/jvm%E5%86%85%E5%AD%98%E9%97%AE%E9%A2%98%E6%8E%92%E6%9F%A5%E6%B5%81%E7%A8%8B/</guid>
      <description>&lt;h2 id=&#34;确认问题现象&#34;&gt;确认问题现象&lt;/h2&gt;&#xA;&lt;p&gt;可以通过服务状态，监控面板、日志信息、监控工具（VisualVM）等，确认问题类型：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;内存使用率居高不下、内存缓慢增加、OOM等&lt;/li&gt;&#xA;&lt;li&gt;频繁GC：Full GC等&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;发现问题不建议重启，留存状态。&lt;/p&gt;&#xA;&lt;h2 id=&#34;保留数据&#34;&gt;保留数据&lt;/h2&gt;&#xA;&lt;h3 id=&#34;heapdump文件&#34;&gt;heapdump文件&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#arthas导出方式&#xA;heapdump /tmp/dump.hprof&#xA;&#xA;#jmap命令保存整个Java堆&#xA;jmap -dump:format=b,file=heap.bin &amp;lt;pid&amp;gt; &#xA;&#xA;#jmap命令只保存Java堆中的存活对象, 包含live选项，会在堆转储前执行一次Full GC&#xA;jmap -dump:live,format=b,file=heap.bin &amp;lt;pid&amp;gt;&#xA;&#xA;#jcmd命令保存整个Java堆,Jdk1.7后有效&#xA;jcmd &amp;lt;pid&amp;gt; GC.heap_dump filename=heap.bin&#xA;&#xA;#在出现OutOfMemoryError的时候JVM自动生成（推荐）节点剩余内存不足heapdump会生成失败&#xA;-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heap.bin&#xA;&#xA;#编程的方式生成&#xA;使用HotSpotDiagnosticMXBean.dumpHeap()方法&#xA;&#xA;#在出现Full GC前后JVM自动生成，本地快速调试可用&#xA;-XX:+HeapDumpBeforeFullGC或 -XX:+HeapDumpAfterFullGC&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;JVM参数：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;-XX:printGCDetails -XX:+UseConcMarkSweepGC -XX:+HeapDumpOnOutOfMemoryError &#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;gc日志&#34;&gt;GC日志&lt;/h3&gt;&#xA;&lt;p&gt;JVM启动参数如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# Java8及以下&#xA;-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:&amp;lt;path&amp;gt;&#xA;&#xA;# Java9及以上&#xA;-Xlog:gc*:&amp;lt;path&amp;gt;:time&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;可以通过EasyGC进行日志分析。&lt;/p&gt;&#xA;&lt;h3 id=&#34;服务日志&#34;&gt;服务日志&lt;/h3&gt;&#xA;&lt;p&gt;通常由日志组件（Promtail &amp;amp; loki）进行采集、存储、展示。&lt;/p&gt;&#xA;&lt;h2 id=&#34;实际问题&#34;&gt;实际问题&lt;/h2&gt;&#xA;&lt;h3 id=&#34;堆内存溢出&#34;&gt;堆内存溢出&lt;/h3&gt;&#xA;&lt;p&gt;问题现象：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;OutOfMemoryError&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;直接内存溢出&#34;&gt;直接内存溢出&lt;/h3&gt;&#xA;&lt;p&gt;问题现象：top指令中相关Java进程占用的RES超过了-Xmx的大小，并且内存占用不断上升。&lt;/p&gt;&#xA;&lt;p&gt;问题定位方法：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;可通过开启NMT（&lt;strong&gt;-XX:NativeMemoryTracking=detail&lt;/strong&gt;）定位问题&lt;/li&gt;&#xA;&lt;li&gt;jcmd查看直接内存情况：jcmd pid VM.native_memory detail&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;NIO、Netty等常用直接内存，Netty可以通过&lt;code&gt;-Dio.netty.leakDetectionLevel&lt;/code&gt;开启&lt;/p&gt;&#xA;&lt;h3 id=&#34;栈空间溢出&#34;&gt;栈空间溢出&lt;/h3&gt;&#xA;&lt;p&gt;问题现象：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;StackOverflow&lt;/li&gt;&#xA;&lt;li&gt;OutOfMemoryError：unable to create new native thread&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;问题定位方法：&lt;/p&gt;</description>
    </item>
    <item>
      <title>《软件研发效能之美》思维导图</title>
      <link>http://localhost:1313/posts/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%BD%AF%E4%BB%B6%E7%A0%94%E5%8F%91%E6%95%88%E8%83%BD%E4%B9%8B%E7%BE%8E%E6%80%9D%E7%BB%B4%E5%AF%BC%E5%9B%BE/</link>
      <pubDate>Sun, 14 Jan 2024 21:40:59 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%BD%AF%E4%BB%B6%E7%A0%94%E5%8F%91%E6%95%88%E8%83%BD%E4%B9%8B%E7%BE%8E%E6%80%9D%E7%BB%B4%E5%AF%BC%E5%9B%BE/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/%E8%BD%AF%E4%BB%B6%E7%A0%94%E5%8F%91%E6%95%88%E8%83%BD%E6%8F%90%E5%8D%87%E4%B9%8B%E7%BE%8E.png&#34; alt=&#34;软件研发效能提升之美-思维导图&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>OSDI&#39;10 《Finding a needle in Haystack Facebook’s photo storage》</title>
      <link>http://localhost:1313/posts/paper-reading/finding-a-needle-in-haystack-facebooks-photo-storage/</link>
      <pubDate>Fri, 08 Dec 2023 22:57:50 +0000</pubDate>
      <guid>http://localhost:1313/posts/paper-reading/finding-a-needle-in-haystack-facebooks-photo-storage/</guid>
      <description>&lt;h2 id=&#34;业务量级&#34;&gt;业务量级&lt;/h2&gt;&#xA;&lt;p&gt;FaceBook存储超过2600亿张图片，20PB，一周存储10亿张，峰值每秒100W图片。一次性写、不修改、很少删除的图片数据。&lt;/p&gt;&#xA;&lt;h2 id=&#34;原始设计的挑战&#34;&gt;原始设计的挑战&lt;/h2&gt;&#xA;&lt;p&gt;访问webserver，获取图片URL，先去CDN获取，cache hit则返回，miss则去Storage加载到CDN再返回。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/image-20231125152100170.png&#34; alt=&#34;Typical Design&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;当文件存储NAS的文件夹存储数千个文件时，请求单个图片的请求会产生多于10次的磁盘IO，即使文件夹内文件数量下降到几百时，还是会产生三次磁盘IO。&lt;/p&gt;&#xA;&lt;p&gt;可以看出，原始架构的性能瓶颈：读操作存在多次磁盘IO。&lt;/p&gt;&#xA;&lt;p&gt;传统POSIX filesystem缺点：文件元信息，例如权限等信息占用较多存储成本。对于巨量数据的情况，成本极大，对于NAS，一个文件读写需要三次磁盘IO：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;根据filename获取inode number&lt;/li&gt;&#xA;&lt;li&gt;读取指定inode&lt;/li&gt;&#xA;&lt;li&gt;读取文件信息本身&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;设计目标&#34;&gt;设计目标&lt;/h2&gt;&#xA;&lt;p&gt;Haystack结构实现的四个目标：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;高吞吐量与低延迟：所有metadata都存储在内存，最多执行一次磁盘IO&lt;/li&gt;&#xA;&lt;li&gt;容错：异地容灾&lt;/li&gt;&#xA;&lt;li&gt;低成本&lt;/li&gt;&#xA;&lt;li&gt;简单&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;新设计&#34;&gt;新设计&lt;/h2&gt;&#xA;&lt;p&gt;Haystack主要解决上述架构的瓶颈问题：多次磁盘IO，关键方法：将多个图片存储为单个大文件，由此仅需要保存大文件的文件元信息。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/image-20231125190839452.png&#34; alt=&#34;Haystack架构&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Haystack架构包括以下三部分：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Haystack Store：真正存储文件的组件，管理文件系统元信息。使用物理volume进行管理，可以将不同主机上的某些物理volume组成一个逻辑volume，这样就可以产生多份副本，进行容错或分流。&lt;/li&gt;&#xA;&lt;li&gt;Haystack Directory：管理逻辑到物理volume的映射关系，以及一些应用元信息，例如图片到逻辑volume的映射，逻辑volume的空闲空间等信息。&lt;/li&gt;&#xA;&lt;li&gt;Haystack Cache：内部缓存CDN，减少对外部CDN的依赖。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;浏览器从Haystack Directory组件获取到的URL如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;http://〈CDN〉/〈Cache〉/〈Machine id〉/〈Logical volume, Photo〉&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;CDN，Haystack Cache层如果hit cache就返回，否则去掉该层地址，请求转发到下一层。&lt;/p&gt;&#xA;&lt;h3 id=&#34;haystack-directory&#34;&gt;Haystack Directory&lt;/h3&gt;&#xA;&lt;p&gt;四个功能：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;逻辑volume到物理volume的映射。&lt;/li&gt;&#xA;&lt;li&gt;跨逻辑卷读写的负载均衡能力。&lt;/li&gt;&#xA;&lt;li&gt;决定一个请求是由CDN处理还是Cache处理。&lt;/li&gt;&#xA;&lt;li&gt;检查逻辑卷是否因为操作原因或达到存储容量导致read-only&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;haystack-cache&#34;&gt;Haystack Cache&lt;/h3&gt;&#xA;&lt;p&gt;从浏览器或CDN接收HTTP请求。该组件使用图片id定位数据，将其组织成了分布式hash table，如果cache miss，则去Haystack Store服务器获取图片信息。&lt;/p&gt;&#xA;&lt;p&gt;对图片进行cache的两个必要条件：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;请求直接来自浏览器而非CDN&lt;/li&gt;&#xA;&lt;li&gt;图片从可写服务器获取的&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;haystack-store&#34;&gt;Haystack Store&lt;/h3&gt;&#xA;&lt;p&gt;每台存储服务器都维护了多个逻辑volume，每个volume都可以理解为一个大文件（100 GB ），文件名为/hay/haystack_&amp;lt;volume_id&amp;gt;，可以通过逻辑volume id和图片offset快速定位到图片信息，可以不通过磁盘IO读取图片（&lt;strong&gt;Q：为什么能不通过磁盘操作读取到磁盘数据？&lt;/strong&gt;），服务器都在内存中维护着物理卷对应文件描述符和图片id到文件系统元信息的映射关系&lt;/p&gt;&#xA;&lt;p&gt;具体的物理结构如下图所示：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/image-20231205220244979.png&#34; alt=&#34;Haystack-Store&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;每台存储服务器代表着一个物理卷，同时也称为superblock，其中包括多个needle，每个needle存储着图片元信息和图片数据。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/image-20231205222508419.png&#34; alt=&#34;fields-explanation&#34;&gt;&lt;/p&gt;&#xA;&lt;h4 id=&#34;read&#34;&gt;Read&lt;/h4&gt;&#xA;&lt;p&gt;来自Cache服务器的读请求会有以下参数：逻辑volume id、key、alternate key、cookie，Store服务器首先从内存中查找对应元信息，然后读取图片数据，使用checksum进行校验后返回。&lt;/p&gt;&#xA;&lt;h4 id=&#34;write&#34;&gt;Write&lt;/h4&gt;&#xA;&lt;p&gt;写请求会包括以下参数：逻辑volume id、key、alternate key、cookie、data，Store服务器将数据组装成needle结构并追加到volume file中。如果(key, alternate key)唯一二元组存在重复问题，有两种情况：&lt;/p&gt;</description>
    </item>
    <item>
      <title>述职报告要点小记</title>
      <link>http://localhost:1313/posts/%E9%9A%8F%E7%AC%94/%E8%BF%B0%E8%81%8C%E6%8A%A5%E5%91%8A%E8%A6%81%E7%82%B9%E5%B0%8F%E8%AE%B0/</link>
      <pubDate>Sun, 07 May 2023 20:32:25 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E9%9A%8F%E7%AC%94/%E8%BF%B0%E8%81%8C%E6%8A%A5%E5%91%8A%E8%A6%81%E7%82%B9%E5%B0%8F%E8%AE%B0/</guid>
      <description>&lt;h2 id=&#34;述职目的&#34;&gt;述职目的&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;企业：掌握员工的具体工作情况与表现。&lt;/li&gt;&#xA;&lt;li&gt;个人：对自己的阶段性总结、反思、阶段规划&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;文档结构&#34;&gt;文档结构&lt;/h2&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/bg.jpg&#34; alt=&#34;述职文档结构（摘自：阿里开发者）&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;概述&#34;&gt;概述&lt;/h3&gt;&#xA;&lt;p&gt;核心：用一分钟总结一下自己这段时间&lt;strong&gt;干了些什么&lt;/strong&gt;，让大家对你有个总体的认知。&lt;strong&gt;业务结果&lt;/strong&gt;有两个重点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;归因：业务结果与个人的关系&lt;/li&gt;&#xA;&lt;li&gt;增量：业务价值有一定的增量部分&lt;/li&gt;&#xA;&lt;li&gt;技术结果：个人的技术能力&#xA;&lt;ol&gt;&#xA;&lt;li&gt;不要造轮子&lt;/li&gt;&#xA;&lt;li&gt;带来变化：新项目、代码重构、性能优化、技术先进性、效率提升等&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;工作总结重点&#34;&gt;工作总结（重点）&lt;/h3&gt;&#xA;&lt;h4 id=&#34;业务背景&#34;&gt;业务背景&lt;/h4&gt;&#xA;&lt;p&gt;核心：&lt;strong&gt;搞清楚why&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;方法论：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;靠谱的PD，会把why说清楚&lt;/li&gt;&#xA;&lt;li&gt;不靠谱的PD，需要自己去调研清楚，调研方案：&#xA;&lt;ol&gt;&#xA;&lt;li&gt;扩大自己的领域知识&lt;/li&gt;&#xA;&lt;li&gt;请教专家&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;解题思考&#34;&gt;解题思考&lt;/h4&gt;&#xA;&lt;p&gt;需要盘清楚现有的资源情况（人力、机器、资金、组织等），然后给出最合适的解决方案，这个过程就是&lt;strong&gt;解题思考&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;h4 id=&#34;目标制定&#34;&gt;目标制定&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;环境决定决策：业务目标由业务增长率决定&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;技术目标：&lt;strong&gt;技术目标是围绕着业务在当前的阶段或形态来设定的&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;技术方案&#34;&gt;技术方案&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;面向未来的架构设计&lt;/strong&gt;：着眼眼前，根据眼前的情况定一个合适的目标，设计系统要面向未来&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;怎么画系统架构图（四部分）&lt;/strong&gt;：系统和外部的边界、内部组件的上下左右关系、系统的非功能性设计、面向未来的设计&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;面向未来的设计：起码看到未来三年的发展形态，抽象总结业务表层问题，把本质抽象成领域模型的概念。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;落地再次贴近现实：架构设计完成后，到具体的落地环节，做出时序图、流程图等，最好能做到后面可以直接编码的程度，后续的多次迭代其实就是对原始的图不断完善和扩展。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;技术深度：某个领域，通过长时间的沉淀积累，总结出一套在该领域下的技术方案。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;结果说明&#34;&gt;结果说明&lt;/h4&gt;&#xA;&lt;p&gt;具体的数据、计算公式等，技术结果可以把核心模块、扩展性、性能等方面例举出来&lt;/p&gt;&#xA;&lt;h4 id=&#34;总结反思&#34;&gt;总结反思&lt;/h4&gt;&#xA;&lt;p&gt;总结出做得好的和做的不好的地方。&lt;/p&gt;&#xA;&lt;h3 id=&#34;个人成长团队贡献&#34;&gt;个人成长&amp;amp;团队贡献&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;可迁移的个人能力：复杂系统架构设计能力、结构化思考能力、组织协调能力、项目管理能力、团队管理能力、沟通能力、演讲能力、数据洞察能力&lt;/li&gt;&#xA;&lt;li&gt;团队贡献：本质还是个人成长，需要把你的成长输出给团队成员。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;财年规划&#34;&gt;财年规划&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;一块业务的下一年的规划&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;难点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;业务定位&lt;/li&gt;&#xA;&lt;li&gt;衡量指标&lt;/li&gt;&#xA;&lt;li&gt;核心业务&amp;amp;技术问题，解决方案&lt;/li&gt;&#xA;&lt;li&gt;竞品分析&lt;/li&gt;&#xA;&lt;li&gt;资源组织最大化&lt;/li&gt;&#xA;&lt;li&gt;风险分析&lt;/li&gt;&#xA;&lt;li&gt;…………&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;reference&#34;&gt;Reference&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://mp.weixin.qq.com/s?__biz=MzIzOTU0NTQ0MA==&amp;amp;mid=2247532301&amp;amp;idx=1&amp;amp;sn=23481d31aed34389bb8c28a5e5db6be5&amp;amp;chksm=e92a4202de5dcb1424bf2378fa83742ce47afd9b670e2f4950593cc8aac0d0d5f5d7c750c564&amp;amp;scene=178&amp;amp;cur_album_id=1427971693057998849#rd&#34;&gt;来自一线技术人的经验分享｜如何写出让人眼前一亮的述职报告&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>《十次经济危机》学习笔记</title>
      <link>http://localhost:1313/posts/%E7%BB%8F%E6%B5%8E/%E5%8D%81%E6%AC%A1%E7%BB%8F%E6%B5%8E%E5%8D%B1%E6%9C%BA%E7%AC%94%E8%AE%B0/</link>
      <pubDate>Sat, 29 Apr 2023 13:39:13 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E7%BB%8F%E6%B5%8E/%E5%8D%81%E6%AC%A1%E7%BB%8F%E6%B5%8E%E5%8D%B1%E6%9C%BA%E7%AC%94%E8%AE%B0/</guid>
      <description>&lt;h2 id=&#34;概述&#34;&gt;概述&lt;/h2&gt;&#xA;&lt;p&gt;本课程分析了中国从1949-2018的十次经济危机。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;理性分析专业知识，无任何意识形态掺杂在内。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;背景和问题&#34;&gt;背景和问题&lt;/h3&gt;&#xA;&lt;p&gt;二战后超级大国地缘政治的不确定性以及冷战特点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;战后双寡头地缘政治重构派生两个&lt;strong&gt;雁阵式重工产业转移&lt;/strong&gt;：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;USA完成了对西欧日韩的控制（马歇尔计划）&#xA;&lt;ul&gt;&#xA;&lt;li&gt;朝鲜战争导致日本得到美国约150亿美元投资再实现工业化&lt;/li&gt;&#xA;&lt;li&gt;中国得到苏联约50亿美元投资用于国家工业化&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;USSR完成对东欧的控制，但受阻于中国维护原住民暴力革命夺取的国家主权&#xA;&lt;ul&gt;&#xA;&lt;li&gt;中国土改利于新政权战胜最初的危机但不利于工业化：分散小农户经济70%在山区不可能使用工业化产品；资本不断增密的重工业无法提取原始积累&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;strong&gt;现代化&lt;/strong&gt;：资本和风险向城市集中的过程，周期性爆发危机，是一个阶段性过程。&lt;/p&gt;&#xA;&lt;p&gt;美国最严重经济波动发生于一战和二战时期。&lt;/p&gt;&#xA;&lt;p&gt;中国严重波动发生于西方主导的冷战时期，伴随着意识形态偏差的庸俗化传播。&lt;/p&gt;&#xA;&lt;p&gt;土地革命完成了：动员全民参加经济建设，土改提供的农产品打赢了城市私人资本引导的&lt;strong&gt;白色大战&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;工业化：&lt;strong&gt;资本增密、排斥劳动力&lt;/strong&gt;的过程。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;1950-1960：第一次外资因苏联1967年援助投资终止而引发60-62和68-70两次债务/赤字/危机。&lt;/li&gt;&#xA;&lt;li&gt;1971-1980：第二次外资引进西方设备，造成74-76和79-81两次外债/赤字/危机。&lt;/li&gt;&#xA;&lt;li&gt;1980-1990：第三次外资（改革开放）造成88-89和93-94两次恶性通胀经济危机。&lt;/li&gt;&#xA;&lt;li&gt;1990-now：第四次外资，带来98-99输入性通缩演化为第一次生产过剩，08-09输入型通胀，2015受西方债务危机影响发生第二次生产过剩&#xA;&lt;ul&gt;&#xA;&lt;li&gt;产业资本危机-&amp;gt;金融资本危机&lt;/li&gt;&#xA;&lt;li&gt;三大差距逐渐拉大：沿海和内地的区域差别、城市和乡村的收入差别、贫富差距&lt;/li&gt;&#xA;&lt;li&gt;政府通过倾斜投资来缓解差距，基础设施建设、农村五通，促进经济发展。&lt;/li&gt;&#xA;&lt;li&gt;国债投资基础设施建设存在的三个问题&#xA;&lt;ul&gt;&#xA;&lt;li&gt;贷款被国有企业占有，既不产生税收，也不产生回报，对私人企业有挤出效应，资本主义国家也无法避免。&lt;/li&gt;&#xA;&lt;li&gt;短期生产过剩通过投资解决，无法根治，导致长期产生。&lt;/li&gt;&#xA;&lt;li&gt;金融资本流动性减缓，导致金融资本不断扩张，导致金融资本过剩&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;2020之后产业资本、商业资本、金融资本全部过剩&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;中国的金字塔形双稳态经济/社会结构：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;经济结构&#xA;&lt;ul&gt;&#xA;&lt;li&gt;地方主要掌握&lt;strong&gt;实质资产&lt;/strong&gt;500万亿，&lt;strong&gt;土地&lt;/strong&gt;随基建投资升值到150万亿。&lt;/li&gt;&#xA;&lt;li&gt;中央主要掌握&lt;strong&gt;金融资产&lt;/strong&gt;180万亿（可扩张）&lt;/li&gt;&#xA;&lt;li&gt;无限负责政府&lt;strong&gt;债务资产&lt;/strong&gt;约40万亿（可扩张）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;社会结构&#xA;&lt;ul&gt;&#xA;&lt;li&gt;地方面对分散小资60%（农民住宅拥有率约为100%）&lt;/li&gt;&#xA;&lt;li&gt;地方面对新崛起中资30-40%，约为5亿人&lt;/li&gt;&#xA;&lt;li&gt;中央掌握政治化大资约10%&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;就业形势：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;劳动力总量8亿，每年增加0.1亿&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;农村劳动力5亿：农业需要0.5亿、乡镇企业吸纳1亿、进城打工2.2亿、仍有1亿以上需要非农就业。&lt;/li&gt;&#xA;&lt;li&gt;越多劳动力进入市场，劳工待遇越差&#xA;&lt;ul&gt;&#xA;&lt;li&gt;收入减少、劳动强度增大、缺乏社保体系&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;经济增长 vs 社会稳定&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;双重过剩：生产过剩和劳动力过剩&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;路权战略：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;一带一路：向南向西的陆路交通建设与次区域交通网络连接。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;发展中国家在资本主义文明阶段的经验归纳：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;任何跟进工业化的后发国家面对资本稀缺都势所必然地采取&lt;strong&gt;亲资本&lt;/strong&gt;政策，只有进入资本过剩阶段后才可能转向&lt;strong&gt;亲民生&lt;/strong&gt;。&lt;/li&gt;&#xA;&lt;li&gt;任何资本投资国都在试图运用其建制权直接控制，或以债权来渗透后发国家的政府制度体系以最大化获取资本收益。&lt;/li&gt;&#xA;&lt;li&gt;发展中国家只有维护&lt;strong&gt;资源和货币主权&lt;/strong&gt;，才能在危机挑战中使用逆周期调节。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;没有货币主权时，危机爆发，外部资本会逃走（做空）。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;新中国的第一次周期性经济危机1949-1951&#34;&gt;新中国的第一次周期性经济危机（1949-1951）&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;革命红利 + 局部战争 &amp;ndash;&amp;gt; 恶性通胀&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;政治上：三反五反&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;经济上：动用国有部门政府直接干预，战争拉动&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;引入外资-&amp;gt;外债-&amp;gt;财政赤字-&amp;gt;降低财政对于扩大再生产的投入-&amp;gt;减少就业-&amp;gt;经济危机-&amp;gt;社会动乱&lt;/p&gt;&#xA;&lt;p&gt;不支持线性社会发展论，只适合地中海周围的国家&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;危机情况：&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;物价恶性上涨：解放的大城市物价上涨几十倍。&lt;/li&gt;&#xA;&lt;li&gt;财政严重赤字：军队开支超过财政总支出60%&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;农业自身内在具有自然过程与经济过程高度结合的特征，在世界近代通过殖民化推工业化的资本文明史中，农业内在特质不可能被根除，客观分化为三个异质性很强的不同类型：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;盎格鲁撒克逊的殖民化大农场&lt;/strong&gt;：新大陆因彻底殖民化造成资源充足的客观条件而得以实现农业规模化和资本化，对应的是公司化和产业化的农业政策。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;莱茵模式的前殖民主义宗主国（欧盟为代表）的中小农场农业&lt;/strong&gt;：农业资本化和生态化结合，农业不能为工业化提供原始积累，也没有自由市场体制下的竞争力，另一方面与农业生态化高度相关的绿色社会运动从欧洲兴起。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;未被西方彻底殖民化的原住民为主的东亚模式的传统小农经济国家的农户经济（日韩为代表）&lt;/strong&gt;：通过对农村人口全覆盖的普惠制的综合性合作社体系来实现社会资源资本化维持工业化原始积累时期的三农的稳定。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;危机根源于&lt;strong&gt;增发无储备货币&lt;/strong&gt;和&lt;strong&gt;物价失控&lt;/strong&gt;：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Java File IO的几种姿势</title>
      <link>http://localhost:1313/posts/java%E5%9F%BA%E7%A1%80/java%E6%96%87%E4%BB%B6io%E7%9A%84%E5%87%A0%E7%A7%8D%E5%A7%BF%E5%8A%BF/</link>
      <pubDate>Wed, 26 Apr 2023 22:41:57 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%9F%BA%E7%A1%80/java%E6%96%87%E4%BB%B6io%E7%9A%84%E5%87%A0%E7%A7%8D%E5%A7%BF%E5%8A%BF/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/image-20230426224504720.png&#34; alt=&#34;Java File IO 复杂度&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;读写方式&#34;&gt;读写方式&lt;/h2&gt;&#xA;&lt;p&gt;Java中的File IO基本可以分为三类：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;面向字节传输的传统IO方式&lt;/li&gt;&#xA;&lt;li&gt;FileChannel文件通道&lt;/li&gt;&#xA;&lt;li&gt;mmap内存映射&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;buffered-stream-io&#34;&gt;Buffered Stream I/O&lt;/h3&gt;&#xA;&lt;p&gt;BufferedReader通过内部buffer将文件的一部分字节缓存下来，减少频繁的磁盘IO。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;testStream&lt;/span&gt;(){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; (BufferedReader reader &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Files.&lt;span style=&#34;color:#a6e22e&#34;&gt;newBufferedReader&lt;/span&gt;(Paths.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;(PATH), StandardCharsets.&lt;span style=&#34;color:#a6e22e&#34;&gt;UTF_8&lt;/span&gt;)) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            String line &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; ((line &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; reader.&lt;span style=&#34;color:#a6e22e&#34;&gt;readLine&lt;/span&gt;()) &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(line);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (IOException x) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            System.&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;format&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;IOException: %s%n&amp;#34;&lt;/span&gt;, x);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;unbuffered-streams-io&#34;&gt;Unbuffered Streams I/O&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;testUnStream&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; (InputStream in &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Files.&lt;span style=&#34;color:#a6e22e&#34;&gt;newInputStream&lt;/span&gt;(Paths.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;(PATH));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             BufferedReader reader &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                     &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; BufferedReader(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; InputStreamReader(in))) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            String line &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; ((line &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; reader.&lt;span style=&#34;color:#a6e22e&#34;&gt;readLine&lt;/span&gt;()) &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(line);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (IOException x) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            System.&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(x);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;channel-io&#34;&gt;Channel I/O&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;readAllBytes&lt;/span&gt;(Path path) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; IOException {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; (SeekableByteChannel sbc &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Files.&lt;span style=&#34;color:#a6e22e&#34;&gt;newByteChannel&lt;/span&gt;(path);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             InputStream in &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Channels.&lt;span style=&#34;color:#a6e22e&#34;&gt;newInputStream&lt;/span&gt;(sbc)) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; size &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; sbc.&lt;span style=&#34;color:#a6e22e&#34;&gt;size&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (size &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt;)MAX_BUFFER_SIZE)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; OutOfMemoryError(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Required array size too large&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; read(in, (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;)size);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; SeekableByteChannel &lt;span style=&#34;color:#a6e22e&#34;&gt;newByteChannel&lt;/span&gt;(Path path, OpenOption... options)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; IOException&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Set&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;OpenOption&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; set &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; HashSet&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;OpenOption&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;(options.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Collections.&lt;span style=&#34;color:#a6e22e&#34;&gt;addAll&lt;/span&gt;(set, options);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; newByteChannel(path, set);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; SeekableByteChannel &lt;span style=&#34;color:#a6e22e&#34;&gt;newByteChannel&lt;/span&gt;(Path path,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                     Set&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;?&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; OpenOption&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; options,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                                     FileAttribute&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;?&amp;gt;&lt;/span&gt;... attrs)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; IOException&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; provider(path).&lt;span style=&#34;color:#a6e22e&#34;&gt;newByteChannel&lt;/span&gt;(path, options, attrs);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; SeekableByteChannel &lt;span style=&#34;color:#a6e22e&#34;&gt;newByteChannel&lt;/span&gt;(Path path,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Set&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;?&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; OpenOption&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; options, FileAttribute&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;?&amp;gt;&lt;/span&gt;... attrs) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; IOException;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;testChannel&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; (SeekableByteChannel sbc &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Files.&lt;span style=&#34;color:#a6e22e&#34;&gt;newByteChannel&lt;/span&gt;(Paths.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;(PATH))) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; BUFFER_CAPACITY &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 10;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ByteBuffer buf &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ByteBuffer.&lt;span style=&#34;color:#a6e22e&#34;&gt;allocate&lt;/span&gt;(BUFFER_CAPACITY);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// Read the bytes with the proper encoding for this platform. If&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// you skip this step, you might see foreign or illegible&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// characters.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            String encoding &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; System.&lt;span style=&#34;color:#a6e22e&#34;&gt;getProperty&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;file.encoding&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; (sbc.&lt;span style=&#34;color:#a6e22e&#34;&gt;read&lt;/span&gt;(buf) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; 0) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                buf.&lt;span style=&#34;color:#a6e22e&#34;&gt;flip&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;print&lt;/span&gt;(Charset.&lt;span style=&#34;color:#a6e22e&#34;&gt;forName&lt;/span&gt;(encoding).&lt;span style=&#34;color:#a6e22e&#34;&gt;decode&lt;/span&gt;(buf));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                buf.&lt;span style=&#34;color:#a6e22e&#34;&gt;clear&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (IOException e){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            System.&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(e);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;filechannel&#34;&gt;FileChannel&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;testFileChannel&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            FileChannel fileChannel &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; RandomAccessFile(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; File(PATH), &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rw&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;getChannel&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ByteBuffer byteBuffer &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ByteBuffer.&lt;span style=&#34;color:#a6e22e&#34;&gt;allocate&lt;/span&gt;(4);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            fileChannel.&lt;span style=&#34;color:#a6e22e&#34;&gt;read&lt;/span&gt;(byteBuffer);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            String str &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; String(byteBuffer.&lt;span style=&#34;color:#a6e22e&#34;&gt;array&lt;/span&gt;(), StandardCharsets.&lt;span style=&#34;color:#a6e22e&#34;&gt;UTF_8&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(str);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (IOException e){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            System.&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(e);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;mmap&#34;&gt;mmap&lt;/h3&gt;&#xA;&lt;p&gt;适用于读写小文件的应用场景。&lt;/p&gt;</description>
    </item>
    <item>
      <title>跑步理论知识</title>
      <link>http://localhost:1313/posts/%E9%9A%8F%E7%AC%94/running-theory/</link>
      <pubDate>Sat, 15 Apr 2023 16:20:59 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E9%9A%8F%E7%AC%94/running-theory/</guid>
      <description>&lt;h1 id=&#34;心率区间&#34;&gt;心率区间&lt;/h1&gt;&#xA;&lt;p&gt;心率区间有以下三种计算方式，最大心率百分比、储备心率百分比、乳酸阈值百分比&lt;/p&gt;&#xA;&lt;p&gt;计算方式：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;最大心率：220 - age&lt;/li&gt;&#xA;&lt;li&gt;储备心率：最大心率 - 静息心率&lt;/li&gt;&#xA;&lt;li&gt;乳酸阈值百分比：根据乳酸阈值划分心率区间&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;乳酸阈值：血液中乳酸浓度的增长速度快于乳酸的代谢速度，使得乳酸开始在血液中堆积的临界状态。&lt;/p&gt;&#xA;&lt;h2 id=&#34;储备心率法&#34;&gt;储备心率法&lt;/h2&gt;&#xA;&lt;p&gt;心率区间 =（最大心率-静止心率）*储备心率%+静止心率&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;心率区间名称&lt;/th&gt;&#xA;          &lt;th&gt;储备心率法&lt;/th&gt;&#xA;          &lt;th&gt;实际数值&lt;/th&gt;&#xA;          &lt;th&gt;说明&lt;/th&gt;&#xA;          &lt;th&gt;含义&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;区间1（E）&lt;/td&gt;&#xA;          &lt;td&gt;59%-74%&lt;/td&gt;&#xA;          &lt;td&gt;138-159&lt;/td&gt;&#xA;          &lt;td&gt;LSD配速，有氧耐力&lt;/td&gt;&#xA;          &lt;td&gt;轻松聊天，锻炼心肌强度，增强身体供氧能力，提高有氧耐力&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;区间2（M）&lt;/td&gt;&#xA;          &lt;td&gt;74%-84%&lt;/td&gt;&#xA;          &lt;td&gt;159-173&lt;/td&gt;&#xA;          &lt;td&gt;马拉松配速&lt;/td&gt;&#xA;          &lt;td&gt;呼吸加重&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;区间3（T）&lt;/td&gt;&#xA;          &lt;td&gt;84%-88%&lt;/td&gt;&#xA;          &lt;td&gt;173-179&lt;/td&gt;&#xA;          &lt;td&gt;乳酸阈值强度&lt;/td&gt;&#xA;          &lt;td&gt;呼吸会喘，身体开始堆积乳酸，提升乳酸阈值，增强乳酸排出能力&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;区间4（A）&lt;/td&gt;&#xA;          &lt;td&gt;88%-95%&lt;/td&gt;&#xA;          &lt;td&gt;179-188&lt;/td&gt;&#xA;          &lt;td&gt;无氧区间&lt;/td&gt;&#xA;          &lt;td&gt;间歇跑，增强乳酸耐受能力，提升无氧耐力&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;区间5（I）&lt;/td&gt;&#xA;          &lt;td&gt;95%-100%&lt;/td&gt;&#xA;          &lt;td&gt;188-196&lt;/td&gt;&#xA;          &lt;td&gt;最大摄氧量强度&lt;/td&gt;&#xA;          &lt;td&gt;高强度间歇，提高无氧能力和速度&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h2 id=&#34;最大心率法&#34;&gt;最大心率法&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;心率区间名称&lt;/th&gt;&#xA;          &lt;th&gt;最大心率法&lt;/th&gt;&#xA;          &lt;th&gt;说明&lt;/th&gt;&#xA;          &lt;th&gt;实际数值&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;区间1（热身）&lt;/td&gt;&#xA;          &lt;td&gt;50%-60%&lt;/td&gt;&#xA;          &lt;td&gt;热身&lt;/td&gt;&#xA;          &lt;td&gt;98-117&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;区间2（燃脂）&lt;/td&gt;&#xA;          &lt;td&gt;60%-70%&lt;/td&gt;&#xA;          &lt;td&gt;有效燃脂，增强心肺能力&lt;/td&gt;&#xA;          &lt;td&gt;117-137&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;区间3（有氧耐力）&lt;/td&gt;&#xA;          &lt;td&gt;70%-80%&lt;/td&gt;&#xA;          &lt;td&gt;有氧耐力&lt;/td&gt;&#xA;          &lt;td&gt;137-156&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;区间4（马拉松配速）&lt;/td&gt;&#xA;          &lt;td&gt;80%-90%&lt;/td&gt;&#xA;          &lt;td&gt;提升乳酸耐受能力&lt;/td&gt;&#xA;          &lt;td&gt;156-176&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;区间5（无氧耐力）&lt;/td&gt;&#xA;          &lt;td&gt;90%-100%&lt;/td&gt;&#xA;          &lt;td&gt;高强度&lt;/td&gt;&#xA;          &lt;td&gt;176-196&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h2 id=&#34;有氧心率区间计算方法&#34;&gt;有氧心率区间计算方法&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;最大心率法&lt;/li&gt;&#xA;&lt;li&gt;储备心率法&lt;/li&gt;&#xA;&lt;li&gt;MAF180：最大有氧心率= 180 - age&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h1 id=&#34;有氧能力&#34;&gt;有氧能力&lt;/h1&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/image.png&#34; alt=&#34;有氧能力&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>解析Java动态代理机制的实现</title>
      <link>http://localhost:1313/posts/java%E5%9F%BA%E7%A1%80/%E8%A7%A3%E6%9E%90java%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E6%9C%BA%E5%88%B6/</link>
      <pubDate>Sun, 05 Mar 2023 21:23:54 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%9F%BA%E7%A1%80/%E8%A7%A3%E6%9E%90java%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E6%9C%BA%E5%88%B6/</guid>
      <description>&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;&#xA;&lt;p&gt;代理模式主要是Proxy对原始方法做了一层包装，用以增加一些新的统一处理逻辑，来增强目标对象的功能。静态代理是传统设计模式中一种传统的实现方案，动态代理能将代理对象的创建延迟到程序运行阶段。&lt;/p&gt;&#xA;&lt;p&gt;以下是一个动态代理的示例：&lt;/p&gt;&#xA;&lt;p&gt;被代理类：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DemoService&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#a6e22e&#34;&gt;process&lt;/span&gt;(String value);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@Slf4j&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DemoServiceImpl&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; DemoService{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; String RESULT &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;result&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#a6e22e&#34;&gt;process&lt;/span&gt;(String value) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        log.&lt;span style=&#34;color:#a6e22e&#34;&gt;info&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;{} is processing, parameter: {}&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;getClass&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;getName&lt;/span&gt;(), value);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; RESULT;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;代理类：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@Slf4j&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DemoInvokerHandler&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; InvocationHandler {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; Object target;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DemoInvokerHandler&lt;/span&gt;(Object target) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;target&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; target;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Object &lt;span style=&#34;color:#a6e22e&#34;&gt;invoke&lt;/span&gt;(Object proxy, Method method, Object&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; args) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; Throwable {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        log.&lt;span style=&#34;color:#a6e22e&#34;&gt;info&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;before...&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Object result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; method.&lt;span style=&#34;color:#a6e22e&#34;&gt;invoke&lt;/span&gt;(target, args);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        log.&lt;span style=&#34;color:#a6e22e&#34;&gt;info&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;after...&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; result;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Object &lt;span style=&#34;color:#a6e22e&#34;&gt;getProxy&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 创建代理对象&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Proxy.&lt;span style=&#34;color:#a6e22e&#34;&gt;newProxyInstance&lt;/span&gt;(Thread.&lt;span style=&#34;color:#a6e22e&#34;&gt;currentThread&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;getContextClassLoader&lt;/span&gt;(),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                target.&lt;span style=&#34;color:#a6e22e&#34;&gt;getClass&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;getInterfaces&lt;/span&gt;(), &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;代理调用：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Java SPI机制学习与常用框架SPI案例</title>
      <link>http://localhost:1313/posts/java%E5%9F%BA%E7%A1%80/java-spi%E6%9C%BA%E5%88%B6%E5%AD%A6%E4%B9%A0%E4%B8%8E%E5%B8%B8%E7%94%A8%E6%A1%86%E6%9E%B6spi%E6%A1%88%E4%BE%8B/</link>
      <pubDate>Tue, 28 Feb 2023 17:01:26 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%9F%BA%E7%A1%80/java-spi%E6%9C%BA%E5%88%B6%E5%AD%A6%E4%B9%A0%E4%B8%8E%E5%B8%B8%E7%94%A8%E6%A1%86%E6%9E%B6spi%E6%A1%88%E4%BE%8B/</guid>
      <description>&lt;h2 id=&#34;概念&#34;&gt;概念&lt;/h2&gt;&#xA;&lt;p&gt;SPI（Service Provider Interface）是JDK内置的服务提供机制，常用于框架的动态扩展，类似于可拔插机制。提供方将接口实现类配置在classpath下的指定位置，调用方读取并加载。当提供方发生变化时，接口的实现也会改变。Java生态中JDK、Dubbo、Spring等都通过SPI提供了动态扩展的能力。&lt;/p&gt;&#xA;&lt;h2 id=&#34;样例&#34;&gt;样例&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Search&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;search&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;FileSearchImpl&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; Search {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;search&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;file search...&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DataBaseSearchImpl&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; Search {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;search&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;db search&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SpiTest&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;(String&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; args) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ServiceLoader&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Search&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; searches &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ServiceLoader.&lt;span style=&#34;color:#a6e22e&#34;&gt;load&lt;/span&gt;(Search.&lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        searches.&lt;span style=&#34;color:#a6e22e&#34;&gt;forEach&lt;/span&gt;(Search::search);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;resources文件夹创建&lt;code&gt;META-INF/services/wang.l1n.spi.Search&lt;/code&gt;文件，内容为接口实现类：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;wang.l1n.spi.FileSearchImpl&#xA;wang.l1n.spi.DataBaseSearchImpl&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;运行结果：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/image-20230226183550948.png&#34; alt=&#34;SPI运行结果&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;load加载流程&#34;&gt;load加载流程&lt;/h3&gt;&#xA;&lt;p&gt;&lt;code&gt;ServiceLoder.load&lt;/code&gt;静态方法用于加载SPI实现类，实现逻辑如下：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;获取当前线程类加载器和上下文信息，调用实例化方法，重新加载SPI&lt;/li&gt;&#xA;&lt;li&gt;重新加载SPI的流程：&#xA;&lt;ol&gt;&#xA;&lt;li&gt;清空缓存providers中已实例化的SPI服务，providers是LinkedHashMap类型，用于保存已经被成功加载的SPI示例对象&#xA;&lt;ul&gt;&#xA;&lt;li&gt;如果providers非空，直接返回Iterator，否则返回LazyIterator的Iterator。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;创建LazyIterator懒加载迭代器，传入SPI类型和类加载器&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;实现代码和对应的成员变量如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;S&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; ServiceLoader&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;S&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;load&lt;/span&gt;(Class&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;S&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; service) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ClassLoader cl &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Thread.&lt;span style=&#34;color:#a6e22e&#34;&gt;currentThread&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;getContextClassLoader&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; ServiceLoader.&lt;span style=&#34;color:#a6e22e&#34;&gt;load&lt;/span&gt;(service, cl);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;S&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; ServiceLoader&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;S&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;load&lt;/span&gt;(Class&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;S&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; service,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                            ClassLoader loader)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ServiceLoader&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt;(service, loader);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ServiceLoader&lt;/span&gt;(Class&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;S&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; svc, ClassLoader cl) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        service &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Objects.&lt;span style=&#34;color:#a6e22e&#34;&gt;requireNonNull&lt;/span&gt;(svc, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Service interface cannot be null&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        loader &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (cl &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; ClassLoader.&lt;span style=&#34;color:#a6e22e&#34;&gt;getSystemClassLoader&lt;/span&gt;() : cl;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        acc &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (System.&lt;span style=&#34;color:#a6e22e&#34;&gt;getSecurityManager&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; AccessController.&lt;span style=&#34;color:#a6e22e&#34;&gt;getContext&lt;/span&gt;() : &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        reload();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;reload&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        providers.&lt;span style=&#34;color:#a6e22e&#34;&gt;clear&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        lookupIterator &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; LazyIterator(service, loader);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; String PREFIX &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;META-INF/services/&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// The class or interface representing the service being loaded&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; Class&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;S&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; service;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// The class loader used to locate, load, and instantiate providers&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; ClassLoader loader;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// The access control context taken when the ServiceLoader is created&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; AccessControlContext acc;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Cached providers, in instantiation order&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; LinkedHashMap&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;String,S&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; providers &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; LinkedHashMap&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;gt;&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// The current lazy-lookup iterator&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; LazyIterator lookupIterator;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Iterator&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;S&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;iterator&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Iterator&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;S&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Iterator&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Map.&lt;span style=&#34;color:#a6e22e&#34;&gt;Entry&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;String,S&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; knownProviders&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; providers.&lt;span style=&#34;color:#a6e22e&#34;&gt;entrySet&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;iterator&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hasNext&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (knownProviders.&lt;span style=&#34;color:#a6e22e&#34;&gt;hasNext&lt;/span&gt;())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; lookupIterator.&lt;span style=&#34;color:#a6e22e&#34;&gt;hasNext&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; S &lt;span style=&#34;color:#a6e22e&#34;&gt;next&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (knownProviders.&lt;span style=&#34;color:#a6e22e&#34;&gt;hasNext&lt;/span&gt;())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; knownProviders.&lt;span style=&#34;color:#a6e22e&#34;&gt;next&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;getValue&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; lookupIterator.&lt;span style=&#34;color:#a6e22e&#34;&gt;next&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;remove&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; UnsupportedOperationException();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;lazyiterator加载流程&#34;&gt;LazyIterator加载流程&lt;/h3&gt;&#xA;&lt;p&gt;加载流程参考代码注释：&lt;/p&gt;</description>
    </item>
    <item>
      <title>状态机引擎的业务实践</title>
      <link>http://localhost:1313/posts/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E7%8A%B6%E6%80%81%E6%9C%BA%E5%BC%95%E6%93%8E%E7%9A%84%E4%B8%9A%E5%8A%A1%E5%AE%9E%E8%B7%B5/</link>
      <pubDate>Sat, 25 Feb 2023 20:57:00 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E7%8A%B6%E6%80%81%E6%9C%BA%E5%BC%95%E6%93%8E%E7%9A%84%E4%B8%9A%E5%8A%A1%E5%AE%9E%E8%B7%B5/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;在开发中通常会有状态属性，例如订单状态、事件处置状态、OA请假单状态等，都会根据不同的动作，去更新对应的状态。如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; status &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (condition1){  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    status &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 1;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (condition2){  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    status &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 2;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (condition3){  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    status &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 3;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上述示例存在的问题：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;在需求增加的情况下，if.else会不断膨胀&lt;/li&gt;&#xA;&lt;li&gt;代码可读性差，略微改动会导致各种问题&lt;/li&gt;&#xA;&lt;li&gt;其他业务逻辑会耦合在if.else代码段中&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;针对系统中状态的管理，可以使用&lt;strong&gt;有限状态机&lt;/strong&gt;去解决，有限状态机是表示有限个状态以及状态间转移的模型。状态机由事件、状态、动作三部分组成。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/image-20230220205838434.png&#34; alt=&#34;image-20230220205838434&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;状态机的简单实现&#34;&gt;状态机的简单实现&lt;/h2&gt;&#xA;&lt;h3 id=&#34;条件分支判断&#34;&gt;条件分支判断&lt;/h3&gt;&#xA;&lt;p&gt;最简单的方案是通过条件分支控制状态的转移，这适合于业务状态较少，并且状态跳转的逻辑较简单的场景，但是当触发事件较多时，需要嵌套多层条件判断，当需求中状态变更事件改变时，需要改动的逻辑较大。案例代码如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;enum&lt;/span&gt; ActivityState {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    PREPARE(0),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    STARTED(1),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    END(2)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; status;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ActivityState(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; status) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; status;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getStatus&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; status;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * 活动状态-状态机&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @author l1nker4&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ActivityStateMachine&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * 活动状态&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; ActivityState currentState;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ActivityStateMachine&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;currentState&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ActivityState.&lt;span style=&#34;color:#a6e22e&#34;&gt;PREPARE&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * 活动开始&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;begin&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (currentState.&lt;span style=&#34;color:#a6e22e&#34;&gt;equals&lt;/span&gt;(ActivityState.&lt;span style=&#34;color:#a6e22e&#34;&gt;PREPARE&lt;/span&gt;)) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;currentState&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ActivityState.&lt;span style=&#34;color:#a6e22e&#34;&gt;STARTED&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;//do something....&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * 活动结束&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;end&lt;/span&gt;(){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (currentState.&lt;span style=&#34;color:#a6e22e&#34;&gt;equals&lt;/span&gt;(ActivityState.&lt;span style=&#34;color:#a6e22e&#34;&gt;STARTED&lt;/span&gt;)){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;currentState&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ActivityState.&lt;span style=&#34;color:#a6e22e&#34;&gt;END&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;//do something...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;状态模式实现&#34;&gt;状态模式实现&lt;/h3&gt;&#xA;&lt;p&gt;设计模式中的状态模式也是状态机的一种实现方式，定义了状态-行为的对应关系，并将各自的行为封装到状态类中。状态模式会引入较多的状态类和方法，需求变更时维护成本大。&lt;/p&gt;</description>
    </item>
    <item>
      <title>HTTPS通信过程分析</title>
      <link>http://localhost:1313/posts/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/https%E9%80%9A%E4%BF%A1%E8%BF%87%E7%A8%8B%E5%88%86%E6%9E%90/</link>
      <pubDate>Fri, 10 Feb 2023 21:33:11 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/https%E9%80%9A%E4%BF%A1%E8%BF%87%E7%A8%8B%E5%88%86%E6%9E%90/</guid>
      <description>&lt;h3 id=&#34;为什么需要https&#34;&gt;为什么需要HTTPS&lt;/h3&gt;&#xA;&lt;p&gt;HTTP缺点：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;明文传输&lt;/li&gt;&#xA;&lt;li&gt;C/S两端不存在验证机制，无法确认对方身份，可能存在中间人攻击。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;概念&#34;&gt;概念&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;对称加密：客户端和服务器持有同一个密钥对数据进行加密解密。&lt;/li&gt;&#xA;&lt;li&gt;非对称加密：公钥加密私钥解密、私钥加密公钥解密&lt;/li&gt;&#xA;&lt;li&gt;CA：证书认证机构，签发数字证书，保证公钥的可信度。&lt;/li&gt;&#xA;&lt;li&gt;数字证书：包含版本、序列号、有效期、颁发者、公钥等信息&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;数字证书是由CA颁发用于证明身份的证书，通过域名申请对应证书，域名的合法性由CA机构保证。&lt;/p&gt;&#xA;&lt;p&gt;TLS有以下几个子协议：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;记录协议（Record Protocol）：规定TLS收发数据的基本单位为&lt;strong&gt;record&lt;/strong&gt;，类似于TCP的segment，所有子协议都必须通过记录协议发出。&lt;/li&gt;&#xA;&lt;li&gt;警报协议（Alert  Protocol）：向对方发出警报信息，比如：证书问题等&lt;/li&gt;&#xA;&lt;li&gt;握手协议（Handshake Protocol）：两端协商TLS版本号、随机数、密码套件等信息，然后客户端通过服务端的公钥和证书上的数字签名、两端协商得到会话密钥。&lt;/li&gt;&#xA;&lt;li&gt;变更密码规范协议：通知对方后续数据使用密码加密保护&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;https通信过程&#34;&gt;HTTPS通信过程&lt;/h2&gt;&#xA;&lt;p&gt;HTTPS通信可以划分为三个阶段：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;TCP协议：通过三次握手建立TCP连接&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;TLS协议：四次握手建立TLS连接&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;HTTPS协议：客户端发送请求，服务端响应请求，通信报文使用密钥加密。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;TLS 1.2 握手：使用非对称加密方式创建对称密钥，并使用对称加密完成HTTP通信。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20230326182939.png&#34; alt=&#34;TLS 1.2 handshake&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;详细过程：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;客户端发送&lt;code&gt;Client Hello&lt;/code&gt;消息到服务端，消息包含TLS版本、加密套件（Cipher Suite）、压缩算法、随机数，会话信息扩展信息等。&lt;/li&gt;&#xA;&lt;li&gt;服务端发送&lt;code&gt;Server Hello&lt;/code&gt;消息，消息包含服务端的TLS版本、加密套件（Cipher Suite）、会话信息&lt;/li&gt;&#xA;&lt;li&gt;服务端发送&lt;code&gt;Certificate&lt;/code&gt;消息，包括服务端的证书信息。&lt;/li&gt;&#xA;&lt;li&gt;服务端发送&lt;code&gt;Server Key Exchange&lt;/code&gt;消息，发送公钥与签名信息等。可能与&lt;code&gt;Server Hello Done&lt;/code&gt;消息一同发送。&lt;/li&gt;&#xA;&lt;li&gt;客户端发送&lt;code&gt;Client Key Exchange&lt;/code&gt;消息，根据自己信任的CA列表，验证服务端证书是否可行，可信则生成一串伪随机数，并使用公钥加密，这串随机数被用于生成新的&lt;strong&gt;对称密钥&lt;/strong&gt;。&lt;/li&gt;&#xA;&lt;li&gt;服务器端使用私钥解密随机数，并使用随机数生成自己的&lt;strong&gt;对称主密钥&lt;/strong&gt;。&lt;/li&gt;&#xA;&lt;li&gt;客户端发送&lt;code&gt;Finished&lt;/code&gt;消息，使用对称密钥加密这次通信的hash值。&lt;/li&gt;&#xA;&lt;li&gt;服务端生成自己的hash值，然后解密客户端发来的信息，检查这两个值是否对应，若对应则发送&lt;code&gt;Finished&lt;/code&gt;消息。&lt;/li&gt;&#xA;&lt;li&gt;接下来，整个HTTP会话都是用对称密钥进行加密并传输。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;TLS握手的关键点：通过生成的随机数和服务端公钥，生成新的密钥，后续通信使用这个对称密钥加密，防止中间人攻击。&lt;/p&gt;</description>
    </item>
    <item>
      <title>ShardingSphere-JDBC学习笔记</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/shardingsphere-jdbc%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</link>
      <pubDate>Wed, 11 Jan 2023 18:41:32 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/shardingsphere-jdbc%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</guid>
      <description>&lt;h2 id=&#34;基础概念&#34;&gt;基础概念&lt;/h2&gt;&#xA;&lt;p&gt;ShardingSphere-JDBC是Apache ShardingSphere项目中的一个子项目，Apache ShardingSphere是一款分布式的数据库生态系统，可以通过分片、弹性伸缩、加密等能力对原有数据库进行增强。&lt;/p&gt;&#xA;&lt;p&gt;ShardingSphere-JDBC定位是&lt;strong&gt;轻量级Java框架&lt;/strong&gt;，在JDBC层提供额外服务。它能尽量透明化水平分库分表所带来的影响，让业务方逻辑上感知到一个数据库节点和逻辑表，当收到SQL查询，主要做了以下工作：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;SQL解析：词法解析和语法解析，提炼出解析上下文&lt;/li&gt;&#xA;&lt;li&gt;SQL路由：根据解析上下文匹配用户配置的库表的分片策略，并生成路由后的SQL（一条或多条）。&lt;/li&gt;&#xA;&lt;li&gt;SQL改写：将SQL改写为物理数据库能正常执行的语句（逻辑SQL -&amp;gt; 物理SQL）。&lt;/li&gt;&#xA;&lt;li&gt;SQL执行：通过多线程异步执行改写后的SQL语句。&lt;/li&gt;&#xA;&lt;li&gt;结果归并：将多个执行结果归并为统一的JDBC接口输出。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;几个概念：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;逻辑表：ORM框架的业务层面，表现为一张表，例如：t_order&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;物理表：数据库层面实际存在的表，例如：t_order_0、t_order_1&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;绑定表：分片规则一致的一组分片表，进行关联查询时，建议使用分片键进行关联，否则影响查询效率。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.order_id in (10, 11);&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;广播表：数据源中都存在的表，且结构和数据都完全一致。适用于数据量不大且需要与其他大数据量表进行关联查询。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;分片键：根据某个字段的计算结果（取模等）进行水平分片&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;路由：通过SQL语句中的信息，找到对应分片的过程&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;分片算法&#34;&gt;分片算法&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;标准分片算法：单一键作为分片键。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;取模算法：根据一些字段，或多个字段hash求值再取模。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;范围限定算法，按照年份、实践等策略路由到目标数据库。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;复合分片算法：多键作为分片键，自行设计&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Hint分片算法：用于处理使用Hint行分片的场景（非数据库字段的分片方式）&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;分片策略&#34;&gt;分片策略&lt;/h3&gt;&#xA;&lt;p&gt;包含分片键和分片算法，ShardingSphere-JDBC提供了以下几种分片策略：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;标准分片策略（StandardSharingStrategy）：使用精确分片算法或范围分片算法，支持单分片键。&lt;/li&gt;&#xA;&lt;li&gt;复合分片策略（ComplexShardingStrategy）：使用复合分片算法，支持多分片键。&lt;/li&gt;&#xA;&lt;li&gt;Hint分片策略（HintShardingStrategy）：使用Hint分片算法&lt;/li&gt;&#xA;&lt;li&gt;Inline分片策略（InlineShardingStrategy）：使用groovy表达式作为分片算法&lt;/li&gt;&#xA;&lt;li&gt;不分片策略（NoneShardingStrategy）：不使用分片算法&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;demo&#34;&gt;Demo&lt;/h2&gt;&#xA;&lt;p&gt;pom.xml&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.mybatis.spring.boot&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;mybatis-spring-boot-starter&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.1.4&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.mysql&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;mysql-connector-j&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;runtime&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;8.0.32&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.projectlombok&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;lombok&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;optional&amp;gt;&lt;/span&gt;true&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/optional&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.baomidou&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;mybatis-plus-boot-starter&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.2.0&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.alibaba&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;druid&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.2.15&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-test&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.shardingsphere&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;sharding-jdbc-spring-boot-starter&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;4.0.0-RC1&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.shardingsphere&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;sharding-core-common&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;4.0.0-RC1&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ShardingSphere提供了多种配置方式：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Netty学习笔记(三)- 时间轮算法</title>
      <link>http://localhost:1313/posts/netty/netty%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E4%B8%89--%E6%97%B6%E9%97%B4%E8%BD%AE%E7%AE%97%E6%B3%95/</link>
      <pubDate>Sat, 03 Dec 2022 10:12:54 +0000</pubDate>
      <guid>http://localhost:1313/posts/netty/netty%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E4%B8%89--%E6%97%B6%E9%97%B4%E8%BD%AE%E7%AE%97%E6%B3%95/</guid>
      <description>&lt;h2 id=&#34;定时器理论&#34;&gt;定时器理论&lt;/h2&gt;&#xA;&lt;p&gt;实际的业务场景会遇到许多使用定时任务的场景，定时器主要有三种表现形式：固定周期定时执行、延迟一定时间执行，指定某个时刻执行。再实现层面，定时器需要考虑&lt;strong&gt;存储和调度&lt;/strong&gt;指定任务，内部通过轮询的方式检查任务是否到期并需要执行。&lt;/p&gt;&#xA;&lt;h2 id=&#34;java定时器&#34;&gt;Java定时器&lt;/h2&gt;&#xA;&lt;p&gt;Java提供了三种常用的定时器实现方式：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Timer&lt;/li&gt;&#xA;&lt;li&gt;DelayQueue&lt;/li&gt;&#xA;&lt;li&gt;ScheduledThreadPoolExecutor&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;timer&#34;&gt;Timer&lt;/h3&gt;&#xA;&lt;p&gt;Timer使用的就是上述最原始的定时器实现方式：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;存储&lt;/strong&gt;：TaskQueue是数组实现的小根堆，deadline最近的任务位于堆顶端。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;调度&lt;/strong&gt;：TimerThread异步线程，定时轮询队列，如果堆顶任务的deadline已到，那么执行任务，如果是周期性任务，执行完计算下次deadline，并再次放入小根堆。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Timer&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; TaskQueue queue &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; TaskQueue();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; TimerThread thread &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; TimerThread(queue);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Timer&lt;/span&gt;(String name) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        thread.&lt;span style=&#34;color:#a6e22e&#34;&gt;setName&lt;/span&gt;(name);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        thread.&lt;span style=&#34;color:#a6e22e&#34;&gt;start&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Timer存在几个缺陷：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;单线程模式，某个TimeTask阻塞，会影响其他的任务调度。&lt;/li&gt;&#xA;&lt;li&gt;Timer的任务调度基于系统时间的，系统时间不正确，可能出现问题。&lt;/li&gt;&#xA;&lt;li&gt;TimeTask执行出现异常，Timer不会捕获，线程终止后，其他任务都不能执行。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;使用案例：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Timer timer &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Timer();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//设置一个10s后调度一个周期为1s的定时任务&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;timer.&lt;span style=&#34;color:#a6e22e&#34;&gt;scheduleAtFixedRate&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; TimerTask() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;run&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// do something&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}, 10000, 1000);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;delayqueue&#34;&gt;DelayQueue&lt;/h3&gt;&#xA;&lt;p&gt;DelayQueue是一种可以延迟获取对象的阻塞队列，内部使用PriorityQueue存储任务，每个元素必须实现Delayed接口，并重写指定方法。DelayQueue提供了put和take两个阻塞方法。对象put进去后，通过compareTo进行优先级排序，getDelay计算出剩余时间，只有小于等于0时，对象才能从其中被取出。&lt;/p&gt;&#xA;&lt;p&gt;实际上只实现了存储定时任务的功能，还需要配合异步线程才能实现定时器。&lt;/p&gt;&#xA;&lt;h3 id=&#34;scheduledthreadpoolexecutor&#34;&gt;ScheduledThreadPoolExecutor&lt;/h3&gt;&#xA;&lt;p&gt;该线程池继承于ThreadPoolExecutor，提供了周期执行和延迟执行的功能，在ThreadPoolExecutor的基础上，重新设计了任务ScheduledFutureTask和阻塞队列DelayedWorkQueue。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Netty学习笔记(二)- 内部机制</title>
      <link>http://localhost:1313/posts/netty/netty%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E4%BA%8C--%E5%86%85%E9%83%A8%E6%9C%BA%E5%88%B6/</link>
      <pubDate>Sat, 19 Nov 2022 08:12:54 +0000</pubDate>
      <guid>http://localhost:1313/posts/netty/netty%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E4%BA%8C--%E5%86%85%E9%83%A8%E6%9C%BA%E5%88%B6/</guid>
      <description>&lt;h1 id=&#34;事件调度层&#34;&gt;事件调度层&lt;/h1&gt;&#xA;&lt;h2 id=&#34;reactor线程模型&#34;&gt;Reactor线程模型&lt;/h2&gt;&#xA;&lt;p&gt;Netty中三种Reactor线程模型来源于&lt;a href=&#34;https://gee.cs.oswego.edu/dl/cpjslides/nio.pdf&#34;&gt;Scalable I/O in Java&lt;/a&gt;，主要有以下三种：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;单线程模型：所有IO操作（连接建立、读写、事件分发）都由一个线程完成。&lt;/li&gt;&#xA;&lt;li&gt;多线程模型：使用多线程处理任务。线程内部仍然是串行化。&lt;/li&gt;&#xA;&lt;li&gt;主从多线程模型：主线程只负责连接的Accept事件，从线程负责除连接外的事件。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Reactor线程模型运行机制可以分为以下四个步骤：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;注册连接：将Channel注册到Reactor线程中的Selector。&lt;/li&gt;&#xA;&lt;li&gt;事件轮询：轮询Selector中已注册的Channel的IO事件。&lt;/li&gt;&#xA;&lt;li&gt;事件分发：将连接的IO事件分发给worker线程。&lt;/li&gt;&#xA;&lt;li&gt;任务处理：Reactor线程负责队列中的非IO任务。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;eventloop&#34;&gt;EventLoop&lt;/h2&gt;&#xA;&lt;p&gt;EventLoop是一种&lt;strong&gt;事件处理模型&lt;/strong&gt;，Netty中EventLoop运行机制如下图所示：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/image-20221113182321659.png&#34; alt=&#34;EventLoop运行机制&#34;&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;BossEventLoopGroup：负责监听客户端的Accept事件，触发时将事件注册到WorkerEventLoopGroup中的一个NioEventLoop，&lt;/li&gt;&#xA;&lt;li&gt;WorkerEventLoopGroup：每建立一个Channel，都选择一个NioEventLoop与其绑定，Channel的所有事件都是线程独立的。不会和其他线程发生交集。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;任务处理机制&#34;&gt;任务处理机制&lt;/h3&gt;&#xA;&lt;p&gt;NioEventLoop不仅负责处理IO事件，还要兼顾执行任务队列中的任务。任务队列遵守FIFO原则。任务基本可以分为三类：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;普通任务：通过NioEventLoop的execute()方法向taskQueue中添加的。&lt;/li&gt;&#xA;&lt;li&gt;定时任务：通过NioEventLoop的schedule()方法向scheduledtaskQueue添加的定时任务，例如心跳消息可以通过该任务实现。&lt;/li&gt;&#xA;&lt;li&gt;尾部队列：执行完taskQueue中任务后会去获取尾部队列tailTasks中的任务去执行。主要做收尾工作，例如统计事件循环的执行时间等。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;使用技巧&#34;&gt;使用技巧&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;使用Boss和Worker两个Group分别处理不同的事件，合理分担压力。&lt;/li&gt;&#xA;&lt;li&gt;对于耗时较长的ChannelHandler可以考虑维护一个业务线程池，将任务封装成Task进行异步处理。，避免ChannelHandler阻塞而造成EventLoop不可用。&lt;/li&gt;&#xA;&lt;li&gt;选用合理的ChannelHandler数量，明确业务和Netty的分层。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h1 id=&#34;服务编排层&#34;&gt;服务编排层&lt;/h1&gt;&#xA;&lt;h2 id=&#34;channelpipeline&#34;&gt;ChannelPipeline&lt;/h2&gt;&#xA;&lt;p&gt;Pipeline如同字面意思，原始的网络字节流流经pipeline，被逐层处理，最终得到成品数据并返回。Netty中的ChannelPipeline采取责任链模式，调用链路环环相扣。&lt;/p&gt;&#xA;&lt;p&gt;ChannelPipeline由一组ChannelHandlerContext组成，内部通过双向链表将ChannelHandlerContext连接起来，当IO事件触发时，依次调用Handler对数据进行处理。ChannelHandlerContext用于保存ChannelHandler的上下文，包含了其生命周期的所有事件：connect、bind、read等。&lt;/p&gt;&#xA;&lt;p&gt;根据数据流向，ChannelPipeline可以分为入站和出站两种处理器，对应&lt;strong&gt;ChannelInboundHandler&lt;/strong&gt;和&lt;strong&gt;ChannelOutboundHandler&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;异常处理&#34;&gt;异常处理&lt;/h2&gt;&#xA;&lt;p&gt;ChannelHandler采用了责任链模式，如果前置的Handler抛出呢Exception，会传递到后置Handler，异常处理的最佳实践，就是在最后加上自定义的异常处理器。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ExceptionHandler&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; ChannelDuplexHandler {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;exceptionCaught&lt;/span&gt;(ChannelHandlerContext ctx, Throwable cause) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (cause &lt;span style=&#34;color:#66d9ef&#34;&gt;instanceof&lt;/span&gt; RuntimeException) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Handle Business Exception Success.&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;零拷贝&#34;&gt;零拷贝&lt;/h1&gt;&#xA;&lt;p&gt;Netty中面向用户态的数据操作优化，主要包含以下几个方面：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;使用堆外内存，避免JVM内存到堆外内存之间的数据拷贝&lt;/li&gt;&#xA;&lt;li&gt;使用CompositeByteBuf，可以组合多个Buffer，将其合并成逻辑上的一个对象，避免物理的内存拷贝。&lt;/li&gt;&#xA;&lt;li&gt;使用Unpooled.wrappedBuffer，将byte数组包装成ByteBuf对象，过程间不产生内存拷贝。&lt;/li&gt;&#xA;&lt;li&gt;ByteBuf.slice切分时不产生内存拷贝，底层共享一个byte数组。&lt;/li&gt;&#xA;&lt;li&gt;使用FileRegion实现文件传输，使用的FileChannel#transferTo()，直接将缓冲区数据输出到目标Channel，避免内核缓冲区和用户态缓冲区的数据拷贝。&lt;/li&gt;&#xA;&lt;/ol&gt;</description>
    </item>
    <item>
      <title>MinIO的分布式存储实践方案</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/minio/minio%E7%9A%84%E5%88%86%E5%B8%83%E5%BC%8F%E5%AD%98%E5%82%A8%E5%AE%9E%E8%B7%B5%E6%96%B9%E6%A1%88/</link>
      <pubDate>Fri, 19 Aug 2022 21:12:54 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/minio/minio%E7%9A%84%E5%88%86%E5%B8%83%E5%BC%8F%E5%AD%98%E5%82%A8%E5%AE%9E%E8%B7%B5%E6%96%B9%E6%A1%88/</guid>
      <description>&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;&#xA;&lt;p&gt;MinIO是一个开源的分布式对象存储组件，它兼容Amazon S3 API，适合于存储大容量的非结构化数据，支持单个对象最大5TB。&lt;/p&gt;&#xA;&lt;p&gt;MinIO特点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;部署简单，仅需要单独一个二进制文件&lt;/li&gt;&#xA;&lt;li&gt;支持纠删码机制，能恢复部分数据块丢失的情况。&lt;/li&gt;&#xA;&lt;li&gt;读写性能高&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/image-20220924181123151.png&#34; alt=&#34;MinIO Benchmark&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;基础原理&#34;&gt;基础原理&lt;/h2&gt;&#xA;&lt;h3 id=&#34;纠删码&#34;&gt;纠删码&lt;/h3&gt;&#xA;&lt;p&gt;纠删码是分布式存储领域常见的一种冗余技术，与副本机制相对比，纠删码拥有更高的磁盘利用率。纠删码的基本原理：通过&lt;strong&gt;纠删码算法&lt;/strong&gt;对原始数据进行计算，得到冗余的编码数据，并将数据和冗余编码一起存储，如果未来存储介质发生故障，导致其中部分数据出错，此时可以通过对应的重构算法，&lt;strong&gt;解码&lt;/strong&gt;出完整的原始数据，以达到容错的目的。即&lt;strong&gt;总数据块 = 原始块 + 校验快&lt;/strong&gt;($n = k + m$)。纠删码技术的磁盘利用率为$k / (k + m)$，允许总数据块中任意m个数据块损坏。&lt;/p&gt;&#xA;&lt;p&gt;上面提到的n、m的比值，是衡量纠删码的核心参数，这个值被称为冗余度，冗余度越高（校验快越多），允许丢失的数据块可以越多，同时数据存储成本也就越高。k值决定数据分块的粒度，k越小，数据分散度越小、重建代价越大。k值越大，数据拷贝的负载越大。常见的公有云独享存储的冗余度一般在&lt;code&gt;1.2-1.4&lt;/code&gt;左右。&lt;/p&gt;&#xA;&lt;p&gt;目前常用的纠删码算法：&lt;code&gt;Reed-Solomon&lt;/code&gt;，它有两个参数n和m，记为$RS(n , m)$。n代表原始数据块个数。m代表校验块个数。&lt;/p&gt;&#xA;&lt;p&gt;下图中是使用16块磁盘作为存储设备的情况，假设此时MinIOn持有16个磁盘，MinIO会将其中8块作为数据盘，另外八块作为校验盘，数据盘存储对象的原始数据，校验盘存储对象的校验数据。纠删码默认配置是&lt;strong&gt;1:1&lt;/strong&gt;，也就是将所有磁盘中的一半作为数据盘，一半做为校验盘。同时MinIO使用HighwayHash编码计算数据块的hash值，获取文件时会计算hash值来校验文件的准确性。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/erasure-code1.jpg&#34; alt=&#34;纠删码的磁盘布局&#34;&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;纠删码缺点&#xA;&lt;ul&gt;&#xA;&lt;li&gt;需要读取其他的数据块和校验块&lt;/li&gt;&#xA;&lt;li&gt;编码解码需要消耗CPU资源&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;纠删码优点&#xA;&lt;ul&gt;&#xA;&lt;li&gt;副本机制对于大文件机极其消耗磁盘空间，纠删码可以通过较少的磁盘冗余，较为高效的解决数据丢失的问题。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;应用场景&#xA;&lt;ul&gt;&#xA;&lt;li&gt;对于不被长期访问的冷数据，采用纠删码技术，可以大大减少副本数量。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;server-pool&#34;&gt;Server Pool&lt;/h3&gt;&#xA;&lt;p&gt;使用minio server指令创建的MinIO节点集合，提供对象存储和处理请求的功能。&lt;/p&gt;&#xA;&lt;p&gt;MinIO可以通过增加Server Pool的方式，实现集群的横向扩展。&lt;/p&gt;&#xA;&lt;p&gt;当有新的Server Pool加入Cluster，存储的元数据会进行同步，但是其他Server Pool已存储对象不会同步。&lt;/p&gt;&#xA;&lt;p&gt;举例：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;minio server https://minio{1&amp;hellip;4}.example.net/mnt/disk{1&amp;hellip;4}代表一个Server Pool，其中有四个server节点各有4块磁盘。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;minio server https://minio{1&amp;hellip;4}.example.net/mnt/disk{1&amp;hellip;4} https://minio{5&amp;hellip;8}.example.net/mnt/disk{1&amp;hellip;4}代表有两个Server Pool。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;MinIO选择Server Pool策略；选择剩余空间最大的Server Pool进行存储。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/image-20221113153730493.png&#34; alt=&#34;MinIO选择策略&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;存储级别&#34;&gt;存储级别&lt;/h3&gt;&#xA;&lt;p&gt;MinIO目前支持两种存储级别：Reduced Redundancy和Standard，提供两种不同的级别来修改数据块和校验块的比例。MinIO使用&lt;strong&gt;EC:N&lt;/strong&gt;来表示EC Set中存储校验块的磁盘数量，N越大，容错能力越强，但占用磁盘空间越多。&lt;/p&gt;&#xA;&lt;p&gt;可以通过在S3 Put API中添加x-amz-storage-class参数来指定当前文件的存储级别。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Standard：默认使用的存储级别，EC:N参数与Set中磁盘数量有关。可通过环境变量MINIO_STORAGE_CLASS_STANDARD=EC:N来设置，N不能大于磁盘数量的一半。&lt;/li&gt;&#xA;&lt;li&gt;Reduced Redundancy：使用比Standard级别更少的磁盘数量存储校验块。通过环境变量MINIO_STORAGE_CLASS_RRS=EC:N来设置。默认参数为EC:2&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/image-20221113154043570.png&#34; alt=&#34;存储级别设置&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Netty学习笔记(一)-概览</title>
      <link>http://localhost:1313/posts/netty/netty%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E4%B8%80-%E6%A6%82%E8%A7%88/</link>
      <pubDate>Sat, 06 Aug 2022 08:12:54 +0000</pubDate>
      <guid>http://localhost:1313/posts/netty/netty%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E4%B8%80-%E6%A6%82%E8%A7%88/</guid>
      <description>&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;&#xA;&lt;p&gt;Netty是一个应用于网络编程领域的NIO网络框架，通过屏蔽底层Socket编程细节，封装了提供上层业务使用的API，简化了网络应用的开发过程。Netty需要关注以下几点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;IO模型、线程模型&lt;/li&gt;&#xA;&lt;li&gt;事件处理机制&lt;/li&gt;&#xA;&lt;li&gt;API接口的使用&lt;/li&gt;&#xA;&lt;li&gt;数据协议、序列化的支持&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Netty的IO模型是基于非阻塞IO实现的，底层通过&lt;code&gt;JDK NIO&lt;/code&gt;中的&lt;code&gt;Selector&lt;/code&gt;实现，&lt;code&gt;Selector&lt;/code&gt;可以同时轮询多个&lt;code&gt;Channel&lt;/code&gt;，采用&lt;code&gt;epoll&lt;/code&gt;模式后只需要一个线程负责&lt;code&gt;Selector&lt;/code&gt;的轮询。&lt;/p&gt;&#xA;&lt;p&gt;IO多路复用的场景中，需要一个&lt;code&gt;Event Dispather&lt;/code&gt;负责将读写事件分发给对应的&lt;code&gt;Event Handler&lt;/code&gt;，事件分发器主要有两种：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Reactor：采用同步IO，实现简单，适用于处理耗时短的场景，耗时长的IO操作容易出现阻塞。&lt;/li&gt;&#xA;&lt;li&gt;Proactor：采用异步IO，实现逻辑复杂，性能更高&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Netty的优点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;易用：将NIO的API进一步封装，提供了开箱即用的工具&lt;/li&gt;&#xA;&lt;li&gt;稳定：修复了NIO的bug&lt;/li&gt;&#xA;&lt;li&gt;可扩展：可以通过启动参数选择Reactor线程模型&lt;/li&gt;&#xA;&lt;li&gt;低消耗：Netty性能优化&#xA;&lt;ul&gt;&#xA;&lt;li&gt;对象池复用&lt;/li&gt;&#xA;&lt;li&gt;零拷贝&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;nio基础&#34;&gt;NIO基础&lt;/h2&gt;&#xA;&lt;p&gt;NIO是一种同步非阻塞的IO模型，NIO与普通IO的最大区别就是非阻塞，通过每个线程通过Selector去监听多个Channel，并且读写数据是以块为单位，与BIO相比，大大提升了IO效率。&lt;/p&gt;&#xA;&lt;p&gt;BIO存在的问题：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;accept、read、write都是同步阻塞，处理IO时，线程阻塞。&lt;/li&gt;&#xA;&lt;li&gt;BIO模型严重依赖线程，线程资源比较宝贵。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Linux中用&lt;code&gt;task_struct&lt;/code&gt;管理，创建或销毁线程使用系统调用，开销大，并且进程切换也存在开销&lt;/li&gt;&#xA;&lt;li&gt;每个线程在JVM中占用1MB内存，连接数量大的时候，极易产生OOM&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Standard IO是对字节流进行读写，读写单位是字节，NIO将IO抽象成块，读写单位是块。&lt;/p&gt;&#xA;&lt;p&gt;基本概念：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Channel：对原IO包中流的模拟，可以通过它来读取和写入数据，数据流向是双向的。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;FileChannel：从文件中读取数据&lt;/li&gt;&#xA;&lt;li&gt;DatagramChannel：通过UDP读写网络数据&lt;/li&gt;&#xA;&lt;li&gt;SocketChannel：通过TCP读写网络数据&lt;/li&gt;&#xA;&lt;li&gt;ServerSocketChannel：监听新的TCP连接，对每个新连接都创建一个SocketChannel&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Buffer：Channel中的数据都需要通过Buffer进行传递，本质上是数组&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;ByteBuffer、CharBuffer等&lt;/li&gt;&#xA;&lt;li&gt;Buffer的内部变量：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;capacity：最大容量&lt;/li&gt;&#xA;&lt;li&gt;position：当前读写处的下标位置&lt;/li&gt;&#xA;&lt;li&gt;limit：还可读写的下标位置&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Selector：NIO采用的Reactor模型，一个线程使用一个Selector通过轮询的方式去监听多个Channel上面的事件，将Channel配置为非阻塞，那么Selector检测到当前Channel没有IO事件，就会轮询其他Channel。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;内存映射文件：是一种读写文件的方式，比常规基于流或者Channel的IO快。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//将文件的前1024字节映射到内存中，map()方法返回一个MappedByteBuffer&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;MappedByteBuffer mbb &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; fc.&lt;span style=&#34;color:#a6e22e&#34;&gt;map&lt;/span&gt;(FileChannel.&lt;span style=&#34;color:#a6e22e&#34;&gt;MapMode&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;READ_WRITE&lt;/span&gt;, 0, 1024);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;demo&#34;&gt;Demo&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SimpleServer&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;(String&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; args) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;         * ServerBootstrap：服务端启动器，负责组装、协调netty组件&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;         * NioEventLoopGroup：thread + selector&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;         * NioServerSocketChannel：对原生NIO的ServerSocketChannel封装&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;         * ChannelInitializer：对channel进行初始化&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;         */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ServerBootstrap()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .&lt;span style=&#34;color:#a6e22e&#34;&gt;group&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; NioEventLoopGroup())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .&lt;span style=&#34;color:#a6e22e&#34;&gt;channel&lt;/span&gt;(NioServerSocketChannel.&lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .&lt;span style=&#34;color:#a6e22e&#34;&gt;childHandler&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ChannelInitializer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;NioSocketChannel&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#75715e&#34;&gt;//连接建立后执行initChannel&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;initChannel&lt;/span&gt;(NioSocketChannel ch) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; Exception {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#75715e&#34;&gt;//StringDecoder：将Bytebuffer转为string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        ch.&lt;span style=&#34;color:#a6e22e&#34;&gt;pipeline&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;addLast&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; StringDecoder());&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        &lt;span style=&#34;color:#75715e&#34;&gt;//自定义handler&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        ch.&lt;span style=&#34;color:#a6e22e&#34;&gt;pipeline&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;addLast&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ChannelInboundHandlerAdapter() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;channelRead&lt;/span&gt;(ChannelHandlerContext ctx, Object msg) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; Exception {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(msg);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        });&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                })&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .&lt;span style=&#34;color:#a6e22e&#34;&gt;bind&lt;/span&gt;(8080);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SimpleClient&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;(String&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; args) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; IOException, InterruptedException {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Bootstrap()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .&lt;span style=&#34;color:#a6e22e&#34;&gt;group&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; NioEventLoopGroup())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .&lt;span style=&#34;color:#a6e22e&#34;&gt;channel&lt;/span&gt;(NioSocketChannel.&lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .&lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ChannelInitializer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;NioSocketChannel&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;initChannel&lt;/span&gt;(NioSocketChannel ch) &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; Exception {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                        ch.&lt;span style=&#34;color:#a6e22e&#34;&gt;pipeline&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;addLast&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; StringEncoder());&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                })&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .&lt;span style=&#34;color:#a6e22e&#34;&gt;connect&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; InetSocketAddress(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;localhost&amp;#34;&lt;/span&gt;, 8080))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;//阻塞直到连接建立&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .&lt;span style=&#34;color:#a6e22e&#34;&gt;sync&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;//代表连接对象&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .&lt;span style=&#34;color:#a6e22e&#34;&gt;channel&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;//发送数据&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                .&lt;span style=&#34;color:#a6e22e&#34;&gt;writeAndFlush&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hello world&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;netty组件&#34;&gt;Netty组件&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Core：提供了底层网络通信的抽象和实现，支持零拷贝的ByteBuffer、可扩展的事件模型、通信API。&lt;/li&gt;&#xA;&lt;li&gt;协议支持层：对主流协议的编解码实现，包括：HTTP、SSL、Protobuf等，还支持自定义应用层协议。&lt;/li&gt;&#xA;&lt;li&gt;传输服务层：提供了网络传输能力的抽象和实现，支持Socket、HTTP tunnel、VM pipe等方式&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/components.png&#34; alt=&#34;netty-components&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Linux文件管理模块分析</title>
      <link>http://localhost:1313/posts/linux/linux%E6%96%87%E4%BB%B6%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97%E5%88%86%E6%9E%90/</link>
      <pubDate>Sat, 23 Jul 2022 09:52:49 +0000</pubDate>
      <guid>http://localhost:1313/posts/linux/linux%E6%96%87%E4%BB%B6%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97%E5%88%86%E6%9E%90/</guid>
      <description>&lt;h2 id=&#34;硬盘文件系统&#34;&gt;硬盘文件系统&lt;/h2&gt;&#xA;&lt;h3 id=&#34;inode与块的存储&#34;&gt;inode与块的存储&lt;/h3&gt;&#xA;&lt;p&gt;硬盘读写时以扇区为单位，文件系统中读写数据最小单位为块，一个块（簇）内部是相邻的几个扇区，在Linux中的ext文件系统，默认大小为4K。&lt;/p&gt;&#xA;&lt;p&gt;文件的元数据存放在inode中，ext4中定义如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; ext4_inode {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;__le16&#x9;i_mode;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;/* File mode */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;__le16&#x9;i_uid;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;/* Low 16 bits of Owner Uid */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;__le32&#x9;i_size_lo;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;/* Size in bytes */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;__le32&#x9;i_atime;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;/* Access time */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;__le32&#x9;i_ctime;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;/* Inode Change time */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;__le32&#x9;i_mtime;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;/* Modification time */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;__le32&#x9;i_dtime;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;/* Deletion Time */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;__le16&#x9;i_gid;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;/* Low 16 bits of Group Id */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;__le16&#x9;i_links_count;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;/* Links count */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;__le32&#x9;i_blocks_lo;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;/* Blocks count */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;__le32&#x9;i_flags;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;/* File flags */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;......&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;__le32&#x9;i_block[EXT4_N_BLOCKS];&lt;span style=&#34;color:#75715e&#34;&gt;/* Pointers to blocks */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;__le32&#x9;i_generation;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;/* File version (for NFS) */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;__le32&#x9;i_file_acl_lo;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;/* File ACL */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;__le32&#x9;i_size_high;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;......&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define&#x9;EXT4_NDIR_BLOCKS&#x9;&#x9;12&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define&#x9;EXT4_IND_BLOCK&#x9;&#x9;&#x9;EXT4_NDIR_BLOCKS&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define&#x9;EXT4_DIND_BLOCK&#x9;&#x9;&#x9;(EXT4_IND_BLOCK + 1)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define&#x9;EXT4_TIND_BLOCK&#x9;&#x9;&#x9;(EXT4_DIND_BLOCK + 1)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define&#x9;EXT4_N_BLOCKS&#x9;&#x9;&#x9;(EXT4_TIND_BLOCK + 1)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;i_block&lt;/code&gt;中存放文件所在的磁盘块地址，可以通过多层寻址增加文件大小上限。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Linux内存管理模块分析</title>
      <link>http://localhost:1313/posts/linux/linux%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97%E5%88%86%E6%9E%90/</link>
      <pubDate>Sun, 17 Jul 2022 09:52:49 +0000</pubDate>
      <guid>http://localhost:1313/posts/linux/linux%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97%E5%88%86%E6%9E%90/</guid>
      <description>&lt;h2 id=&#34;概述&#34;&gt;概述&lt;/h2&gt;&#xA;&lt;p&gt;内存管理主要分为三个方面：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;管理物理内存：只有内核中负责内存管理的模块可以使用&lt;/li&gt;&#xA;&lt;li&gt;管理虚拟内存：每个进程看到的都是独立且互不干扰的虚拟空间&lt;/li&gt;&#xA;&lt;li&gt;物理内存和虚拟内存的转换：上述两者的映射关系&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;无论是内核态程序还是用户态程序，都使用虚拟内存，虚拟内存空间布局如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/image-20220723131749685.png&#34; alt=&#34;Linux-Process-Virtual-Memory&#34;&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;内核空间部分：存放内核进程的程序&lt;/li&gt;&#xA;&lt;li&gt;用户空间部分：存放用户进程的程序，从最低位开始，逐个段如下：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Text Segment：存放二进制可执行代码的位置&lt;/li&gt;&#xA;&lt;li&gt;Data Segment：存放静态常量&lt;/li&gt;&#xA;&lt;li&gt;BSS Segment：存放未初始化的静态变量&lt;/li&gt;&#xA;&lt;li&gt;Heap：动态分配内存的区域，malloc在这个空间分配&lt;/li&gt;&#xA;&lt;li&gt;Memory Mapping Segment：用来把文件映射到内存的区域，如果可执行文件依赖某个动态链接库，so文件就映射在这。&lt;/li&gt;&#xA;&lt;li&gt;Stack：进程的函数调用栈，由一个个frame（相当于函数实体）构成，内部存放局部变量、返回地址等信息，frame结构如下图所示：&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/image-20220717113852718.png&#34; alt=&#34;stack-frame&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;可以通过&lt;code&gt;pmap pid&lt;/code&gt;展示进程的地址空间相关信息。&lt;/p&gt;&#xA;&lt;h2 id=&#34;基本概念&#34;&gt;基本概念&lt;/h2&gt;&#xA;&lt;h3 id=&#34;分段机制&#34;&gt;分段机制&lt;/h3&gt;&#xA;&lt;p&gt;分段机制如下图所示：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/image-20220717133205056.png&#34; alt=&#34;分段机制&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;在Linux中，段表被称为&lt;strong&gt;段描述符表&lt;/strong&gt;，放在&lt;strong&gt;全局描述符表 GDT&lt;/strong&gt;中，一个段表项由段基址base，界限limit，还有一些标识符组成：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;DEFINE_PER_CPU_PAGE_ALIGNED&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; gdt_page, gdt_page) &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; { .gdt &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#ifdef CONFIG_X86_64&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&#x9;[GDT_ENTRY_KERNEL32_CS]&#x9;&#x9;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GDT_ENTRY_INIT&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0xc09b&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0xfffff&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;[GDT_ENTRY_KERNEL_CS]&#x9;&#x9;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GDT_ENTRY_INIT&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0xa09b&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0xfffff&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;[GDT_ENTRY_KERNEL_DS]&#x9;&#x9;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GDT_ENTRY_INIT&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0xc093&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0xfffff&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;[GDT_ENTRY_DEFAULT_USER32_CS]&#x9;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GDT_ENTRY_INIT&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0xc0fb&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0xfffff&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;[GDT_ENTRY_DEFAULT_USER_DS]&#x9;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GDT_ENTRY_INIT&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0xc0f3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0xfffff&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;[GDT_ENTRY_DEFAULT_USER_CS]&#x9;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GDT_ENTRY_INIT&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0xa0fb&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0xfffff&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#else&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&#x9;[GDT_ENTRY_KERNEL_CS]&#x9;&#x9;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GDT_ENTRY_INIT&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0xc09a&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0xfffff&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;[GDT_ENTRY_KERNEL_DS]&#x9;&#x9;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GDT_ENTRY_INIT&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0xc092&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0xfffff&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;[GDT_ENTRY_DEFAULT_USER_CS]&#x9;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GDT_ENTRY_INIT&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0xc0fa&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0xfffff&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;[GDT_ENTRY_DEFAULT_USER_DS]&#x9;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GDT_ENTRY_INIT&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0xc0f2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0xfffff&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;......&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#endif&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;} };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;EXPORT_PER_CPU_SYMBOL_GPL&lt;/span&gt;(gdt_page);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define __KERNEL_CS&#x9;&#x9;&#x9;(GDT_ENTRY_KERNEL_CS*8)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define __KERNEL_DS&#x9;&#x9;&#x9;(GDT_ENTRY_KERNEL_DS*8)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define __USER_DS&#x9;&#x9;&#x9;(GDT_ENTRY_DEFAULT_USER_DS*8 + 3)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define __USER_CS&#x9;&#x9;&#x9;(GDT_ENTRY_DEFAULT_USER_CS*8 + 3)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;分段机制在Linux中，可以做权限审核，用户态试图访问内核态，权限不足会禁止访问。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Linux进程管理模块分析</title>
      <link>http://localhost:1313/posts/linux/linux%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97%E5%88%86%E6%9E%90/</link>
      <pubDate>Thu, 14 Jul 2022 23:31:46 +0000</pubDate>
      <guid>http://localhost:1313/posts/linux/linux%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86%E6%A8%A1%E5%9D%97%E5%88%86%E6%9E%90/</guid>
      <description>&lt;h2 id=&#34;二进制程序执行&#34;&gt;二进制程序执行&lt;/h2&gt;&#xA;&lt;h3 id=&#34;编译过程&#34;&gt;编译过程&lt;/h3&gt;&#xA;&lt;p&gt;源代码文件会经过以下的步骤生成可执行文件（CSAPP）：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;预处理：预处理过程会将头文件嵌入代码中，定义宏展开，生成&lt;code&gt;.i&lt;/code&gt;文件&lt;/li&gt;&#xA;&lt;li&gt;编译：编译生成汇编语言程序,生成&lt;code&gt;.s&lt;/code&gt;文件&lt;/li&gt;&#xA;&lt;li&gt;汇编：汇编器as将汇编语言翻译成机器指令，打包成&lt;code&gt;.o&lt;/code&gt;文件，这被称为&lt;code&gt;Relocatable File&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;链接：链接器ld将链接库和重定位文件合并，生成可执行文件&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;编译&#34;&gt;编译&lt;/h3&gt;&#xA;&lt;p&gt;&lt;code&gt;process.c&lt;/code&gt;内容如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;sys/types.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;extern&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;create_process&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; program, &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;**&lt;/span&gt; arg_list);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;create_process&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; program, &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;**&lt;/span&gt; arg_list)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;pid_t&lt;/span&gt; child_pid;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    child_pid &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fork&lt;/span&gt; ();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (child_pid &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; child_pid;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;execvp&lt;/span&gt; (program, arg_list);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;abort&lt;/span&gt; ();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;createprocess.c&lt;/code&gt;内容如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;sys/types.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;extern&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;create_process&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; program, &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;**&lt;/span&gt; arg_list);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt; ()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; arg_list[] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ls&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-l&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/opt/&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        NULL&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;create_process&lt;/span&gt; (&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ls&amp;#34;&lt;/span&gt;, arg_list);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;编译上面两个文件，生成&lt;code&gt;.o&lt;/code&gt;文件&lt;/p&gt;</description>
    </item>
    <item>
      <title>短网址系统设计总结</title>
      <link>http://localhost:1313/posts/%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/%E7%9F%AD%E7%BD%91%E5%9D%80%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1%E6%80%BB%E7%BB%93/</link>
      <pubDate>Sun, 10 Jul 2022 14:29:01 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/%E7%9F%AD%E7%BD%91%E5%9D%80%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1%E6%80%BB%E7%BB%93/</guid>
      <description>&lt;h2 id=&#34;需求评估&#34;&gt;需求评估&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;输入数据：一个长网址、过期时间和一个自定义的别名&lt;/li&gt;&#xA;&lt;li&gt;输出数据：自定义别名或者随机生成的短网址，过期时间之前访问都会被重定向到原始地址。&lt;/li&gt;&#xA;&lt;li&gt;读多写少&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;实现原理：将短网址redirect到长网址（301/302跳转）&lt;/p&gt;&#xA;&lt;p&gt;约束：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;过期即失效&lt;/li&gt;&#xA;&lt;li&gt;短网址唯一&lt;/li&gt;&#xA;&lt;li&gt;支持自定义短网址&lt;/li&gt;&#xA;&lt;li&gt;QPS要求、低延迟、可靠性、安全性&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;系统设计&#34;&gt;系统设计&lt;/h2&gt;&#xA;&lt;h3 id=&#34;可行解&#34;&gt;可行解&lt;/h3&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;写&#xA;&lt;ol&gt;&#xA;&lt;li&gt;输入长域名，判断是否存在&lt;/li&gt;&#xA;&lt;li&gt;生成一个未使用的短网址，并进行持久化&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;读&#xA;&lt;ol&gt;&#xA;&lt;li&gt;获取短网址，判断是否过期&lt;/li&gt;&#xA;&lt;li&gt;正常则返回短网址&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;其他方面：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;使用延迟删除策略清理过期数据&lt;/li&gt;&#xA;&lt;li&gt;读时消重：返回的时候过滤重复元素&lt;/li&gt;&#xA;&lt;li&gt;写时消重：写时判断以避免重复写入&lt;/li&gt;&#xA;&lt;li&gt;短网址生成算法：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;UUID：无法保证唯一性&lt;/li&gt;&#xA;&lt;li&gt;哈希：MurMurHash等方法，无法保证唯一性，考虑转为62进制&lt;/li&gt;&#xA;&lt;li&gt;ID：使用7位62进制，即长度为7，由大小写字母加数字共62个字符组成&lt;/li&gt;&#xA;&lt;li&gt;雪花算法：转为62进制&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;用户自定义：记录正在使用的ID，写入时判断是否存在&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;MySQL表结构如下：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th style=&#34;text-align: center&#34;&gt;id&lt;/th&gt;&#xA;          &lt;th&gt;long_url&lt;/th&gt;&#xA;          &lt;th&gt;short_url&lt;/th&gt;&#xA;          &lt;th&gt;expire_time&lt;/th&gt;&#xA;          &lt;th&gt;create_time&lt;/th&gt;&#xA;          &lt;th&gt;delete_time&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;Redis键值设计：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;k：长网址, v：短网址&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;吞吐量优化&#34;&gt;吞吐量优化&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;水平扩展&lt;/strong&gt;：使用Nginx做负载均衡&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;存储层&lt;/strong&gt;：MySQL替换为持久化KV存储，比如RocksDB，若存在数据分析的需求，可以添加数仓&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;索引优化&lt;/strong&gt;：两个方面&#xA;&lt;ol&gt;&#xA;&lt;li&gt;写入时判需要判断长网址是否存在&lt;/li&gt;&#xA;&lt;li&gt;读取时根据短网址查询长网址&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;分片&lt;/strong&gt;：短网址进行一致性哈希等方式计算分片位置。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;缓存层&lt;/strong&gt;：&lt;strong&gt;读多写少&lt;/strong&gt;的系统使用缓存优化QPS&#xA;&lt;ul&gt;&#xA;&lt;li&gt;使用bloom filter检查长网址是否存储，短网址是否分配&lt;/li&gt;&#xA;&lt;li&gt;直接在本地设计缓存&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;业务层&lt;/strong&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;分布式ID生成需要考虑&lt;strong&gt;数据一致性&lt;/strong&gt;问题&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;网络层&lt;/strong&gt;：降低&lt;strong&gt;广域延迟&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;可靠性优化&#34;&gt;可靠性优化&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;存储层：考虑主从副本机制，增加数据可靠性&lt;/li&gt;&#xA;&lt;li&gt;提供跨机房的数据冗余备份，通过log同步数据&lt;/li&gt;&#xA;&lt;li&gt;监控业务集群，实现熔断、限流、扩容缩容等&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;安全性优化&#34;&gt;安全性优化&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;避免使用自增，防止逐个遍历&lt;/li&gt;&#xA;&lt;li&gt;防止DDos，对接口做限流，增加IP黑名单机制&lt;/li&gt;&#xA;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Kafka学习笔记(四)-集群工作机制</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E5%9B%9B-%E9%9B%86%E7%BE%A4%E5%B7%A5%E4%BD%9C%E6%9C%BA%E5%88%B6/</link>
      <pubDate>Wed, 06 Jul 2022 18:49:22 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E5%9B%9B-%E9%9B%86%E7%BE%A4%E5%B7%A5%E4%BD%9C%E6%9C%BA%E5%88%B6/</guid>
      <description>&lt;h2 id=&#34;controller机制&#34;&gt;Controller机制&lt;/h2&gt;&#xA;&lt;p&gt;Controller主要作用是在Zookeeper的帮助下管理和协调整个Kafka集群（在zk中存储集群元数据）。Kafka集群中会有一个或多个Broker，其中一个Broker会被选举为Controller，它负责管理整个集群中所有分区和副本的状态，其工作职责包括以下内容：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Topic管理&lt;/strong&gt;：完成对Kafka的Topic的创建删除、分区增加等操作。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;分区重分配&lt;/strong&gt;：新的Broker加入集群时，不会自动分担已有的topic负载，只会对后续的topic生效，此时如果需要对已有topic负载，需要用户手动进行&lt;strong&gt;分区重分配&lt;/strong&gt;。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Leader选举&lt;/strong&gt;：负责Partition Leader选举的工作&lt;/li&gt;&#xA;&lt;li&gt;集群成员管理：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Kafka 使用Zookeeper的临时节点来选举Controller&lt;/li&gt;&#xA;&lt;li&gt;Zookeeper在Broker加入集群或退出集群时通知Controller&lt;/li&gt;&#xA;&lt;li&gt;Controller负责在Broker加入或离开集群时进行分区Leader选举&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;元数据管理：Controller负责管理集群中所有的元数据&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Controller选举流程：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;每个Broker启动时，都会尝试读取&lt;code&gt;/controller&lt;/code&gt;节点的brokerid的值，如果值不为-1，则表明已经有其他broker节点成为Controller，当前broker放弃选举&lt;/li&gt;&#xA;&lt;li&gt;如果不存在&lt;code&gt;/controller&lt;/code&gt;节点或节点数据异常，则主动创建节点并存储brokerid&lt;/li&gt;&#xA;&lt;li&gt;其他broker会将选举成功的Brokerid都在内存保存下来&lt;/li&gt;&#xA;&lt;li&gt;同时使用&lt;code&gt;/controller_epoch&lt;/code&gt;持久性节点来记录任期号，记录Controller发生变化的次数，类似于Raft中的任期。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;初始值为1，每个与Controller交互的请求都会携带&lt;code&gt;controller_epoch&lt;/code&gt;，如果请求的&lt;code&gt;controller_epoch&lt;/code&gt;大于内存中&lt;code&gt;controller_epoch&lt;/code&gt;，说明内存中的值过期了，目前已有新的Controller当选。&lt;/li&gt;&#xA;&lt;li&gt;由两部分组成：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;epoch：单调递增的版本号，leader发生变更，进行自增&lt;/li&gt;&#xA;&lt;li&gt;start offset：Leader副本在该Epoch值上写入的首条消息的位移。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;每个分区都缓存该值，并定期持久化到&lt;code&gt;checkpoint&lt;/code&gt;文件中&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;partition-leader选举&#34;&gt;Partition Leader选举&lt;/h3&gt;&#xA;&lt;p&gt;Controller拥有选举分区Leader的功能，每个分区都会有一个Broker作为Leader，处理所有的读写请求，选举流程由Controller负责：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Controller从ZK中读取当前分区所有的ISR集合&lt;/li&gt;&#xA;&lt;li&gt;调用配置的分区选择算法选举分区的Leader&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;code&gt;Partition Leader&lt;/code&gt;的定义如下：&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Each partition has one server which acts as the &amp;ldquo;leader&amp;rdquo; and zero or more servers which act as &amp;ldquo;followers&amp;rdquo;. The leader handles all read and write requests for the partition while the followers passively replicate the leader. If the leader fails, one of the followers will automatically become the new leader. Each server acts as a leader for some of its partitions and a follower for others so load is well balanced within the cluster.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kafka学习笔记(三)-通信协议</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E4%B8%89-%E9%80%9A%E4%BF%A1%E5%8D%8F%E8%AE%AE/</link>
      <pubDate>Sun, 03 Jul 2022 10:49:22 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E4%B8%89-%E9%80%9A%E4%BF%A1%E5%8D%8F%E8%AE%AE/</guid>
      <description>&lt;h2 id=&#34;协议设计&#34;&gt;协议设计&lt;/h2&gt;&#xA;&lt;p&gt;需要进行网络传输的中间件都会拥有自己的一套通信协议，这往往会成为该组件的性能瓶颈，需要考虑的优化点较多。Kafka自定义了基于TCP的二进制通信协议，Kafka2.0中，一共有43种协议类型，每个都有对应的请求和响应，与HTTP协议类似，它同样有&lt;code&gt;RequestHeader&lt;/code&gt;和&lt;code&gt;RequestBody&lt;/code&gt;。其中&lt;code&gt;RequestHeader&lt;/code&gt;结构如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;api_key：API标识，例如PRODUCE、FETCH等，用于分别请求的作用。&lt;/li&gt;&#xA;&lt;li&gt;api_version：API版本号&lt;/li&gt;&#xA;&lt;li&gt;correlation_id：客户端指定的唯一标识，服务端返回响应需要将该字段返回以此对应。&lt;/li&gt;&#xA;&lt;li&gt;client_id：客户端id&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Kafka除了提供基本数据类型，还提供了以下的特有类型：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;nullable_string：可为空的字符串类型，若为空用-1表示&lt;/li&gt;&#xA;&lt;li&gt;bytes：表示字节序列，开头是数据长度N（int32表示），后面是N个字节&lt;/li&gt;&#xA;&lt;li&gt;nullable_bytes：与上述string相同&lt;/li&gt;&#xA;&lt;li&gt;records：表示Kafka中的消息序列&lt;/li&gt;&#xA;&lt;li&gt;array：表示一个给定类型T的数组&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;code&gt;RequestBody&lt;/code&gt;结构如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;transactional_id：事务id，不使用事务，此项为null&lt;/li&gt;&#xA;&lt;li&gt;acks：对应客户端的acks参数&lt;/li&gt;&#xA;&lt;li&gt;timeout：超时时间&lt;/li&gt;&#xA;&lt;li&gt;topic_data：要发送的数据集合，array类型&#xA;&lt;ul&gt;&#xA;&lt;li&gt;topic：主题&lt;/li&gt;&#xA;&lt;li&gt;data：数据，array类型&#xA;&lt;ul&gt;&#xA;&lt;li&gt;partition：分区编号&lt;/li&gt;&#xA;&lt;li&gt;record_set：数据&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;code&gt;Response&lt;/code&gt;结构如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;ResponseHeader&#xA;&lt;ul&gt;&#xA;&lt;li&gt;correlation_id：与请求相对应&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;ResponseBody&#xA;&lt;ul&gt;&#xA;&lt;li&gt;responses：array类型，返回的响应结果&#xA;&lt;ul&gt;&#xA;&lt;li&gt;topic：主题&lt;/li&gt;&#xA;&lt;li&gt;partition_responses：返回结果，array类型&#xA;&lt;ul&gt;&#xA;&lt;li&gt;partition：分区编号&lt;/li&gt;&#xA;&lt;li&gt;error_code：错误码，用来标识错误类型&lt;/li&gt;&#xA;&lt;li&gt;base_offset：消息集的起始偏移量&lt;/li&gt;&#xA;&lt;li&gt;log_append_time：消息写入broker的时间&lt;/li&gt;&#xA;&lt;li&gt;log_start_offset：所在分区起始偏移量&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>分析Linux中的Zero-Copy技术</title>
      <link>http://localhost:1313/posts/linux/%E5%88%86%E6%9E%90zero-copy%E6%8A%80%E6%9C%AF/</link>
      <pubDate>Thu, 30 Jun 2022 20:33:10 +0000</pubDate>
      <guid>http://localhost:1313/posts/linux/%E5%88%86%E6%9E%90zero-copy%E6%8A%80%E6%9C%AF/</guid>
      <description>&lt;h2 id=&#34;传统io的流程&#34;&gt;传统IO的流程&lt;/h2&gt;&#xA;&lt;p&gt;零拷贝技术是对传统IO的性能优化，在介绍零拷贝之前，先简单了解一下传统IO中，数据流向的过程：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;用户进程发起&lt;code&gt;read()&lt;/code&gt;调用，从用户态切换至内核态，DMA从文件中读取数据，并存储在IO Buffer（内核态）&lt;/li&gt;&#xA;&lt;li&gt;请求得到的数据从IO Buffer拷贝到用户态Buffer（从内核态切换到用户态），然后返回给用户进程。&lt;/li&gt;&#xA;&lt;li&gt;用户进程调用&lt;code&gt;write()&lt;/code&gt;将数据输出到网卡中，此时将从用户态切换到内核态，请求数据从用户进程空间拷贝到Socket Buffer。&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;write()&lt;/code&gt;调用结束后返回用户进程，此时从内核态切换到用户态。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;整个过程中涉及4次上下文切换、4次数据拷贝（2次CPU拷贝 + 2次DMA拷贝）。&lt;/p&gt;&#xA;&lt;p&gt;我们需要对该流程进行优化，以提高IO的性能，因此诞生了零拷贝的概念。&lt;/p&gt;&#xA;&lt;h2 id=&#34;零拷贝&#34;&gt;零拷贝&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&amp;ldquo;&lt;strong&gt;Zero-copy&lt;/strong&gt;&amp;rdquo; describes &lt;a href=&#34;https://en.wikipedia.org/wiki/Computer&#34;&gt;computer&lt;/a&gt; operations in which the &lt;a href=&#34;https://en.wikipedia.org/wiki/Central_processing_unit&#34;&gt;CPU&lt;/a&gt; does not perform the task of copying data from one &lt;a href=&#34;https://en.wikipedia.org/wiki/RAM&#34;&gt;memory&lt;/a&gt; area to another or in which unnecessary data copies are avoided. This is frequently used to save CPU cycles and memory bandwidth in many time consuming tasks, such as when transmitting a &lt;a href=&#34;https://en.wikipedia.org/wiki/Computer_file&#34;&gt;file&lt;/a&gt; at high speed over a &lt;a href=&#34;https://en.wikipedia.org/wiki/Telecommunications_network&#34;&gt;network&lt;/a&gt;, etc., thus improving &lt;a href=&#34;https://en.wikipedia.org/wiki/Computer_performance&#34;&gt;performances&lt;/a&gt; of &lt;a href=&#34;https://en.wikipedia.org/wiki/Computer_program&#34;&gt;programs&lt;/a&gt; (&lt;a href=&#34;https://en.wikipedia.org/wiki/Process_(computing)&#34;&gt;processes&lt;/a&gt;) executed by a computer.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kafka学习笔记(二)-存储架构</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E4%BA%8C-%E5%AD%98%E5%82%A8%E7%BB%93%E6%9E%84/</link>
      <pubDate>Wed, 29 Jun 2022 20:06:22 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E4%BA%8C-%E5%AD%98%E5%82%A8%E7%BB%93%E6%9E%84/</guid>
      <description>&lt;h1 id=&#34;kafka存储架构&#34;&gt;Kafka存储架构&lt;/h1&gt;&#xA;&lt;p&gt;Kafka是为了解决大数据量的实时日志流而产生的，日志流主要特点包括：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;数据实时存储&lt;/li&gt;&#xA;&lt;li&gt;海量数据存储与处理&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Kafka需要保证以下几点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;存储的主要是消息流&lt;/li&gt;&#xA;&lt;li&gt;要保证海量数据的高效存储&lt;/li&gt;&#xA;&lt;li&gt;要支持海量数据的高效检索&lt;/li&gt;&#xA;&lt;li&gt;要保证数据的安全性和稳定性&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Kafka使用的存储方案是：磁盘顺序写 + 稀疏哈希索引。&lt;/p&gt;&#xA;&lt;h2 id=&#34;日志目录布局&#34;&gt;日志目录布局&lt;/h2&gt;&#xA;&lt;p&gt;Kafka中消息以Topic为单位归类，各个Topic下面分为多个分区，分区中每条消息都会被分配一个唯一的序列号（offset）。日志命名方式为：&lt;code&gt;&amp;lt;topic&amp;gt;-&amp;lt;partition&amp;gt;&lt;/code&gt;&lt;/p&gt;&#xA;&lt;p&gt;在不考虑多副本的情况下，一个分区对应一个Log，为了防止Log过大，Kafka引入&lt;code&gt;LogSegment&lt;/code&gt;，将Log切分为多个&lt;code&gt;LogSegment&lt;/code&gt;。其结构如下所示：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Log&#xA;&lt;ul&gt;&#xA;&lt;li&gt;LogSegment：每个 LogSegment 都有一个基准偏移量 baseOffset，用来表示当前 LogSegment中第一条消息的offset。只有最后一个LogSegment才能写入。下述文件根据&lt;code&gt;baseOffset&lt;/code&gt;命名，长度固定为20位数字，没有达到的位数用0填充。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;.log：日志文件&lt;/li&gt;&#xA;&lt;li&gt;.index：偏移量索引文件&lt;/li&gt;&#xA;&lt;li&gt;.timeindex：时间戳索引文件&lt;/li&gt;&#xA;&lt;li&gt;.snapshot：快照索引文件&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;消息格式&#34;&gt;消息格式&lt;/h2&gt;&#xA;&lt;p&gt;消息格式关系到存储性能，比如冗余字段会增加分区的存储空间、网络传输的开销较大。&lt;/p&gt;&#xA;&lt;p&gt;Kafka3.0中将&lt;code&gt;BatchRecords&lt;/code&gt;作为磁盘中的存储单元，一个&lt;code&gt;BatchRecords&lt;/code&gt;中包含多个&lt;code&gt;Record&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;BatchRecords&lt;/code&gt;的格式如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;baseOffset: int64&#xA;batchLength: int32&#xA;partitionLeaderEpoch: int32&#xA;magic: int8 (current magic value is 2)&#xA;crc: int32&#xA;attributes: int16&#xA;    bit 0~2:&#xA;        0: no compression&#xA;        1: gzip&#xA;        2: snappy&#xA;        3: lz4&#xA;        4: zstd&#xA;    bit 3: timestampType&#xA;    bit 4: isTransactional (0 means not transactional)&#xA;    bit 5: isControlBatch (0 means not a control batch)&#xA;    bit 6: hasDeleteHorizonMs (0 means baseTimestamp is not set as the delete horizon for compaction)&#xA;    bit 7~15: unused&#xA;lastOffsetDelta: int32&#xA;baseTimestamp: int64&#xA;maxTimestamp: int64&#xA;producerId: int64&#xA;producerEpoch: int16&#xA;baseSequence: int32&#xA;records: [Record]&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;字段解释如下：&lt;/p&gt;</description>
    </item>
    <item>
      <title>小记-构建RPM包</title>
      <link>http://localhost:1313/posts/linux/%E5%B0%8F%E8%AE%B0-%E6%9E%84%E5%BB%BArpm%E5%8C%85/</link>
      <pubDate>Mon, 27 Jun 2022 18:38:46 +0000</pubDate>
      <guid>http://localhost:1313/posts/linux/%E5%B0%8F%E8%AE%B0-%E6%9E%84%E5%BB%BArpm%E5%8C%85/</guid>
      <description>&lt;h2 id=&#34;准备工作&#34;&gt;准备工作&lt;/h2&gt;&#xA;&lt;p&gt;OS环境与rpm版本号如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[root@localhost ~]# uname -a&#xD;&#xA;Linux localhost.localdomain 3.10.0-693.el7.x86_64 #1 SMP Tue Aug 22 21:09:27 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux&#xD;&#xA;&#xD;&#xA;[root@localhost ~]# rpm --version&#xD;&#xA;RPM 版本 4.11.3&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;安装rpm-build&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;yum install -y rpm-build&#x9;# 构建的rpm的核心组件&#xD;&#xA;yum install -y rpmdevtools  # 提供了构建rpm包的一些工具&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;查看工作目录：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[root@localhost rpmbuild]# rpmbuild --showrc | grep topdir&#xD;&#xA;-14: _builddir&#x9;%{_topdir}/BUILD&#xD;&#xA;-14: _buildrootdir&#x9;%{_topdir}/BUILDROOT&#xD;&#xA;-14: _rpmdir&#x9;%{_topdir}/RPMS&#xD;&#xA;-14: _sourcedir&#x9;%{_topdir}/SOURCES&#xD;&#xA;-14: _specdir&#x9;%{_topdir}/SPECS&#xD;&#xA;-14: _srcrpmdir&#x9;%{_topdir}/SRPMS&#xD;&#xA;-14: _topdir&#x9;%{getenv:HOME}/rpmbuild&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;工作目录位于&lt;code&gt;$HOME/rpmbuild&lt;/code&gt;，在该目录下创建以下文件夹、或直接使用&lt;code&gt;rpmdev-setuptree&lt;/code&gt;生成目录：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[root@localhost rpmbuild]# mkdir -pv /root/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;目录的各个用途如下：&lt;/p&gt;</description>
    </item>
    <item>
      <title>使用Prometheus &#43; Grafana 构建监控可视化系统</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/prometheus/%E4%BD%BF%E7%94%A8prometheus-&#43;-grafana-%E6%9E%84%E5%BB%BA%E7%9B%91%E6%8E%A7%E5%8F%AF%E8%A7%86%E5%8C%96%E7%B3%BB%E7%BB%9F/</link>
      <pubDate>Sat, 11 Jun 2022 13:02:34 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/prometheus/%E4%BD%BF%E7%94%A8prometheus-&#43;-grafana-%E6%9E%84%E5%BB%BA%E7%9B%91%E6%8E%A7%E5%8F%AF%E8%A7%86%E5%8C%96%E7%B3%BB%E7%BB%9F/</guid>
      <description>&lt;h1 id=&#34;监控系统简介&#34;&gt;监控系统简介&lt;/h1&gt;&#xA;&lt;p&gt;业务监控系统通常包含以下一些组件：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;采集&lt;/strong&gt;：信息源来自log、metrics等。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;可以通过定期外围探测、AOP手动织入、字节码自动织入&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;上报&lt;/strong&gt;：通过http或者tcp&lt;/li&gt;&#xA;&lt;li&gt;聚合&lt;/li&gt;&#xA;&lt;li&gt;存储&lt;/li&gt;&#xA;&lt;li&gt;可视化、告警&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;业务监控系统解决了什么问题？&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;趋势分析：收集长期监控数据，对监控指标进行趋势分析，例如：分析磁盘空间增长率，预测何时进行磁盘扩容。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;对照分析：分析不同版本在运行时资源使用情况差异。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;告警：当服务出现故障时，监控可以迅速反应并告警。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;故障分析与定位：故障发生时，可以通过分析历史数据去定位问题。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;数据可视化：通过采集的数据，生成可视化仪表盘。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;对于运维：监控CPU、内存、硬盘等使用情况。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;对于研发：监控某个异常指标的变化情况，来保证业务的稳定性。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;对于产品或运营：关注产品层面：某个活动参加人数的增长情况等&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;监控系统分为以下五层：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;端监控：对网站、APP、小程序等进行端监控，采集页面打开速度、稳定性、外部服务调用成功率等参数。&lt;/li&gt;&#xA;&lt;li&gt;业务层监控：对业务模块进行监控，采集QPS、DAU、业务接口访问数量等。&lt;/li&gt;&#xA;&lt;li&gt;应用层监控：对分布式应用进行管理和监控&lt;/li&gt;&#xA;&lt;li&gt;中间件监控：对中间件进行监控，主要判断组件是否存活。&lt;/li&gt;&#xA;&lt;li&gt;系统层监控：对操作系统监控，主要包括：CPU、磁盘I/O、网络连接等参数。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h1 id=&#34;prometheus简介&#34;&gt;Prometheus简介&lt;/h1&gt;&#xA;&lt;p&gt;当前监控系统主要有集中式日志解决方案（ELK）和时序数据库解决方案。监控三要素如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Metrics：可聚合，带有时间戳的数据。&lt;/li&gt;&#xA;&lt;li&gt;Logging：离散日志，分为有结构和无结构。&lt;/li&gt;&#xA;&lt;li&gt;Tracing：请求域内的调用链。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;prometheus架构&#34;&gt;Prometheus架构&lt;/h2&gt;&#xA;&lt;p&gt;Prometheus的架构图如下所示：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/prometheus/Prometheus-framework.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;其中各组件功能如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Prometheus Server：核心部分，负责实现对监控数据的获取，存储以及查询。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Retrieval：定时去配置文件中指定target抓取指标数据。（Pull）&lt;/li&gt;&#xA;&lt;li&gt;TSDB：Prometheus内置了时序数据库，存储抓取的指标数据。&lt;/li&gt;&#xA;&lt;li&gt;HTTP Server：提供了HTTP接口进行操作。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Jobs/exporters：exporter将监控数据通过HTTP服务的形式暴露给Prometheus Server，其定时进行Pull。&lt;/li&gt;&#xA;&lt;li&gt;Pushgateway：临时性的Job可以将监控数据push到这，Prometheus从Pushgateway拉取数据。&lt;/li&gt;&#xA;&lt;li&gt;AlertManager：告警处理中心。Prometheus支持基于PromQL创建告警规则。&lt;/li&gt;&#xA;&lt;li&gt;Data Visualization：数据可视化，其中Prometheus自带的web UI可以通过PromQL进行查询，通过Grafana可以展示丰富的图表数据。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;从上述组件可以看出：Prometheus提供了&lt;strong&gt;收集数据-&amp;gt;存储数据-&amp;gt;处理数据-&amp;gt;展示数据&lt;/strong&gt;这一系列功能，完全适用上述的应用场景。&lt;/p&gt;&#xA;&lt;h2 id=&#34;获取监控数据的两种方式&#34;&gt;获取监控数据的两种方式&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Pull：从监控的target通过轮询获取监控信息。主要是HTTP API。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;告警可以按照策略分片，可以做到数据的冷热分离。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;主要流程如下：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Prometheus根据配置定期去targets拉取数据。&lt;/li&gt;&#xA;&lt;li&gt;当拉取数据大于配置的内存缓冲区时，Prometheus会将数据持久化到磁盘或云端。&lt;/li&gt;&#xA;&lt;li&gt;Prometheus通过PromQL、API等方式获取数据，同时可以配置rules，当触发条件时，将alert推送到配置的alertmanager。&lt;/li&gt;&#xA;&lt;li&gt;alertmanager收到告警时，会执行相应的策略。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Push：程序主动将数据推送到监控系统中，Prometheus采用gateway实现该方式。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;实时性好&lt;/li&gt;&#xA;&lt;li&gt;由于推送时机的不可预知性，监控系统无法掌握主动性，可能会导致对监控进程产生影响。&lt;/li&gt;&#xA;&lt;li&gt;增加gateway组件，增加了系统的复杂度。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;优缺点&#34;&gt;优缺点&lt;/h2&gt;&#xA;&lt;p&gt;优点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Golang编写，支持云原生，二进制文件直接启动，也支持容器化部署。&lt;/li&gt;&#xA;&lt;li&gt;支持多种语言的客户端。&lt;/li&gt;&#xA;&lt;li&gt;支持本地存储和云端存储，单机性能强。&lt;/li&gt;&#xA;&lt;li&gt;可扩展，使用联邦集群启动多个Prometheus实例来分布式处理。&lt;/li&gt;&#xA;&lt;li&gt;支持静态文件配置和动态发现等机制。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;缺点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;不适用Logging、Tracing等监控。&lt;/li&gt;&#xA;&lt;li&gt;Prometheus数据默认保留15天，适用于追踪近期数据。&lt;/li&gt;&#xA;&lt;li&gt;本地存储有限，需要考虑第三方存储。&lt;/li&gt;&#xA;&lt;li&gt;联邦集群没有提供统一的全局视图。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h1 id=&#34;grafana简介&#34;&gt;Grafana简介&lt;/h1&gt;&#xA;&lt;p&gt;Grafana是一个可以通过各种图形方式对数据进行可视化的一个开源软件，官网简介如下：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kafka学习笔记(一)-基础入门</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E4%B8%80-%E5%9F%BA%E7%A1%80%E5%85%A5%E9%97%A8/</link>
      <pubDate>Fri, 06 May 2022 15:08:22 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/kafka/kafka%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E4%B8%80-%E5%9F%BA%E7%A1%80%E5%85%A5%E9%97%A8/</guid>
      <description>&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;&#xA;&lt;p&gt;Kafka是由LinkedIn使用Scala语言开发的分布式消息引擎系统，目前已被捐献给Apache基金会，它以高吞吐量、可持久化、流数据处理等特性而被广泛使用。它主要有以下三种主要功能：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;消息中间件：具备常见的消息队列功能：系统解耦、冗余存储、流量削峰填谷、缓冲、异步通信，同时具备消息顺序性保障、回溯消费等功能。&lt;/li&gt;&#xA;&lt;li&gt;数据存储系统：使用Kafka存储各种服务的log，然后统一输出，ELK可使用Kafka进行数据中转。&lt;/li&gt;&#xA;&lt;li&gt;流数据处理平台：与flink、spark、storm等组件整合，提供实时计算。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Kafka支持两种常见消息传输模型：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;点对点模型&lt;/strong&gt;：也称为消息队列模型，系统A发送的消息只能被系统B接收，其它系统读取不到。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;发布/订阅模型&lt;/strong&gt;：使用&lt;code&gt;Topic&lt;/code&gt;接收消息，&lt;code&gt;Publisher&lt;/code&gt;和&lt;code&gt;Subscriber&lt;/code&gt;都可以有多个，可以同时向Topic发送接收消息。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;基本概念&#34;&gt;基本概念&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Kafka体系结构：一个Kafka集群包括若干Producer、Customer、Broker，以及一个Zookeeper集群。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Broker：服务端由被称为&lt;code&gt;Broker&lt;/code&gt;的服务进程构成，&lt;code&gt;Broker&lt;/code&gt;负责接受和处理客户端请求，以及对消息进行持久化。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;可以简单看作为一个独立的Kafka服务节点（进程示例）&lt;/li&gt;&#xA;&lt;li&gt;Broker层面的领导者被称为Controller&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Producer：客户端节点，发送消息的一方。&lt;/li&gt;&#xA;&lt;li&gt;Customer：客户端节点，接收消息的一方。&lt;/li&gt;&#xA;&lt;li&gt;Customer Group：消费者组内每个消费者负责消费不同分区的数据。一个分区只能由组内一个消费者消费，不同消费组之间互不影响。&lt;/li&gt;&#xA;&lt;li&gt;&lt;del&gt;Zookeeper集群：负责元数据管理，集群选举。&lt;/del&gt;目前最新版3.1.0提供了KRaft模式，集群不再依赖ZK。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;ZK主要负责存储Kafka集群的元数据，协调集群工作。&lt;/li&gt;&#xA;&lt;li&gt;记录信息如下：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;/brokers/ids/{0-n}：记录broker服务器节点，不同的broker使用不同的brokerid，会将自己的ip地址和端口信息记录到节点&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;ol start=&#34;2&#34;&gt;&#xA;&lt;li&gt;/brokers/topics/{topic}：记录topic分区以及broker的对应信息&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;ol start=&#34;3&#34;&gt;&#xA;&lt;li&gt;/comsumers/{group_id}/ids/{consumer_id}：消费者负载均衡&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Topic：&lt;strong&gt;逻辑概念&lt;/strong&gt;，Kafka中消息以topic为单位进行分类，生产者将消息发送到特定的topic，消费者订阅topic进行消费。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;分区partition&#34;&gt;分区（partition）&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Partition：topic可以分为多个partition，分区在物理存储层面可以看作一个可Append的Log文件，消息被Append到Log中会分配一个&lt;code&gt;offset&lt;/code&gt;，这个属性是消息的唯一标识 ，&lt;strong&gt;Kafka通过它来保证消息在分区内的顺序性&lt;/strong&gt;，因此Kafka&lt;strong&gt;保证分区有序&lt;/strong&gt;而不是主题有序。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;主题中的partition可以分布在不同的Broker中。&lt;/li&gt;&#xA;&lt;li&gt;消息到达broker后，根据分区规则存储到指定的partition。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;多副本机制replica&#34;&gt;多副本机制（Replica）&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;多副本机制（Replica）：是对于&lt;strong&gt;分区&lt;/strong&gt;而言的，&lt;strong&gt;同一分区的不同副本中保存的是相同的消息。&lt;/strong&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Leader：分区中的主副本，负责处理读写请求，Producer/Consumer交互的对象。&lt;/li&gt;&#xA;&lt;li&gt;Follower：分区中的从副本，只会实时从Leader副本同步数据。&lt;/li&gt;&#xA;&lt;li&gt;所有副本被称为AR（Assigned Replicas），所有与Leader副本数据一致性差距过多的副本组成OSR（Out-of-Sync Replicas），于leader保持一定程度同步的副本称为ISR（In-Sync Replicas）。&lt;/li&gt;&#xA;&lt;li&gt;Leader故障后，从ISR中选举新的Leader。&lt;/li&gt;&#xA;&lt;li&gt;高水位（HW-High Watermark）：消费者能消费的最大offset位置，相当于&lt;strong&gt;所有副本中都存在的消息&lt;/strong&gt;（木桶效应）&lt;/li&gt;&#xA;&lt;li&gt;LEO（Log End Offset）：标识当前日志文件中下一条待写入消息的offset，每个副本都会维护自身的LEO，&lt;strong&gt;ISR中最小的LEO即为分区的HW&lt;/strong&gt;。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;多副本的作用：提高Kafka的可用性。&lt;/p&gt;&#xA;&lt;p&gt;涉及参数：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;unclean.leader.election.enable：为true则ISR为空也能选举，为false则只能从ISR选举。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;metadata&#34;&gt;metadata&lt;/h3&gt;&#xA;&lt;p&gt;Q：客户端如何知道请求哪个broker？&lt;/p&gt;&#xA;&lt;p&gt;client通过metadata从任意broker获取集群信息，其中包括：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;topic信息&lt;/li&gt;&#xA;&lt;li&gt;每个topic的分区、副本情况&lt;/li&gt;&#xA;&lt;li&gt;leader分区所在的broker连接信息&lt;/li&gt;&#xA;&lt;li&gt;每个broker的连接信息&lt;/li&gt;&#xA;&lt;li&gt;其他信息&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/20230718224608.png&#34; alt=&#34;Kafka应用架构(https://developer.confluent.io/courses/architecture/get-started/)&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;部署&#34;&gt;部署&lt;/h2&gt;&#xA;&lt;p&gt;使用WSL 2环境进行单机部署。&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;zero@Pluto:~$ uname -a&#xA;Linux Pluto 4.19.128-microsoft-standard #1 SMP Tue Jun 23 12:58:10 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Kafka需要Java环境，由于Kafka最新版本3.1.0不再支持Java8，故使用Java11。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Zookeeper论文阅读笔记</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/zookeeper/zookeeper%E8%AE%BA%E6%96%87%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0/</link>
      <pubDate>Fri, 22 Apr 2022 21:57:47 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/zookeeper/zookeeper%E8%AE%BA%E6%96%87%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0/</guid>
      <description>&lt;h2 id=&#34;摘要&#34;&gt;摘要&lt;/h2&gt;&#xA;&lt;p&gt;Zookeeper是一个带有事件驱动的分布式系统缓存，提供了强大的分布式协调能力，结合了组播消息、分布式锁等内容。&lt;/p&gt;&#xA;&lt;p&gt;Zookeeper提供了高性能服务，保证了对客户端请求FIFO顺序执行和线性化写，在给出了在2:1到100:1的读/写比率下，ZooKeeper 每秒可以处理数万到数十万个事务。&lt;/p&gt;&#xA;&lt;h2 id=&#34;1简介&#34;&gt;1.简介&lt;/h2&gt;&#xA;&lt;p&gt;分布式系统需要不同形式的协调程序，&lt;strong&gt;配置&lt;/strong&gt;是协调的最基本形式。&lt;/p&gt;&#xA;&lt;p&gt;Zookeeper的API设计，移除了锁等阻塞原语来提高性能，使用&lt;strong&gt;wait-free的数据结构&lt;/strong&gt;来实现对应的功能。&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;注：wait-free：他保证任何线程都能在有限的过程内执行完成。&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;Zookeeper可以用集群模式中的副本来实现高可用性和高性能，是西安了基于领导者的原子广播协议（ZAB：&lt;strong&gt;Zookeeper Atomic Broadcast&lt;/strong&gt;），Zookeeper应用的主要负载是读操作，所以需要保证读吞吐量的可扩展。&lt;/p&gt;&#xA;&lt;p&gt;Zookeeper使用&lt;strong&gt;watch机制&lt;/strong&gt;使得客户端不需要直接管理客户端缓存，对于一个给定的数据对象，客户端可以监视到更新动作，当有更新的时候收到通知消息。而Chubby 直接操作客户端缓存，会阻塞更新直到所有的客户端缓存都被改变。如果任何客户端速度较慢或者故障，更新都会延迟。&lt;/p&gt;&#xA;&lt;p&gt;本文主要讨论ZooKeeper的设计和实现，包括：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;协调内核：提出了一种可用于分布式系统的无等待、具有宽松的一致性保证的协调服务。&lt;/li&gt;&#xA;&lt;li&gt;协调示例&lt;/li&gt;&#xA;&lt;li&gt;协调相关的思路&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;2zookeeper服务&#34;&gt;2.Zookeeper服务&lt;/h2&gt;&#xA;&lt;h3 id=&#34;21-概述&#34;&gt;2.1 概述&lt;/h3&gt;&#xA;&lt;p&gt;Zookeeper将客户端抽象为&lt;code&gt;znodes&lt;/code&gt;，并将其构造为树形结构，客户端可以创建两种znode：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;普通：client通过创建和删除显式操作普通节点。&lt;/li&gt;&#xA;&lt;li&gt;临时：创建后可以显式删除或者系统在会话结束后自动删除。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;watch机制使得客户端无须轮询就可以接收到状态变换的通知信息。与一个会话关联的 watches 只会触发一次；一旦触发或者会话结束，就会被注销。&lt;/p&gt;&#xA;&lt;p&gt;设计znode不是用来保存通用数据，而是用来映射客户端应用的抽象，主要是对于协调用途的元数据。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/distribute%20system/zookeeper/paper/namespace.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;22-客户端api&#34;&gt;2.2 客户端API&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;create(path, data, flags)&lt;/strong&gt;：使用 path 名称创建一个 znode 节点，保存 data，返回新创建的 znode 名称。 flags 用于创建普通或者临时节点，也可以设置顺序标识。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;delete(path, version)&lt;/strong&gt;： 删除指定 path 和 version 的 znode 节点。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;exists(path, watch)&lt;/strong&gt;： 如果指定 path 的 znode 存在则返回真，如果不存在则返回假。watch 标识用于在 znode 上设置监视器。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;getData(path, watch)&lt;/strong&gt;： 返回数据和元数据，如版本信息。watch 标识与 &lt;code&gt;exists()&lt;/code&gt; 的 watch 标识一样，但如果 znode 不存在则不会设置监视器。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;setData(path, data, version)&lt;/strong&gt;： 根据 path 和 version 将数据写入到 znode。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;getChildren(path, watch)&lt;/strong&gt;： 返回 znode 所有子节点的名称集合。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;sync(path)&lt;/strong&gt;： 在操作开始时，等待所有挂起的更新操作发送到客户端连接的服务器。path 当前未使用。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;所有API都提供同步异步两个版本，无论同步异步，都会保证执行顺序按照FIFO进行。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Zookeeper入门教程</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/zookeeper/zookeeper%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B/</link>
      <pubDate>Mon, 11 Apr 2022 15:26:27 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/zookeeper/zookeeper%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B/</guid>
      <description>&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;&#xA;&lt;p&gt;Zookeeper为分布式系统提供了高效可靠的分布式协调服务，其本质是一个键值存储系统，提供了诸如命名服务、配置管理、分布式锁等服务。其采用ZAB协议对集群数据的一致性进行管理。&lt;/p&gt;&#xA;&lt;p&gt;它负责存储和管理一些数据，然后接受观察者的注册，一旦数据状态发生变化，Zookeeper负责通知观察者做出相应的反应。&lt;/p&gt;&#xA;&lt;p&gt;几个特点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;一个Leader，多个Follow组成的集群。&lt;/li&gt;&#xA;&lt;li&gt;半数以上节点存活，集群即可正常服务，适合部署奇数台节点。&lt;/li&gt;&#xA;&lt;li&gt;全局数据一致，每个节点都保存相同的数据副本。&lt;/li&gt;&#xA;&lt;li&gt;所有客户端看到的数据都是一致的，并且请求按照顺序执行（FIFO）&lt;/li&gt;&#xA;&lt;li&gt;数据更新原子性。&lt;/li&gt;&#xA;&lt;li&gt;更新删除操作都是基于事务的，是用于&lt;strong&gt;读多写少&lt;/strong&gt;环境。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;数据模型&#34;&gt;数据模型&lt;/h3&gt;&#xA;&lt;p&gt;Zookeeper的数据模型由一个树形结构构成，每个节点称为一个ZNode，由于设计目标是实现协调服务，而不是数据存储，故默认存储大小为1MB，每个ZNode可以通过其路径唯一标识。&lt;/p&gt;&#xA;&lt;h2 id=&#34;运行&#34;&gt;运行&lt;/h2&gt;&#xA;&lt;p&gt;从官网下载Zookeeper的二进制发布版，解压后得到以下文件：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;zero@Pluto:~/Zookeeper/apache-zookeeper-3.5.7-bin$ ls&#xA;LICENSE.txt  NOTICE.txt  README.md  README_packaging.txt  bin  conf  docs  lib&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;执行&lt;code&gt;bin/zkServer.sh version&lt;/code&gt;，看到版本信息说明正常运行。&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;zero@Pluto:~/Zookeeper/apache-zookeeper-3.5.7-bin$ bin/zkServer.sh version&#xA;/usr/bin/java&#xA;ZooKeeper JMX enabled by default&#xA;Using config: /home/zero/Zookeeper/apache-zookeeper-3.5.7-bin/bin/../conf/zoo.cfg&#xA;Usage: bin/zkServer.sh [--config &amp;lt;conf-dir&amp;gt;] {start|start-foreground|stop|restart|status|print-cmd}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;单机部署&#34;&gt;单机部署&lt;/h3&gt;&#xA;&lt;p&gt;创建一个zoo.cfg文件，内容如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;tickTime=2000&#xA;&#xA;initLimit=10&#xA;&#xA;syncLimit=5&#xA;&#xA;dataDir=/opt/Zookeeper-3.5.7/zkData&#xA;&#xA;clientPort=2181&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;执行&lt;code&gt;bin/zkServer.sh start&lt;/code&gt;启动服务器节点。&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;zero@Pluto:/opt/Zookeeper-3.5.7$ bin/zkServer.sh start&#xA;/usr/bin/java&#xA;ZooKeeper JMX enabled by default&#xA;Using config: /opt/Zookeeper-3.5.7/bin/../conf/zoo.cfg&#xA;Starting zookeeper ... STARTED&#xA;&#xA;zero@Pluto:/opt/Zookeeper-3.5.7$ jps -l&#xA;3892 sun.tools.jps.Jps&#xA;3850 org.apache.zookeeper.server.quorum.QuorumPeerMain&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;执行&lt;code&gt;bin/zkCli.sh&lt;/code&gt;启动客户端。&lt;/p&gt;</description>
    </item>
    <item>
      <title>DDIA阅读笔记(一)-数据系统的基石</title>
      <link>http://localhost:1313/posts/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F/ddia%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0%E4%B8%80-%E6%95%B0%E6%8D%AE%E7%B3%BB%E7%BB%9F%E7%9A%84%E5%9F%BA%E7%9F%B3/</link>
      <pubDate>Sun, 03 Apr 2022 18:59:06 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F/ddia%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0%E4%B8%80-%E6%95%B0%E6%8D%AE%E7%B3%BB%E7%BB%9F%E7%9A%84%E5%9F%BA%E7%9F%B3/</guid>
      <description>&lt;h2 id=&#34;第一章可靠性可伸缩性可维护性&#34;&gt;第一章：可靠性、可伸缩性、可维护性&lt;/h2&gt;&#xA;&lt;p&gt;应用的两个分类：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;data-intensive&lt;/strong&gt;：问题通常来自数据量、数据复杂性、以及数据的变更速度。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;compute-intensive&lt;/strong&gt;：瓶颈在于CPU。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;可靠性&#34;&gt;可靠性&lt;/h3&gt;&#xA;&lt;p&gt;可以把可靠性粗略理解为 “即使出现问题，也能继续正确工作”。&lt;/p&gt;&#xA;&lt;p&gt;造成错误的原因叫做 &lt;strong&gt;故障（fault）&lt;/strong&gt;，能预料并应对故障的系统特性可称为 &lt;strong&gt;容错（fault-tolerant）&lt;/strong&gt; 或 &lt;strong&gt;韧性（resilient）&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;fault种类：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;硬件故障（hardware faults）&lt;/strong&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;增加单个硬件的冗余度：磁盘可以组建RAID、服务器使用双路电源和热拔插CPU等。&lt;/li&gt;&#xA;&lt;li&gt;云平台的设计就是优先考虑 **灵活性（flexibility）**和 &lt;strong&gt;弹性（elasticity）&lt;/strong&gt;，而不是单机可靠性。&lt;/li&gt;&#xA;&lt;li&gt;引入软件容错机制。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;系统性错误（systematic error）&lt;/strong&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;软件错误&lt;/li&gt;&#xA;&lt;li&gt;修复问题代码、进程隔离、监控分析&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;人为错误&lt;/strong&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;以最小化犯错机会的方式设计系统：精心设计的API&lt;/li&gt;&#xA;&lt;li&gt;与最容易犯错的模块解耦&lt;/li&gt;&#xA;&lt;li&gt;彻底的测试：单元测试、系统测试&lt;/li&gt;&#xA;&lt;li&gt;允许从人为错误中简单快速地恢复：快速回滚配置变更、分批发布新代码。&lt;/li&gt;&#xA;&lt;li&gt;配置详细地监控，比如性能指标和错误率。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;可伸缩性&#34;&gt;可伸缩性&lt;/h3&gt;&#xA;&lt;p&gt;&lt;strong&gt;可伸缩性（Scalability）&lt;/strong&gt; 是用来描述系统应对负载增长能力的术语。&lt;/p&gt;&#xA;&lt;p&gt;描述性能的指标：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;吞吐量（throughput）&lt;/strong&gt;：每秒可以处理的记录数量。或者在特定规模数据集上运行作业的总时间。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;响应时间（response time）&lt;/strong&gt;：客户端发送请求到接收响应之间的时间。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;响应时间的高百分位点（尾部延迟）指标非常重要&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;处理方法：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;垂直伸缩：转向更强大的机器。&lt;/li&gt;&#xA;&lt;li&gt;水平伸缩：负载分布到多台小机器。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;strong&gt;弹性（elastic）&lt;/strong&gt;：在检测到负载增加时自动增加计算资源&lt;/p&gt;&#xA;&lt;h3 id=&#34;可维护性&#34;&gt;可维护性&lt;/h3&gt;&#xA;&lt;p&gt;三个设计原则来避免自己的软件系统变为遗留系统：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;可操作性&lt;/li&gt;&#xA;&lt;li&gt;简单性&lt;/li&gt;&#xA;&lt;li&gt;可演化性&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;可操作性&#34;&gt;可操作性&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;监控系统提供可见性&lt;/li&gt;&#xA;&lt;li&gt;将系统与标准化工具集成&lt;/li&gt;&#xA;&lt;li&gt;避免单机部署&lt;/li&gt;&#xA;&lt;li&gt;提供良好的文档&lt;/li&gt;&#xA;&lt;li&gt;提供良好的默认行为（配置参数？）&lt;/li&gt;&#xA;&lt;li&gt;自我修复&lt;/li&gt;&#xA;&lt;li&gt;行为可预测&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;简单性&#34;&gt;简单性&lt;/h4&gt;&#xA;&lt;p&gt;消除&lt;strong&gt;额外复杂度&lt;/strong&gt;的最好工具之一是&lt;strong&gt;抽象&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;抽象帮助我们控制系统复杂度。&lt;/p&gt;&#xA;&lt;h4 id=&#34;可演化性&#34;&gt;可演化性&lt;/h4&gt;&#xA;&lt;p&gt;系统的需求是变化的，使用敏捷工作模式来应对，例如TDD和重构。&lt;/p&gt;&#xA;&lt;h2 id=&#34;第二章数据模型与查询语言&#34;&gt;第二章：数据模型与查询语言&lt;/h2&gt;&#xA;&lt;p&gt;问题：需要将数据模型抽象成对应的概念。&lt;/p&gt;&#xA;&lt;p&gt;每个层都通过提供一个明确的数据模型来隐藏更低层次中的复杂性。&lt;/p&gt;&#xA;&lt;h3 id=&#34;关系模型和文档模型&#34;&gt;关系模型和文档模型&lt;/h3&gt;&#xA;&lt;h4 id=&#34;关系模型&#34;&gt;关系模型&lt;/h4&gt;&#xA;&lt;p&gt;常见分类：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;TP（事务性）：银行交易&lt;/li&gt;&#xA;&lt;li&gt;AP（分析型）：数据报表&lt;/li&gt;&#xA;&lt;li&gt;HTAP（混合型）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;问题：关系模型很难直观表达&lt;strong&gt;一对多的关系&lt;/strong&gt;．&lt;/p&gt;</description>
    </item>
    <item>
      <title>MySQL调优总结</title>
      <link>http://localhost:1313/posts/mysql/mysql%E8%B0%83%E4%BC%98%E6%80%BB%E7%BB%93%E7%AC%94%E8%AE%B0/</link>
      <pubDate>Tue, 01 Mar 2022 12:23:36 +0000</pubDate>
      <guid>http://localhost:1313/posts/mysql/mysql%E8%B0%83%E4%BC%98%E6%80%BB%E7%BB%93%E7%AC%94%E8%AE%B0/</guid>
      <description>&lt;h1 id=&#34;前言&#34;&gt;前言&lt;/h1&gt;&#xA;&lt;p&gt;数据库调优的几个维度：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;建立索引&lt;/li&gt;&#xA;&lt;li&gt;SQL语句优化&lt;/li&gt;&#xA;&lt;li&gt;服务器参数调优：包括缓冲区、线程数等&lt;/li&gt;&#xA;&lt;li&gt;分库分表、集群模式&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;调优目标：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;尽可能节省系统资源，以提高系统吞吐量。&lt;/li&gt;&#xA;&lt;li&gt;合理的结构设计和参数调整，以提高用户操作响应的速度。&lt;/li&gt;&#xA;&lt;li&gt;减少系统的瓶颈，提高MySQL整体性能。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;如何定位调优问题：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;用户反馈&lt;/li&gt;&#xA;&lt;li&gt;日志分析&lt;/li&gt;&#xA;&lt;li&gt;服务器资源监控&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;调优维度：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;选择合适的DBMS&lt;/li&gt;&#xA;&lt;li&gt;优化表设计&#xA;&lt;ol&gt;&#xA;&lt;li&gt;遵循三范式的原则&lt;/li&gt;&#xA;&lt;li&gt;多表联查可以考虑反范式化&lt;/li&gt;&#xA;&lt;li&gt;表字段的数据类型选择&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;优化SQL查询（逻辑）&lt;/li&gt;&#xA;&lt;li&gt;使用索引（物理）&lt;/li&gt;&#xA;&lt;li&gt;使用缓存&lt;/li&gt;&#xA;&lt;li&gt;库级优化&#xA;&lt;ol&gt;&#xA;&lt;li&gt;读写分离&#xA;&lt;ol&gt;&#xA;&lt;li&gt;一主一从&lt;/li&gt;&#xA;&lt;li&gt;双主双从&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;数据分片：对数据库进行分库分表。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h1 id=&#34;mysql服务器优化&#34;&gt;MySQL服务器优化&lt;/h1&gt;&#xA;&lt;p&gt;两个方面：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;硬件优化&lt;/li&gt;&#xA;&lt;li&gt;MySQL服务的参数优化&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;硬件调优&#34;&gt;硬件调优&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;配置较大的内存，增加缓冲区容量，减少磁盘IO。&lt;/li&gt;&#xA;&lt;li&gt;配置高速磁盘系统，减少磁盘IO的时间。&lt;/li&gt;&#xA;&lt;li&gt;合理分布磁盘IO，将磁盘IO分布在多个设备上，减少竞争。&lt;/li&gt;&#xA;&lt;li&gt;配置多处理器。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;参数调优&#34;&gt;参数调优&lt;/h2&gt;&#xA;&lt;p&gt;通过优化MySQL可以提高资源利用率，从而提高MySQL服务器性能。&lt;/p&gt;&#xA;&lt;p&gt;几个重要的参数：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;innodb_buffer_pool_size：表和索引的缓存区大小。&lt;/li&gt;&#xA;&lt;li&gt;key_buffer_size：索引缓冲区大小，所有线程共享，值太大也会导致OS频繁换页。&lt;/li&gt;&#xA;&lt;li&gt;table_cache：同时打开的表的个数。&lt;/li&gt;&#xA;&lt;li&gt;query_cache_size：&lt;strong&gt;查询缓冲区&lt;/strong&gt;大小，与query_cache_type配合使用。&lt;/li&gt;&#xA;&lt;li&gt;query_cache_type：0代表所有查询不使用查询缓冲区，1表示所有都使用，当查询语句指定&lt;code&gt;SQL_NO_CACHE&lt;/code&gt;则不使用。&lt;/li&gt;&#xA;&lt;li&gt;sort_buffer_size：每个需要进行&lt;strong&gt;排序&lt;/strong&gt;的线程分配的缓冲区大小，增加这个参数的值可以提高&lt;code&gt;ORDER BY&lt;/code&gt;或&lt;code&gt;GROUP BY&lt;/code&gt;操作的速度。&lt;/li&gt;&#xA;&lt;li&gt;join_buffer_size：每个需要&lt;strong&gt;联合查询&lt;/strong&gt;的线程所使用的缓冲区大小。&lt;/li&gt;&#xA;&lt;li&gt;read_buffer_size：每个线程&lt;strong&gt;连续扫描时&lt;/strong&gt;为扫描的每个表分配的缓冲区的大小。&lt;/li&gt;&#xA;&lt;li&gt;innodb_flush_log_at_trx_commit：**何时将redo log buffer的数据写入redo log file，并将日志文件写入磁盘中。**默认为1。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;0：redo log buffer每隔一秒将其数据刷入page cache，该模式下事务提交不会触发刷盘操作。&lt;/li&gt;&#xA;&lt;li&gt;1：每次事务提交都会将将redo log buffer中数据刷入page cache，并立刻刷入磁盘。效率较低也为安全。&lt;/li&gt;&#xA;&lt;li&gt;2：每次事务提交都会将redo log buffer中数据刷入page cache，由OS同步到磁盘。（每秒一次）&#xA;&lt;ul&gt;&#xA;&lt;li&gt;mysql进程崩溃不会有数据丢失，当时OS宕机会有数据丢失。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;innodb_log_buffer_size：InnoDB存储引擎的&lt;strong&gt;事务日志缓冲区&lt;/strong&gt;，为了提升性能，也是先将信息写入 &lt;code&gt;Innodb Log Buffer&lt;/code&gt; 中，当满足 &lt;code&gt;innodb_flush_log_trx_commit&lt;/code&gt; 参数所设置的相应条件（或者日志缓冲区写满）之后，才会将日志写到文件（或者同步到磁盘）中。&lt;/li&gt;&#xA;&lt;li&gt;max_connections：允许连接到MySQL数据库的最大数量。如果&lt;code&gt;connection_errors_max_connections&lt;/code&gt;不为0，并且一直增长，说明不断有连接因为数据库连接数已到最大值而失败，此时考虑增大&lt;code&gt;max_connections&lt;/code&gt;的值。&lt;/li&gt;&#xA;&lt;li&gt;back_log：用于&lt;strong&gt;控制MySQL监听TCP端口时设置的积压请求栈大小。&lt;/strong&gt; 连接数达到&lt;code&gt;max_connections&lt;/code&gt;，新来的请求将会被存在堆栈中，以等待某一连接释放资源，如果等待连接的数量超过back_log，将会报错。&lt;/li&gt;&#xA;&lt;li&gt;thread_cache_size：线程池缓存线程数量的大小，当客户端断开连接后将当前线程缓存起来， 当在接到新的连接请求时快速响应无需创建新的线程 。这对于短链接的应用程序十分有用。&lt;/li&gt;&#xA;&lt;li&gt;wait_timeout：一个连接的最大连接时间。&lt;/li&gt;&#xA;&lt;li&gt;interactive_timeout：服务器在关闭连接前等待行动的秒数。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h1 id=&#34;优化数据库结构&#34;&gt;优化数据库结构&lt;/h1&gt;&#xA;&lt;p&gt;几个策略：&lt;/p&gt;</description>
    </item>
    <item>
      <title>网络IO模型总结</title>
      <link>http://localhost:1313/posts/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E7%BD%91%E7%BB%9Cio%E6%A8%A1%E5%9E%8B%E6%80%BB%E7%BB%93/</link>
      <pubDate>Tue, 22 Feb 2022 10:44:13 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E7%BD%91%E7%BB%9Cio%E6%A8%A1%E5%9E%8B%E6%80%BB%E7%BB%93/</guid>
      <description>&lt;h2 id=&#34;网络io流程&#34;&gt;网络IO流程&lt;/h2&gt;&#xA;&lt;p&gt;网络IO中的一次请求和响应的流程基本如下：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;内核通过网卡读取客户端的请求数据，将数据读取到内核缓冲区。数据从网卡到内核空间；&lt;/li&gt;&#xA;&lt;li&gt;从内核缓冲区读取数据到应用进程缓冲区。数据从内核空间到用户空间；&lt;/li&gt;&#xA;&lt;li&gt;服务端进程在自己的用户空间中，处理客户端的请求。数据在用户空间中被处理；&lt;/li&gt;&#xA;&lt;li&gt;处理完数据并构建好的响应之后，将数据从用户缓冲区写入内核缓冲区。&lt;/li&gt;&#xA;&lt;li&gt;内核将内核缓冲区中的响应写入网卡，网卡通过底层的通讯协议，会将数据发送给目标客户端。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;两组概念：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;同步&lt;/strong&gt;：请求被逐个地处理，无法并发执行。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;异步&lt;/strong&gt;：多个请求可以并发执行，内核IO操作完成后会通知用户线程，或者调用用户进程的回调函数。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;阻塞&lt;/strong&gt;：请求发出后，由于该请求操作需要的条件不满足，请求操作一直阻塞，不会返回，直到条件满足。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;非阻塞&lt;/strong&gt;：请求发出后，若该请求需要的条件不满足，则立即返回一个标志信息告知条件不满足，而不会一直等待。一般需要通过循环判断请求条件是否满足来获取请求结果。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;在《UNIX网络编程》中，将UNIX的IO模型分为了以下五种：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;阻塞式IO&lt;/li&gt;&#xA;&lt;li&gt;非阻塞式IO&lt;/li&gt;&#xA;&lt;li&gt;IO多路复用&lt;/li&gt;&#xA;&lt;li&gt;信号驱动式IO&lt;/li&gt;&#xA;&lt;li&gt;异步IO&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;阻塞式io&#34;&gt;阻塞式IO&lt;/h2&gt;&#xA;&lt;p&gt;该模型中，用户空间的应用程序通过执行read调用（底层是recvfrom系统调用）来从socket中读取数据，在应用程序发起read调用后，会一直阻塞，直到数据包到达网卡上并复制到内核空间中，随后从内核空间拷贝到用户空间之后才会返回。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/network-io/blocking-io.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;BIO在实现异步操作时，只能使用多线程进行处理，一个请求对应一个线程，该模型对于高并发环境，开销十分巨大，需要考虑其他的IO处理模型。&lt;/p&gt;&#xA;&lt;h2 id=&#34;非阻塞式io&#34;&gt;非阻塞式IO&lt;/h2&gt;&#xA;&lt;p&gt;应用程序发起系统调用，如果内核数据暂未准备好，进程可以做其他事，然后再次轮询内核获取请求结果。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/network-io/nonblocking-io.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;简单的NIO需要不断的重复发起IO系统调用，这种不断地询问内核的操作，这将占用大量的 CPU 时间，并导致&lt;strong&gt;上下文切换&lt;/strong&gt;，系统资源利用率较低。&lt;/p&gt;&#xA;&lt;h2 id=&#34;io多路复用&#34;&gt;IO多路复用&lt;/h2&gt;&#xA;&lt;p&gt;IO多路复用模型通过一个&lt;strong&gt;监听线程&lt;/strong&gt;发起另一种形式的系统调用，由一个线程监听多个文件描述符（fd，linux系统把所有网络请求以一个fd来标识），一旦某个fd的操作就绪（一般是内核缓冲区可读/可写），该系统调用就会返回，随后监听线程可以通知程序对准备好了的fd进行对应的IO系统调用，比如通过recvfrom读取数据。&lt;/p&gt;&#xA;&lt;p&gt;在Linux中select、poll、epoll函数就是IO多路复用的具体实现。Java4新增的NIO包中引入的选择器Selector，使用的就是IO多路复用模型，通过它，只需要一个线程便可以管理多个客户端连接。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/network-io/multiplexing.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;信号驱动io&#34;&gt;信号驱动IO&lt;/h2&gt;&#xA;&lt;p&gt;应用程序通过sigaction系统调用安装一个信号处理函数，应用程序继续工作，当数据准备好后，内核给进程发送一个&lt;code&gt;SIGIO&lt;/code&gt;信号，应用程序开始&lt;strong&gt;执行系统调用&lt;/strong&gt;执行IO操作。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/network-io/signal-io.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这种模型的优势在于等待数据达到期间，进程不被阻塞。只需要等待信号处理函数的通知。&lt;/p&gt;&#xA;&lt;h2 id=&#34;异步io&#34;&gt;异步IO&lt;/h2&gt;&#xA;&lt;p&gt;AIO的基本流程是：用户线程通过系统调用，告知内核启动某个IO操作，用户线程随即返回。内核在整个IO操作（包括数据准备、数据复制）完成后，会通知用户程序，用户执行后续的业务操作。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/network-io/aio.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;与信号驱动式IO的区别：信号驱动模型是由内核通知我们&lt;strong&gt;何时可以启动一个IO操作&lt;/strong&gt;，而异步IO模型由内核通知我们&lt;strong&gt;IO操作何时完成&lt;/strong&gt;。信号驱动IO更像半异步IO。&lt;/p&gt;&#xA;&lt;h2 id=&#34;参考&#34;&gt;参考&lt;/h2&gt;&#xA;&lt;p&gt;《UNIX网络编程》&lt;/p&gt;</description>
    </item>
    <item>
      <title>Raft论文阅读笔记</title>
      <link>http://localhost:1313/posts/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F/raft-note/</link>
      <pubDate>Mon, 31 Jan 2022 14:19:03 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F/raft-note/</guid>
      <description>&lt;h2 id=&#34;介绍&#34;&gt;介绍&lt;/h2&gt;&#xA;&lt;p&gt;Paxos算法较为复杂，并且不易于应用到工业界，因此诞生了Raft算法，其首要目标是可理解性，Raft算法主要分解为几个部分：领导者选举、日志复制、安全性、成员变更等。Raft算法有一些独特的特性：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;强领导者：日志entry只从领导者发送给其他服务器&lt;/li&gt;&#xA;&lt;li&gt;领导者选举：Raft算法采用一个随即计时器来选举领导人&lt;/li&gt;&#xA;&lt;li&gt;成员关系调整：Raft算法采用一种共同一致的方法来处理集群成员变换的问题，此时集群依然可以工作。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;属性解释&#34;&gt;属性解释&lt;/h3&gt;&#xA;&lt;p&gt;&lt;strong&gt;状态&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h4 id=&#34;所有服务器上的持久性状态&#34;&gt;所有服务器上的持久性状态&lt;/h4&gt;&#xA;&lt;p&gt;(在响应 RPC 请求之前，已经更新到了稳定的存储设备)&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;参数&lt;/th&gt;&#xA;          &lt;th&gt;解释&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;currentTerm&lt;/td&gt;&#xA;          &lt;td&gt;服务器已知最新的任期（在服务器首次启动时初始化为0，单调递增）&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;votedFor&lt;/td&gt;&#xA;          &lt;td&gt;当前任期内收到选票的 candidateId，如果没有投给任何候选人 则为空&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;log[]&lt;/td&gt;&#xA;          &lt;td&gt;日志条目；每个条目包含了用于状态机的命令，以及领导人接收到该条目时的任期（初始索引为1）&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h4 id=&#34;所有服务器上的易失性状态&#34;&gt;所有服务器上的易失性状态&lt;/h4&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;参数&lt;/th&gt;&#xA;          &lt;th&gt;解释&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;commitIndex&lt;/td&gt;&#xA;          &lt;td&gt;已知已提交的最高的日志条目的索引（初始值为0，单调递增）&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;lastApplied&lt;/td&gt;&#xA;          &lt;td&gt;已经被应用到状态机的最高的日志条目的索引（初始值为0，单调递增）&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h4 id=&#34;领导人服务器上的易失性状态&#34;&gt;领导人（服务器）上的易失性状态&lt;/h4&gt;&#xA;&lt;p&gt;(选举后已经重新初始化)&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;参数&lt;/th&gt;&#xA;          &lt;th&gt;解释&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;nextIndex[]&lt;/td&gt;&#xA;          &lt;td&gt;对于每一台服务器，发送到该服务器的下一个日志条目的索引（初始值为领导人最后的日志条目的索引+1）&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;matchIndex[]&lt;/td&gt;&#xA;          &lt;td&gt;对于每一台服务器，已知的已经复制到该服务器的最高日志条目的索引（初始值为0，单调递增）&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h4 id=&#34;追加条目appendentriesrpc&#34;&gt;&lt;strong&gt;追加条目（AppendEntries）RPC&lt;/strong&gt;：&lt;/h4&gt;&#xA;&lt;p&gt;由leader调用，用于日志条目的复制，同时也被当做心跳使用&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;参数&lt;/th&gt;&#xA;          &lt;th&gt;解释&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;term&lt;/td&gt;&#xA;          &lt;td&gt;领导人的任期&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;leaderId&lt;/td&gt;&#xA;          &lt;td&gt;领导人 ID 因此跟随者可以对客户端进行重定向（译者注：跟随者根据领导人 ID 把客户端的请求重定向到领导人，比如有时客户端把请求发给了跟随者而不是领导人）&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;prevLogIndex&lt;/td&gt;&#xA;          &lt;td&gt;紧邻新日志条目之前的那个日志条目的索引&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;prevLogTerm&lt;/td&gt;&#xA;          &lt;td&gt;紧邻新日志条目之前的那个日志条目的任期&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;entries[]&lt;/td&gt;&#xA;          &lt;td&gt;需要被保存的日志条目（被当做心跳使用时，则日志条目内容为空；为了提高效率可能一次性发送多个）&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;leaderCommit&lt;/td&gt;&#xA;          &lt;td&gt;领导人的已知已提交的最高的日志条目的索引&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;返回值&lt;/th&gt;&#xA;          &lt;th&gt;解释&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;term&lt;/td&gt;&#xA;          &lt;td&gt;当前任期，对于领导人而言 它会更新自己的任期&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;success&lt;/td&gt;&#xA;          &lt;td&gt;如果跟随者所含有的条目和 prevLogIndex 以及 prevLogTerm 匹配上了，则为 true&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h5 id=&#34;receiver的实现&#34;&gt;receiver的实现&lt;/h5&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;如果&lt;code&gt;term &amp;lt; currentTerm&lt;/code&gt;， return false&lt;/li&gt;&#xA;&lt;li&gt;在接收者日志中 如果能找到一个和 prevLogIndex 以及 prevLogTerm 一样的索引和任期的日志条目 则继续执行下面的步骤 否则return false&lt;/li&gt;&#xA;&lt;li&gt;如果一个已经存在的条目和新条目发生了冲突，那么就删除这个已经存在的条目以及它之后的所有条目&lt;/li&gt;&#xA;&lt;li&gt;追加的条目暂未存在日志中&lt;/li&gt;&#xA;&lt;li&gt;如果&lt;code&gt;leaderCommit &amp;gt; commitIndex&lt;/code&gt;，设置commitIndex = min(leaderCommit, index of last new entry)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;请求投票requestvoterpc&#34;&gt;&lt;strong&gt;请求投票（RequestVote）RPC&lt;/strong&gt;：&lt;/h4&gt;&#xA;&lt;p&gt;由候选人负责调用用来征集选票（5.2 节）&lt;/p&gt;</description>
    </item>
    <item>
      <title>Bitcask论文阅读笔记</title>
      <link>http://localhost:1313/posts/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F/bitcask/</link>
      <pubDate>Thu, 13 Jan 2022 17:45:04 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F/bitcask/</guid>
      <description>&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;&#xA;&lt;p&gt;Bitcask是Riak分布式数据库使用的日志型存储模型，主要有以下几点特性：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;读写低延迟&lt;/li&gt;&#xA;&lt;li&gt;高吞吐量，尤其是随机写&lt;/li&gt;&#xA;&lt;li&gt;能处理大量的数据集而不降低性能&lt;/li&gt;&#xA;&lt;li&gt;故障时快速恢复且不丢失数据&lt;/li&gt;&#xA;&lt;li&gt;易于备份和恢复&lt;/li&gt;&#xA;&lt;li&gt;易于理解的代码结构和数据格式&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;结构&#34;&gt;结构&lt;/h2&gt;&#xA;&lt;h3 id=&#34;硬盘结构&#34;&gt;硬盘结构&lt;/h3&gt;&#xA;&lt;p&gt;在给定的一段时间内，只有一个&lt;code&gt;active data file&lt;/code&gt;能提供&lt;code&gt;append&lt;/code&gt;（写入）功能，当该文件大小达到指定阈值时，则会创建一个新的&lt;code&gt;active data file&lt;/code&gt;。每一个写入到file的entry结构如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/distribute%20system/bitcask/entry.jpg&#34; alt=&#34;Entry结构&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;包括以下内容：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;crc：校验值&lt;/li&gt;&#xA;&lt;li&gt;tstamp：记录写入该数据的时间&lt;/li&gt;&#xA;&lt;li&gt;ksz：key_size&lt;/li&gt;&#xA;&lt;li&gt;value_sz：value_size&lt;/li&gt;&#xA;&lt;li&gt;key：key&lt;/li&gt;&#xA;&lt;li&gt;value：value&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;内存结构&#34;&gt;内存结构&lt;/h3&gt;&#xA;&lt;p&gt;在写入之后，一个被称为&lt;code&gt;keydir&lt;/code&gt;（hash table）的内存结构将被更新，每一个键映射到固定大小的结构中，包括了以下内容：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;file_id：去哪个文件查询&lt;/li&gt;&#xA;&lt;li&gt;value_size：读取value多长的字节&lt;/li&gt;&#xA;&lt;li&gt;value_position：value在文件中的位置&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;每一次写操作发生，&lt;code&gt;keydir&lt;/code&gt;都会进行原子性的更新。&lt;/p&gt;&#xA;&lt;h2 id=&#34;操作&#34;&gt;操作&lt;/h2&gt;&#xA;&lt;h3 id=&#34;read&#34;&gt;read&lt;/h3&gt;&#xA;&lt;p&gt;读取value的过程：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;查找keydir中的key，并读取&lt;code&gt;file_id&lt;/code&gt;，&lt;code&gt;position&lt;/code&gt;，&lt;code&gt;size&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;li&gt;通过&lt;code&gt;file_id&lt;/code&gt;找到对应的&lt;code&gt;data file&lt;/code&gt;，再通过&lt;code&gt;position&lt;/code&gt;和&lt;code&gt;size&lt;/code&gt;字段找到entry中的value。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;merge&#34;&gt;merge&lt;/h3&gt;&#xA;&lt;p&gt;由于删除操作并不会真正删除掉entry，只是将删除操作封装成entry写入文件，因此需要&lt;code&gt;merge&lt;/code&gt;操作将所有的非&lt;code&gt;active&lt;/code&gt;文件中entry遍历，并重组为一个新文件。同时生成一个&lt;code&gt;hint file&lt;/code&gt;，用于存储&lt;code&gt;data file&lt;/code&gt;的位置和大小。&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Q：hint file的作用是什么？&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;A：每次进程重启时需要重建&lt;code&gt;keydir&lt;/code&gt;，需要扫描所有的数据文件，因此使用&lt;code&gt;hint file &lt;/code&gt;加速构建&lt;code&gt;keydir&lt;/code&gt;的速度。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Leetcode-Tree刷题记录</title>
      <link>http://localhost:1313/posts/%E7%AE%97%E6%B3%95/leetcode-tree/</link>
      <pubDate>Fri, 02 Jul 2021 15:40:28 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E7%AE%97%E6%B3%95/leetcode-tree/</guid>
      <description>&lt;h3 id=&#34;结构体定义&#34;&gt;结构体定义&lt;/h3&gt;&#xA;&lt;p&gt;Leetcode中TreeNode结构体定义如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C++&#34; data-lang=&#34;C++&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;TreeNode&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; val;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      TreeNode &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;left;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      TreeNode &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;right;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      TreeNode() &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; val(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;), left(&lt;span style=&#34;color:#66d9ef&#34;&gt;nullptr&lt;/span&gt;), right(&lt;span style=&#34;color:#66d9ef&#34;&gt;nullptr&lt;/span&gt;) {}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      TreeNode(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; x) &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; val(x), left(&lt;span style=&#34;color:#66d9ef&#34;&gt;nullptr&lt;/span&gt;), right(&lt;span style=&#34;color:#66d9ef&#34;&gt;nullptr&lt;/span&gt;) {}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      TreeNode(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; x, TreeNode &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;left, TreeNode &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;right) &lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt; val(x), left(left), right(right) {}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;二叉树的前序遍历&#34;&gt;二叉树的前序遍历&lt;/h3&gt;&#xA;&lt;p&gt;递归版本：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C++&#34; data-lang=&#34;C++&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Solution&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    vector&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; res;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    vector&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; preorderTraversal(TreeNode&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; root) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;root) &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; res;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        res.push_back(root&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;val);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        preorderTraversal(root&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;left);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        preorderTraversal(root&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;right);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; res;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;迭代版本：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C++&#34; data-lang=&#34;C++&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Solution&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    vector&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; preorderTraversal(TreeNode&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; root) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        vector&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; res;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        stack&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;TreeNode&lt;span style=&#34;color:#f92672&#34;&gt;*&amp;gt;&lt;/span&gt; stack;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(root){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            stack.push(root);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;stack.empty()){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            TreeNode&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; curr &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; stack.top();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            stack.pop();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            res.push_back(curr&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;val);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(curr&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;right &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nullptr&lt;/span&gt;){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                stack.push(curr&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;right);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(curr&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;left &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nullptr&lt;/span&gt;){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                stack.push(curr&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;left);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; res;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;二叉树的中序遍历&#34;&gt;二叉树的中序遍历&lt;/h3&gt;&#xA;&lt;p&gt;递归版本：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Leetcode-字符串刷题记录</title>
      <link>http://localhost:1313/posts/%E7%AE%97%E6%B3%95/leetcode-string/</link>
      <pubDate>Thu, 18 Feb 2021 17:24:19 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E7%AE%97%E6%B3%95/leetcode-string/</guid>
      <description>&lt;h3 id=&#34;520-检测大写字母&#34;&gt;520. 检测大写字母&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;detectCapitalUse&lt;/span&gt;(String word) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; arr &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; word.&lt;span style=&#34;color:#a6e22e&#34;&gt;toCharArray&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; up &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0, low &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt;(i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; arr.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(arr&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;i&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                low&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                up&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            i&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(up &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; arr.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(low &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; arr.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(up &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; 1 &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; arr&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;125-验证回文串&#34;&gt;125. 验证回文串&lt;/h3&gt;&#xA;&lt;p&gt;经典问题，需要过滤非字符非数字。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;isPalindrome&lt;/span&gt;(String s) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(s &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        s &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; s.&lt;span style=&#34;color:#a6e22e&#34;&gt;toLowerCase&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        StringBuilder str &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; StringBuilder(s.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;());&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; c : s.&lt;span style=&#34;color:#a6e22e&#34;&gt;toCharArray&lt;/span&gt;()) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ((c &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;0&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; c &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;9&amp;#39;&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; (c &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; c &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;z&amp;#39;&lt;/span&gt;)) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                str.&lt;span style=&#34;color:#a6e22e&#34;&gt;append&lt;/span&gt;(c);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; str.&lt;span style=&#34;color:#a6e22e&#34;&gt;toString&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;equals&lt;/span&gt;(str.&lt;span style=&#34;color:#a6e22e&#34;&gt;reverse&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;toString&lt;/span&gt;());&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;14-最长公共前缀&#34;&gt;14. 最长公共前缀&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;首先计算出最短字符串的长度，这个长度就是外层循环的遍历次数。&lt;/li&gt;&#xA;&lt;li&gt;内层逐个比较字符串的指定位置的值。&lt;/li&gt;&#xA;&lt;li&gt;通过StringBuilder拼接公共前缀。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#a6e22e&#34;&gt;longestCommonPrefix&lt;/span&gt;(String&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; strs) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(strs.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; 0) &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        StringBuilder sb &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; StringBuilder();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; minLength &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 1000;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//计算最短字符串长度&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt;(String str : strs){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(str.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; minLength){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                minLength &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; str.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        String demo &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; strs&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;0&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0; i&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; minLength; i&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; flag &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; c &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; demo.&lt;span style=&#34;color:#a6e22e&#34;&gt;charAt&lt;/span&gt;(i);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; j &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 1; j &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; strs.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;; j&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(strs&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;j&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;charAt&lt;/span&gt;(i) &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; c){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#75715e&#34;&gt;//不等于&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    flag &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(flag){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                sb.&lt;span style=&#34;color:#a6e22e&#34;&gt;append&lt;/span&gt;(c);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                flag &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; sb.&lt;span style=&#34;color:#a6e22e&#34;&gt;toString&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;434-字符串中的单词数&#34;&gt;434. 字符串中的单词数&lt;/h3&gt;&#xA;&lt;p&gt;一轮遍历即可，判断依据是：&lt;strong&gt;当前值是空格，前一位非空格&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>分布式系统理论笔记</title>
      <link>http://localhost:1313/posts/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F%E7%90%86%E8%AE%BA%E7%AC%94%E8%AE%B0/</link>
      <pubDate>Sat, 23 Jan 2021 14:12:00 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F%E7%90%86%E8%AE%BA%E7%AC%94%E8%AE%B0/</guid>
      <description>&lt;h1 id=&#34;引言&#34;&gt;引言&lt;/h1&gt;&#xA;&lt;p&gt;分布式系统面临的问题：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;数据一致性&lt;/strong&gt;：数据均匀分布到多个存储节点，如何保证多个副本的数据一致性问题。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;集群可用性&lt;/strong&gt;：集群的服务是否可用。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;分区容错性&lt;/strong&gt;：当发生故障，集群如何快速恢复从而提供正常服务。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h1 id=&#34;理论&#34;&gt;理论&lt;/h1&gt;&#xA;&lt;h2 id=&#34;拜占庭将军问题&#34;&gt;拜占庭将军问题&lt;/h2&gt;&#xA;&lt;p&gt;存在恶意节点行为的场景中（数字货币的区块链技术中）：必须使用拜占庭容错算法（BFT）。常用的有PBFT算法、PoW算法。&lt;/p&gt;&#xA;&lt;p&gt;计算机分布式系统中，最常用的是非拜占庭容错算法，即故障容错算法（CFT）。&lt;strong&gt;CFT解决的是分布式系统中存在故障，但不存在恶意节点的场景下的共识问题&lt;/strong&gt;。这个场景可能会丢失信息、消息重复问题，但是不存在错误消息，或者伪造消息的情况。常见算法有Paxos算法、Raft算法、ZAB协议。&lt;/p&gt;&#xA;&lt;h2 id=&#34;cap理论&#34;&gt;CAP理论&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Q：如何设计分区容错一致性模型？&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;h3 id=&#34;cap三指标&#34;&gt;CAP三指标&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;一致性（Consistency）&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;强调的是数据在集群中的一致性。&lt;/li&gt;&#xA;&lt;li&gt;客户端每次的读操作，无论访问哪个节点，要么读到同一份数据，要么读取失败。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;可用性（Availability）&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;强调的是服务可用，但不保证数据的一致。&lt;/li&gt;&#xA;&lt;li&gt;无论客户端访问哪个节点，都能得到响应数据，但是不保证数据是最新的。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;分区容错性（Partition Tolerance）&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;强调的是集群对分区故障的容错能力。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;节点出现任意数量的消息丢失或高延迟，系统仍然可以继续提供服务。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;cap不可能三角&#34;&gt;CAP不可能三角&lt;/h3&gt;&#xA;&lt;p&gt;对于一个分布式系统而言，一致性、可用性、分区容错性三个指标不可兼得，只能进行三选二。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/distribute%20system/CAP/CAP-triangle.jpg&#34; alt=&#34;CAP不可能三角&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;如何使用cap理论&#34;&gt;如何使用CAP理论&lt;/h3&gt;&#xA;&lt;p&gt;节点之间的分区故障是必然发生的，因此分区容错性（P）是必须要保证的。那么只剩下两种选择：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;CP：选择一致性（C）的时候，如果因为消息丢失、延迟过高发生了网络分区，部分节点无法保持一致，这时集群节点拒绝客户端的写操作。&lt;/li&gt;&#xA;&lt;li&gt;AP：选择可用性（A）的时候，系统将始终处理客户端的查询，返回特定信息，如果发生了网络分区，一些节点无法返回最新特定信息。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;acid&#34;&gt;ACID&lt;/h2&gt;&#xA;&lt;p&gt;单机上实现ACID可以通过锁、时间序列等机制保障操作的顺序执行。分布式系统的ACID实现需要掌握分布式事务协议，比如二阶段提交协议、TCC（Try-Confirm-Cancel）。&lt;/p&gt;&#xA;&lt;p&gt;可以将ACID特性理解为CAP中一致性的边界（最强的一致性），但是大部分场景对一致性的要求不是特别高，&lt;strong&gt;如果不是必须，尽量不要实现事务，可以考虑采用强一致性或最终一致性。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;二阶段提交协议&#34;&gt;二阶段提交协议&lt;/h3&gt;&#xA;&lt;p&gt;用于保证多个节点操作的原子性，也就是：&lt;strong&gt;要么多个节点的操作全部执行成功，要么全部失败。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;节点分为：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;协调者&lt;/li&gt;&#xA;&lt;li&gt;参与者&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;执行过程如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;提交请求阶段（投票阶段）&#xA;&lt;ul&gt;&#xA;&lt;li&gt;每一个参与者投票表决事务是放弃还是提交，一旦参与者投票要求提交事务，那么不允许中途放弃事务，这个特性需要代码实现时保障的。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;提交执行阶段（完成阶段）&#xA;&lt;ul&gt;&#xA;&lt;li&gt;事务的每个参与者执行最终统一的决定，提交事务或者放弃事务，这个约定是为了实现ACID中的原子性。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;存在的问题：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;提交请求阶段，需要预留资源，在资源预留时期，其他人不能操作。&lt;/li&gt;&#xA;&lt;li&gt;数据库是独立的系统。无法动态调整锁的粒度，并发性能下降。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;tcctry-confirm-cancel&#34;&gt;TCC（Try-Confirm-Cancel）&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Try（预留）：预留相关资源&lt;/li&gt;&#xA;&lt;li&gt;Confirm（确认）：确认操作，完成分布式事务。&lt;/li&gt;&#xA;&lt;li&gt;Cancel（撤销）：如果无法操作，则进行撤销操作。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;TCC本质上是补偿事务，核心思想是针对每个操作都要注册一个与之对应的确认操作和撤销操作。它是一个业务层面的协议。在业务中实现分布式事务。对业务代码的侵入性较高。实现的复杂度更高。&lt;/p&gt;&#xA;&lt;h2 id=&#34;base理论&#34;&gt;BASE理论&lt;/h2&gt;&#xA;&lt;p&gt;BASE理论是CAP理论中的AP的延伸，是互联网大规模分布式系统的实践总结，强调可用性。BASE理论的核心就是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;基本可用（Basically Available）&lt;/li&gt;&#xA;&lt;li&gt;最终一致性（Eventually Consistent）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;基本可用&#34;&gt;基本可用&lt;/h3&gt;&#xA;&lt;p&gt;当分布式系统出现不可预知的故障时，允许损失部分功能的可用性，保证核心功能的可用性。例如：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;延迟响应&lt;/strong&gt;：12306购票系统出现突发流量时，会将购票请求放入队列中进行排队等待处理，通过牺牲响应时间的可用性，保障核心功能的运行。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;流量削峰&lt;/strong&gt;：在不同的时间，出售不同的票，将请求错开，削弱请求峰值。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;体验降级&lt;/strong&gt;：大流量情况，通过降低图片的清晰度和大小，提升系统的处理能力。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;过载保护&lt;/strong&gt;：请求排队时，如果请求等待时间超时，这时直接拒绝超时请求。或者队列满了之后，清除队列中一定数量的排队请求，保证系统不过载，实现系统的基本可用。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;最终一致性&#34;&gt;最终一致性&lt;/h3&gt;&#xA;&lt;p&gt;​&#x9;&#x9;系统中所有的数据副本在经过一段时间的同步后，最终能达到一个一致的状态。这存在一个短暂的延迟。几乎所有的互联网系统采用的都是最终一致性，只有实在无法使用最终一致性，才使用强一致性或分布式事务。对于金融系统，需要考虑分布式事务。&lt;/p&gt;&#xA;&lt;p&gt;​&#x9;&#x9;如何实现最终一致性？&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;以最新写入的数据为准，比如AP模型的KV存储采用的是这种方式。&lt;/li&gt;&#xA;&lt;li&gt;以第一次写入的数据为准，如果你不希望存储的数据被更改，可以以它为准。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;​&#x9;&#x9;如何实现最终一致性？&lt;/p&gt;</description>
    </item>
    <item>
      <title>Leetcode-数组刷题记录</title>
      <link>http://localhost:1313/posts/%E7%AE%97%E6%B3%95/leetcode-array/</link>
      <pubDate>Fri, 08 Jan 2021 21:58:44 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E7%AE%97%E6%B3%95/leetcode-array/</guid>
      <description>&lt;h2 id=&#34;数组的遍历&#34;&gt;数组的遍历&lt;/h2&gt;&#xA;&lt;h3 id=&#34;485-最大连续1的个数&#34;&gt;485. 最大连续1的个数&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;findMaxConsecutiveOnes&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; nums) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//res存储最长的子数组&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; res &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//count记录的是每个被0隔断的子数组&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; count &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0; i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; nums.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;; i&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;//如果当前元素是1，更新当前子数组的长度&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(nums&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;i&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; 1){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                count&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;//遇到0，比较res, count的大小，并将count重置为0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                res &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Math.&lt;span style=&#34;color:#a6e22e&#34;&gt;max&lt;/span&gt;(res, count);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                count &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//避免最后一个子数组是最大的情况，例如：1,0,1,1,0,1,1,1,1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Math.&lt;span style=&#34;color:#a6e22e&#34;&gt;max&lt;/span&gt;(res, count);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;495-提莫攻击&#34;&gt;495. 提莫攻击&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;findPoisonedDuration&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; timeSeries, &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; duration) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; res &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0; i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; timeSeries.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;; i &lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;//当前能持续的时间&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; time &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; timeSeries&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;i&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; duration &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;1;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;//超过下一次攻击的时间&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(i &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; timeSeries.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;1 &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; time &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; timeSeries&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;i &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                res &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; (timeSeries&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;i &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; timeSeries&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;i&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                res &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; duration;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; res;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;第三大的数&#34;&gt;第三大的数&lt;/h3&gt;&#xA;&lt;p&gt;时间复杂度要求$O(n)$，也就是只能通过一趟遍历完成。&lt;/p&gt;</description>
    </item>
    <item>
      <title>OSTEP阅读笔记-Persistence（三）</title>
      <link>http://localhost:1313/posts/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/os/ostep-persistence/</link>
      <pubDate>Tue, 22 Dec 2020 19:49:48 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/os/ostep-persistence/</guid>
      <description>&lt;h2 id=&#34;chapter-io设备&#34;&gt;Chapter I/O设备&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Q：如何将I/O集成进计算机系统中？&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;h3 id=&#34;361-系统架构&#34;&gt;36.1 系统架构&lt;/h3&gt;&#xA;&lt;p&gt;典型的系统架构如图所示：CPU通过&lt;strong&gt;memory bus&lt;/strong&gt;连接到系统内存。显卡或者其它高速I/O设备通过常规的IO总线（I/O bus，例如PCI）连接到系统。最后是外围总线（peripheral bus，例如SCSI、SATA、USB），他们将最慢的设备连接到系统，包括磁盘、鼠标等。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/os/ostep/chapter-36/36.1.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;362-标准设备&#34;&gt;36.2 标准设备&lt;/h3&gt;&#xA;&lt;p&gt;标准设备包括两部分，分别是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;向系统其他部分展现的硬件/软件接口&lt;/li&gt;&#xA;&lt;li&gt;内部结构，包括设备相关的特定实现，负责具体实现设备展现给系统的抽象接口。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/os/ostep/chapter-36/36.2.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;363-标准协议&#34;&gt;36.3 标准协议&lt;/h3&gt;&#xA;&lt;p&gt;一个简化的设备接口包括三个寄存器：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;一个状态（&lt;strong&gt;status&lt;/strong&gt;）寄存器：读取并查看设备的当前状态&lt;/li&gt;&#xA;&lt;li&gt;一个命令（&lt;strong&gt;command&lt;/strong&gt;）寄存器：用于通知设备执行某个具体任务。&lt;/li&gt;&#xA;&lt;li&gt;一个数据（&lt;strong&gt;data&lt;/strong&gt;）寄存器：将数据传给设备或从设备接收数据。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;通过读写这些寄存器，OS可以控制设备的行为。&lt;/p&gt;&#xA;&lt;p&gt;因此可以将操作步骤设置为如下：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;OS反复读取状态寄存器，等待设备进入可以接受命令的就绪状态。（轮询）&lt;/li&gt;&#xA;&lt;li&gt;OS将数据发送到数据寄存器。&lt;/li&gt;&#xA;&lt;li&gt;OS将命令写入命令寄存器。&lt;/li&gt;&#xA;&lt;li&gt;OS再次通过不断轮询设备，等待并判断设备是否执行完成命令。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Q：如何减少频繁轮询，从而降低管理设备的CPU的开销？&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;h3 id=&#34;364-利用中断减少cpu开销&#34;&gt;36.4 利用中断减少CPU开销&lt;/h3&gt;&#xA;&lt;p&gt;设备可以抛出一个硬件中断，引发CPU跳转执行OS预先定义好的中断服务例程（ISR）或者更为简单的中断处理程序（interrupt handler）。&lt;/p&gt;&#xA;&lt;p&gt;使用中断并非是最佳方案，假如有一个高性能的设备，在CPU第一次轮询时就可以返回结果，那么使用中断反而效率更低。如果设备的速度未知，可以考虑混合策略，先尝试轮询一小段事件，如果设备没有完成操作，此时再使用中断。&lt;/p&gt;&#xA;&lt;p&gt;如果是网络环境中，那么不要使用中断，因为每个数据包都会发生一次中断，那么可能导致OS发生活锁（一直处理中断程序而不处理用户的请求）。&lt;/p&gt;&#xA;&lt;p&gt;另一个基于中断的优化就是合并（coalescing），设备在抛出中断之前往往会等待一小段时间，在此期间如果有其他请求的中断，会将多次中断合并为一次中断抛出。从而降低处理中断的代价。&lt;/p&gt;&#xA;&lt;h3 id=&#34;365-dma方式&#34;&gt;36.5 DMA方式&lt;/h3&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Q：如何减少Programming IO的开销？&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;使用DMA（&lt;strong&gt;Direct Memory Access&lt;/strong&gt;）：DMA引擎是一种特殊设备，它可以协调完成内存和设备间的数据传递，不需要CPU介入。&lt;/p&gt;&#xA;&lt;p&gt;工作过程如下：为了能够将数据传送给设备，OS通过programming告诉DMA引擎数据在内存的位置，要拷贝的大小以及拷贝到哪个设备。在此之后，OS就可以处理其他请求了。当DMA的任务完成后，DMA控制器会抛出一个中断来告诉OS自己完成了数据传输。&lt;/p&gt;&#xA;&lt;h3 id=&#34;366-设备交互的方法&#34;&gt;36.6 设备交互的方法&lt;/h3&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Q：如何与设备通信？&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;使用明确的I/O指令。&lt;/li&gt;&#xA;&lt;li&gt;内存映射I/O（memory-mapped I/O）&#xA;&lt;ul&gt;&#xA;&lt;li&gt;通过这种方式，硬件将设备寄存器映射到指定的内存地址中。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;367-纳入os设备驱动程序&#34;&gt;36.7 纳入OS：设备驱动程序&lt;/h3&gt;&#xA;&lt;p&gt;每个设备都有非常具体的接口，如何将它们纳入OS，而我们希望OS尽可能通用。&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Q：如何实现一个设备无关的OS？&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;操作系统将与IO设备交互的软件称为设备驱动程序。（封装，向上层展现接口即可）&lt;/p&gt;&#xA;&lt;h3 id=&#34;368-ide磁盘驱动程序&#34;&gt;36.8 IDE磁盘驱动程序&lt;/h3&gt;&#xA;&lt;p&gt;基本逻辑如下：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;等待驱动就绪&lt;/strong&gt;：当驱动READY，读取状态寄存器（0x1F7）&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;向命令寄存器写入参数&lt;/strong&gt;：写入扇区数，待访问扇区对应的逻辑块地址（LBA），并将驱动编号（master= 0x00，slave = 0x10，因为IDE允许接入两个硬盘）写入命令寄存器（0x1F2- 0x1F6）。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;开启I/O&lt;/strong&gt;：发送读写命令到命令寄存器。向命令寄存器（0x1F7）中写入&lt;code&gt;READ-WRITE&lt;/code&gt;命令。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;数据传送&lt;/strong&gt;（针对写请求）：等待直到驱动状态为&lt;code&gt;READY&lt;/code&gt;和&lt;code&gt;DRQ&lt;/code&gt;（驱动请求数据），向数据端口写入数据。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;中断处理&lt;/strong&gt;：每个扇区的数据传送结束后都会触发一次中断处理程序，可以合并中断。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;错误处理&lt;/strong&gt;：每次操作之后读取状态寄存器，如果ERROR位被置位。可以读取错误寄存器来获取详细信息。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/os/ostep/chapter-36/36.5.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>OSTEP阅读笔记- Concurrency（二）</title>
      <link>http://localhost:1313/posts/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/os/ostep-concurrency/</link>
      <pubDate>Thu, 17 Dec 2020 16:57:51 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/os/ostep-concurrency/</guid>
      <description>&lt;h2 id=&#34;chapter-26-并发介绍&#34;&gt;Chapter 26 并发介绍&lt;/h2&gt;&#xA;&lt;p&gt;本章介绍为单个运行进程提供的新抽象：thread。线程共享地址空间。&lt;/p&gt;&#xA;&lt;p&gt;每个线程都有自己的PC与自己用于计算的&lt;code&gt;register&lt;/code&gt;。如果有两个线程运行在同一个处理器上，发生&lt;code&gt;context switch&lt;/code&gt;时，与进程不同的是，使用PCB保存进程状态，使用TCB保存线程状态。区别是：地址空间保持不变（不需要切换当前使用的页表）。&lt;/p&gt;&#xA;&lt;p&gt;另一个主要区别在于栈，传统进程只有一个栈，如图26.1所示：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/os/ostep/chapter-26/26.1.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;多线程中，每个线程拥有自己的栈，位于栈上的变量、参数、返回值是无法共享的。&lt;/p&gt;&#xA;&lt;h3 id=&#34;261-实例线程创建&#34;&gt;26.1 实例：线程创建&lt;/h3&gt;&#xA;&lt;p&gt;示例：使用&lt;code&gt;pthead_create()&lt;/code&gt;创建了两个线程，主程序调用&lt;code&gt;pthread_join()&lt;/code&gt;等待指定线程执行完成。&lt;/p&gt;&#xA;&lt;p&gt;线程的执行顺序取决于系统调度。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/os/ostep/chapter-26/26.2.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;262-共享数据导致的问题&#34;&gt;26.2 共享数据导致的问题&lt;/h3&gt;&#xA;&lt;p&gt;多线程对共享数据进行操作会导致非预期结果。&lt;/p&gt;&#xA;&lt;h3 id=&#34;263-核心问题不可控的调度&#34;&gt;26.3 核心问题：不可控的调度&lt;/h3&gt;&#xA;&lt;p&gt;竞态条件（&lt;strong&gt;race condition&lt;/strong&gt;）：结果取决于代码的执行顺序。运气不好会导致错误的结果。&lt;/p&gt;&#xA;&lt;h3 id=&#34;264-原子性&#34;&gt;26.4 原子性&lt;/h3&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Q：如何构建有用的同步原语？需要从硬件中获取那些支持？&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;h3 id=&#34;265-等待另一个线程&#34;&gt;26.5 等待另一个线程&lt;/h3&gt;&#xA;&lt;p&gt;需要研究多线程中的&lt;code&gt;wait/signal&lt;/code&gt;机制。&lt;/p&gt;&#xA;&lt;h2 id=&#34;chapter-27-线程api&#34;&gt;Chapter 27 线程API&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Q：如何创建和控制线程？&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;h3 id=&#34;271-pthread_create&#34;&gt;27.1 pthread_create&lt;/h3&gt;&#xA;&lt;p&gt;在POSIX中：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;pthread.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;pthread_create&lt;/span&gt;( &lt;span style=&#34;color:#66d9ef&#34;&gt;pthread_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;thread&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;pthread_attr_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; attr,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;start_routine)(&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; arg);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参数：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;thread&lt;/strong&gt;：指向pthread_t结构类型的指针，利用它与线程交互。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;attr&lt;/strong&gt;：用于指定该线程可能具有的任何属性，包括设置栈大小、调度优先级。属性通过调用&lt;code&gt;pthread_attr_init()&lt;/code&gt;初始化。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;start_routine&lt;/strong&gt;：一个函数指针，指示线程应该在哪个函数上运行。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;arg&lt;/strong&gt;：传递给线程的参数&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;272-pthread_join&#34;&gt;27.2 pthread_join&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;pthread.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;pthread_join&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;pthread_t&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;thread&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;**&lt;/span&gt;retval);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参数：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;thread&lt;/strong&gt;：指定需要等待的线程&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;retval&lt;/strong&gt;：指向你希望得到的返回值，定义为一个指向void的指针。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;273-锁&#34;&gt;27.3 锁&lt;/h3&gt;&#xA;&lt;p&gt;互斥进入临界区：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;pthread_mutex_lock&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;pthread_mutex_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;mutex);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;pthread_mutex_unlock&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;pthread_mutex_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;mutex);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;pthread_mutex_t&lt;/span&gt; lock &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; PTHREAD_MUTEX_INITIALIZER;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;pthread_mutex_lock&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;lock);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;x &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// or whatever your critical section is&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;pthread_mutex_unlock&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;lock);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;274-条件变量&#34;&gt;27.4 条件变量&lt;/h3&gt;&#xA;&lt;p&gt;当线程之间必须发生某种信号时，如果一个线程在等待另一个线程继续执行某些操作，条件变量就很有用。&lt;/p&gt;</description>
    </item>
    <item>
      <title>OSTEP阅读笔记-Virtuallization（一）</title>
      <link>http://localhost:1313/posts/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/os/ostep-virtualization/</link>
      <pubDate>Sat, 05 Dec 2020 14:21:23 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/os/ostep-virtualization/</guid>
      <description>&lt;h1 id=&#34;进程虚拟化&#34;&gt;进程虚拟化&lt;/h1&gt;&#xA;&lt;h2 id=&#34;chapter-4-进程&#34;&gt;Chapter 4 进程&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Q：如何提供有许多CPU的假象？&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;OS通过&lt;code&gt;Visualizing&lt;/code&gt;  CPU来提供这种假象。通过让一个进程只运行一个时间片，然后切换到其它进程，这样就提供了存在多个虚拟CPU的假象。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;时分共享：典型的就是时间片划分，将一小段时间分配给不同的进程。&lt;/li&gt;&#xA;&lt;li&gt;空分共享：典型的就是磁盘空间，将空间分配给不同的文件。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Qustions：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;如何实现&lt;code&gt;context switch&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;OS如何执行&lt;code&gt;scheduling policy&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;41-抽象进程&#34;&gt;4.1 抽象：进程&lt;/h3&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;OS为正在运行的程序提供的抽象，就是所谓的进程。&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;进程的&lt;code&gt;machine state&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;进程可访问的内存（&lt;code&gt;address space&lt;/code&gt;）：指令和数据存储在&lt;code&gt;address space&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;li&gt;寄存器（&lt;code&gt;register&lt;/code&gt;）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;42-进程api&#34;&gt;4.2 进程API&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;create&lt;/li&gt;&#xA;&lt;li&gt;destroy&lt;/li&gt;&#xA;&lt;li&gt;wait&lt;/li&gt;&#xA;&lt;li&gt;miscellaneous control&lt;/li&gt;&#xA;&lt;li&gt;status&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;43-进程创建的细节&#34;&gt;4.3 进程创建的细节&lt;/h3&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Q: 程序如何转换为进程？换而言之，OS如何启动并运行一个程序？&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;OS将代码和静态数据&lt;code&gt;load&lt;/code&gt;到内存中，加载到进程的&lt;code&gt;address space&lt;/code&gt;。如图4.1所示：&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/os/ostep/chapter-4/program-to-process.jpg&#34; alt=&#34;从程序到进程&#34;&gt;&lt;/p&gt;&#xA;&lt;ol start=&#34;2&#34;&gt;&#xA;&lt;li&gt;加载后，OS在运行前需要执行初始化操作。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;为程序的**运行时栈（run-time stack）**分配一些内存。C程序使用栈存放局部变量，函数参数和返回地址。&lt;/li&gt;&#xA;&lt;li&gt;为**堆（heap）**分配一些内存，C程序中，堆用于显式请求的动态分配数据（&lt;code&gt;malloc &amp;amp; free&lt;/code&gt;）&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;I/O&lt;/code&gt;相关的任务。UNIX中每个进程都会有三个打开的文件描述符（&lt;code&gt;file descriptor&lt;/code&gt;）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;44-进程状态&#34;&gt;4.4 进程状态&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;运行&lt;/li&gt;&#xA;&lt;li&gt;就绪&lt;/li&gt;&#xA;&lt;li&gt;阻塞&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;进程的状态转化图如图4.2所示：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/os/ostep/chapter-4/process-state.jpg&#34; alt=&#34;进程：状态转换&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;45-数据结构&#34;&gt;4.5 数据结构&lt;/h3&gt;&#xA;&lt;p&gt;对于停止的进程，上下文将保存寄存器的内容，通过上下文切换可以使OS恢复运行该进程。&lt;/p&gt;&#xA;&lt;p&gt;下图中的&lt;code&gt;context&lt;/code&gt;就是上下文的数据结构，&lt;code&gt;proc&lt;/code&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/os/ostep/chapter-4/proc.jpg&#34; alt=&#34;xv6的proc结构&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;chapter-5-进程api&#34;&gt;Chapter 5 进程API&lt;/h2&gt;&#xA;&lt;p&gt;本章讨论在UNIX系统中的进程创建。&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Q：如何创建并控制进程？&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;h3 id=&#34;fork-系统调用&#34;&gt;fork() 系统调用&lt;/h3&gt;&#xA;&lt;p&gt;&lt;code&gt;fork()&lt;/code&gt;用于创建新进程，&lt;code&gt;fork&lt;/code&gt;的子进程从&lt;code&gt;fork&lt;/code&gt;处开始执行。示例代码如下：&lt;/p&gt;</description>
    </item>
    <item>
      <title>ThreadLocal解析</title>
      <link>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/java-threadlocal/</link>
      <pubDate>Thu, 03 Dec 2020 11:17:38 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/java-threadlocal/</guid>
      <description>&lt;h1 id=&#34;简介&#34;&gt;简介&lt;/h1&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its &lt;code&gt;get&lt;/code&gt; or &lt;code&gt;set&lt;/code&gt; method) has its own, independently initialized copy of the variable. &lt;code&gt;ThreadLocal&lt;/code&gt; instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;简而言之，&lt;code&gt;ThreadLocal&lt;/code&gt;可以创建一个只能被当前线程访问或修改的变量。&lt;/p&gt;&#xA;&lt;h1 id=&#34;分析&#34;&gt;分析&lt;/h1&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Q：如何实现线程隔离？&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;使用&lt;code&gt;Thread&lt;/code&gt;对象中的&lt;code&gt;ThreadLocalMap&lt;/code&gt;进行数据存储。也就是&lt;code&gt;ThreadLocal&lt;/code&gt;将数据存储到当前的线程对象中，通过&lt;code&gt;Thread.currentThread()&lt;/code&gt;来获取线程，再通过&lt;code&gt;getMap(t)&lt;/code&gt;来获取&lt;code&gt;ThreadLocalMap&lt;/code&gt;。具体内容通过阅读源码来逐步分析。&lt;/p&gt;&#xA;&lt;h2 id=&#34;get&#34;&gt;get&lt;/h2&gt;&#xA;&lt;p&gt;返回当前线程存储的&lt;code&gt;ThreadLocal&lt;/code&gt;值，如果不存在，会进行初始化并返回。通过&lt;code&gt;map.getEntry(this)&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * Returns the value in the current thread&amp;#39;s copy of this&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * thread-local variable.  If the variable has no value for the&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * current thread, it is first initialized to the value returned&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * by an invocation of the {@link #initialValue} method.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; *&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @return the current thread&amp;#39;s value of this thread-local&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; T &lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//获取当前对象&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Thread t &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Thread.&lt;span style=&#34;color:#a6e22e&#34;&gt;currentThread&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//通过getMap获取ThreadLocalMap&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ThreadLocalMap map &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; getMap(t);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (map &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//获取entry&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ThreadLocalMap.&lt;span style=&#34;color:#a6e22e&#34;&gt;Entry&lt;/span&gt; e &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; map.&lt;span style=&#34;color:#a6e22e&#34;&gt;getEntry&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (e &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;@SuppressWarnings&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;unchecked&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            T result &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (T)e.&lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; result;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//不存在则进行初始化&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; setInitialValue();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;getmap&#34;&gt;getMap&lt;/h2&gt;&#xA;&lt;p&gt;返回指定线程的&lt;code&gt;ThreadLocalMap&lt;/code&gt;。&lt;/p&gt;</description>
    </item>
    <item>
      <title>几个Java并发工具类解析</title>
      <link>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/%E5%87%A0%E4%B8%AAjava%E5%B9%B6%E5%8F%91%E5%B7%A5%E5%85%B7%E7%B1%BB%E8%A7%A3%E6%9E%90/</link>
      <pubDate>Sun, 29 Nov 2020 22:40:17 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/%E5%87%A0%E4%B8%AAjava%E5%B9%B6%E5%8F%91%E5%B7%A5%E5%85%B7%E7%B1%BB%E8%A7%A3%E6%9E%90/</guid>
      <description>&lt;h1 id=&#34;countdownlatch&#34;&gt;CountDownLatch&lt;/h1&gt;&#xA;&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;只有当N个线程执行完毕，并且进行&lt;code&gt;countDown&lt;/code&gt;操作时，才允许&lt;code&gt;await&lt;/code&gt;的线程继续执行。否则该线程挂起。&lt;/p&gt;&#xA;&lt;p&gt;适用情况：一个线程需要等待其他N个线程执行完毕，再继续执行，是join的替代。&lt;/p&gt;&#xA;&lt;h2 id=&#34;构造方法&#34;&gt;构造方法&lt;/h2&gt;&#xA;&lt;p&gt;参数&lt;code&gt;count&lt;/code&gt;为计数值，传入&lt;code&gt;AQS&lt;/code&gt;的实现类&lt;code&gt;Sync&lt;/code&gt;设置成AQS的&lt;code&gt;state&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CountDownLatch&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; count) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (count &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; 0) &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; IllegalArgumentException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;count &amp;lt; 0&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;sync&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Sync(count);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;sync&#34;&gt;Sync&lt;/h2&gt;&#xA;&lt;p&gt;通过继承&lt;code&gt;AQS&lt;/code&gt;从而完成同步的核心功能。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Sync&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; AbstractQueuedSynchronizer {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; serialVersionUID &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 4982264981922014374L;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//构造方法&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Sync(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; count) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            setState(count);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getCount&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; getState();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;tryAcquireShared&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; acquires) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; (getState() &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; 0) &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; 1 : &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;1;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;tryReleaseShared&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; releases) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// Decrement count; signal when transition to zero&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (;;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; c &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; getState();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (c &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; 0)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; nextc &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; c&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;1;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (compareAndSetState(c, nextc))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; nextc &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; 0;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;核心方法&#34;&gt;核心方法&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;countDown&lt;/strong&gt;：将count值减1&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;await&lt;/strong&gt;：调用&lt;strong&gt;await&lt;/strong&gt;的线程会被挂起，直到&lt;code&gt;count&lt;/code&gt;为0才继续执行，允许中断&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;await&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; InterruptedException {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        sync.&lt;span style=&#34;color:#a6e22e&#34;&gt;acquireSharedInterruptibly&lt;/span&gt;(1);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;countDown&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        sync.&lt;span style=&#34;color:#a6e22e&#34;&gt;releaseShared&lt;/span&gt;(1);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;await&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; timeout, TimeUnit unit)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; InterruptedException {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; sync.&lt;span style=&#34;color:#a6e22e&#34;&gt;tryAcquireSharedNanos&lt;/span&gt;(1, unit.&lt;span style=&#34;color:#a6e22e&#34;&gt;toNanos&lt;/span&gt;(timeout));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;使用案例&#34;&gt;使用案例&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Driver&lt;/span&gt; { &lt;span style=&#34;color:#75715e&#34;&gt;// ...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; InterruptedException {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     CountDownLatch startSignal &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; CountDownLatch(1);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     CountDownLatch doneSignal &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; CountDownLatch(N);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0; i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; N; &lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;i) &lt;span style=&#34;color:#75715e&#34;&gt;// create and start threads&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Thread(&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Worker(startSignal, doneSignal)).&lt;span style=&#34;color:#a6e22e&#34;&gt;start&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     doSomethingElse();            &lt;span style=&#34;color:#75715e&#34;&gt;// don&amp;#39;t let run yet&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     startSignal.&lt;span style=&#34;color:#a6e22e&#34;&gt;countDown&lt;/span&gt;();      &lt;span style=&#34;color:#75715e&#34;&gt;// let all threads proceed&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     doSomethingElse();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     doneSignal.&lt;span style=&#34;color:#a6e22e&#34;&gt;await&lt;/span&gt;();           &lt;span style=&#34;color:#75715e&#34;&gt;// wait for all to finish&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Worker&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; Runnable {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; CountDownLatch startSignal;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; CountDownLatch doneSignal;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;startSignal&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; startSignal;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;doneSignal&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; doneSignal;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;run&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        startSignal.&lt;span style=&#34;color:#a6e22e&#34;&gt;await&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        doWork();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        doneSignal.&lt;span style=&#34;color:#a6e22e&#34;&gt;countDown&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (InterruptedException ex) {} &lt;span style=&#34;color:#75715e&#34;&gt;// return;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;doWork&lt;/span&gt;() { ... }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;cyclicbarrier&#34;&gt;CyclicBarrier&lt;/h1&gt;&#xA;&lt;h2 id=&#34;简介-1&#34;&gt;简介&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point. CyclicBarriers are useful in programs involving a fixed sized party of threads that must occasionally wait for each other. The barrier is called &lt;em&gt;cyclic&lt;/em&gt; because it can be re-used after the waiting threads are released.&lt;/p&gt;</description>
    </item>
    <item>
      <title>解析线程池ThreadPoolExecutor</title>
      <link>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/%E8%A7%A3%E6%9E%90%E7%BA%BF%E7%A8%8B%E6%B1%A0threadpoolexecutor/</link>
      <pubDate>Thu, 26 Nov 2020 14:05:34 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/%E8%A7%A3%E6%9E%90%E7%BA%BF%E7%A8%8B%E6%B1%A0threadpoolexecutor/</guid>
      <description>&lt;h1 id=&#34;什么是线程池&#34;&gt;什么是线程池&lt;/h1&gt;&#xA;&lt;p&gt;&lt;code&gt;Thread Pool&lt;/code&gt;是一种基于池化思想管理线程的工具，经常出现在多线程程序中。&lt;/p&gt;&#xA;&lt;p&gt;线程池的优点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;降低资源消耗：通过池化技术重复利用已创建线程。&lt;/li&gt;&#xA;&lt;li&gt;提高响应速度：任务到达时，无需等待进程创建即可执行。&lt;/li&gt;&#xA;&lt;li&gt;提高线程的可管理性：使用线程池进行统一的分配、调优和监控。&lt;/li&gt;&#xA;&lt;li&gt;提供更多强大的功能：线程池具备可扩展性，允许开发人员向其中增加更多功能。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h1 id=&#34;为什么用线程池&#34;&gt;为什么用线程池&lt;/h1&gt;&#xA;&lt;p&gt;直接创建线程存在性能开销：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Java中线程是基于内核线程实现的，线程的创建和销毁需要进行系统调用，性能开销较高。&lt;/li&gt;&#xA;&lt;li&gt;Java8中，每个&lt;code&gt;Thread&lt;/code&gt;都需要有一个内核线程的支持，这意味着每个&lt;code&gt;Thread&lt;/code&gt;都需要消耗一定的内核资源。Java8中每个线程栈大小是1M，Java11中，对创建线程操作进行优化，创建一个线程只需要40KB左右。&lt;/li&gt;&#xA;&lt;li&gt;线程切换引起&lt;code&gt;context switch&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;​&#x9;&#x9;使用线程池解决的核心问题就是&lt;strong&gt;资源管理问题&lt;/strong&gt;，多线程环境下，不确定性会带来一些问题：频繁申请/销毁线程会带来额外的开销、存在资源耗尽的风险等。&lt;/p&gt;&#xA;&lt;p&gt;​&#x9;&#x9;使用池化思想将资源统一在一起管理的一种思想，可以最大化收益最小化风险，&lt;/p&gt;&#xA;&lt;h1 id=&#34;threadpoolexecutor&#34;&gt;ThreadPoolExecutor&lt;/h1&gt;&#xA;&lt;h2 id=&#34;继承关系&#34;&gt;继承关系&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;ThreadPoolExecutor&lt;/code&gt;类的继承关系如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/concurrency/pool/ThreadPoolExecutor.jpg&#34; alt=&#34;ThreadPoolExecutor继承关系&#34;&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Executor：顶层的&lt;code&gt;Executor&lt;/code&gt;仅提供一个&lt;code&gt;execute()&lt;/code&gt;接口，实现了提交任务与执行任务的解耦。&lt;/li&gt;&#xA;&lt;li&gt;ExecutorService：继承自&lt;code&gt;Executor&lt;/code&gt;，实现了添加了其他接口，例如：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;为一个或一批异步任务生成Future的方法&lt;/li&gt;&#xA;&lt;li&gt;提供了管控线程池的方法，例如停止线程池运行。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;AbstractExecutorService：实现了&lt;code&gt;ExecutorService&lt;/code&gt;，实现了除&lt;code&gt;execute()&lt;/code&gt;以外的所有方法，将最重要的&lt;code&gt;execute()&lt;/code&gt;交给&lt;code&gt;ThreadPoolExecutor&lt;/code&gt;实现。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;运行机制&#34;&gt;运行机制&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;ThreadPoolExecutor&lt;/code&gt;的基本运行机制如下图所示（图片来源：美团技术团队）：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/concurrency/pool/ThreadPoolExecutor%E6%89%A7%E8%A1%8C%E6%B5%81%E7%A8%8B.png&#34; alt=&#34;ThreadPoolExecutor&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;线程池内部相当于一个生产者消费者模型，将线程池分成两个部分：任务管理、线程管理。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;任务管理相当于生产者，任务提交后，线程池判断该任务的后续操作。&#xA;&lt;ol&gt;&#xA;&lt;li&gt;直接申请线程执行该任务&lt;/li&gt;&#xA;&lt;li&gt;存放到阻塞队列中等待&lt;/li&gt;&#xA;&lt;li&gt;拒绝该任务。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;线程管理部分是消费者，根据任务请求进行线程分配工作，当线程执行完任务后会继续获取新的任务去执行，最终当线程获取不到任务时，线程会进行回收。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;构造方法&#34;&gt;构造方法&lt;/h2&gt;&#xA;&lt;p&gt;核心的构造方法如下，主要参数有：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;corePoolSize&lt;/strong&gt;：核心线程数量&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;maximumPoolSize&lt;/strong&gt;：最大线程数量&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;workQueue&lt;/strong&gt;：BlockingQueue类型，保存等待执行任务的阻塞队列，当提交一个新的任务到线程池时，线程池根据当前状态决定后续处理。可选择以下几种：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;ArrayBlockingQueue&lt;/li&gt;&#xA;&lt;li&gt;LinkedBlockingQueue：Executors.newFixedThreadPool使用该队列&lt;/li&gt;&#xA;&lt;li&gt;SynchronousQueue：同步队列，容量为0，put必须等待take，take等待put，Executors.newCachedThreadPool使用该队列。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;keepAliveTime&lt;/strong&gt;：线程池维护线程所允许的时间。当线程池中的线程数量大于corePoolSize的时候，如果这时没有新的任务提交，核心线程外的线程不会立即销毁，而是会等待，直到等待的时间超过了keepAliveTime。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;threadFactory&lt;/strong&gt;：它是&lt;code&gt;ThreadFactory&lt;/code&gt;类型的变量，用来创建新线程。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;handler&lt;/strong&gt;：&lt;code&gt;RejectedExecutionHandler&lt;/code&gt;类型，表示线程池的拒绝策略。如果阻塞队列满了并且没有空闲的线程，这时如果继续提交任务，就需要采取一种策略处理该任务。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ThreadPoolExecutor&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; corePoolSize,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; maximumPoolSize,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; keepAliveTime,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              TimeUnit unit,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              BlockingQueue&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Runnable&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; workQueue,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              ThreadFactory threadFactory,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                              RejectedExecutionHandler handler) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (corePoolSize &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; 0 &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            maximumPoolSize &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; 0 &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            maximumPoolSize &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; corePoolSize &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            keepAliveTime &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; 0)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; IllegalArgumentException();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (workQueue &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; threadFactory &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; handler &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; NullPointerException();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;acc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; System.&lt;span style=&#34;color:#a6e22e&#34;&gt;getSecurityManager&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt; :&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                AccessController.&lt;span style=&#34;color:#a6e22e&#34;&gt;getContext&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;corePoolSize&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; corePoolSize;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;maximumPoolSize&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; maximumPoolSize;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;workQueue&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; workQueue;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;keepAliveTime&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; unit.&lt;span style=&#34;color:#a6e22e&#34;&gt;toNanos&lt;/span&gt;(keepAliveTime);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;threadFactory&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; threadFactory;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;handler&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; handler;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;线程池的状态&#34;&gt;线程池的状态&lt;/h2&gt;&#xA;&lt;p&gt;线程池的运行状态，由&lt;code&gt;AtomicInteger ctl&lt;/code&gt;维护，其中分为两个参数：&lt;code&gt;runState&lt;/code&gt;和&lt;code&gt;workerCount&lt;/code&gt;，高3位存储&lt;code&gt;runState&lt;/code&gt;，低29位存储&lt;code&gt;workerCount&lt;/code&gt;，提供了位运算的方法来获取对应的参数。线程池的运行状态，通过内部进行调整。&lt;/p&gt;</description>
    </item>
    <item>
      <title>ReentrantReadWriteLock源码分析</title>
      <link>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/reentrantreadwritelock/</link>
      <pubDate>Sun, 22 Nov 2020 17:00:43 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/reentrantreadwritelock/</guid>
      <description>&lt;h1 id=&#34;简介&#34;&gt;简介&lt;/h1&gt;&#xA;&lt;p&gt;ReentrantReadWriteLock分为读锁和写锁两个实例，读锁是共享锁，可被多个读线程同时使用，写锁是独占锁。持有写锁的线程可以继续获取读锁，反之不行。&lt;/p&gt;&#xA;&lt;p&gt;Doug Lea 将持有写锁的线程，去获取读锁，之后释放读锁，最后释放写锁，从写锁降级为读锁的过程称为&lt;strong&gt;锁降级（Lock downgrading）&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;但是，&lt;strong&gt;锁升级&lt;/strong&gt;是不可以的。线程持有读锁的话，在没释放的情况下不能去获取写锁，因为会发生&lt;strong&gt;死锁&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;h1 id=&#34;类的继承关系&#34;&gt;类的继承关系&lt;/h1&gt;&#xA;&lt;p&gt;ReentrantReadWriteLock实现了ReadWriteLock接口，该接口定义了两个方法，分别返回读锁和写锁。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ReentrantReadWriteLock&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; ReadWriteLock, java.&lt;span style=&#34;color:#a6e22e&#34;&gt;io&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Serializable&lt;/span&gt; {}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ReadWriteLock&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * Returns the lock used for reading.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     *&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * @return the lock used for reading&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Lock &lt;span style=&#34;color:#a6e22e&#34;&gt;readLock&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * Returns the lock used for writing.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     *&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * @return the lock used for writing&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Lock &lt;span style=&#34;color:#a6e22e&#34;&gt;writeLock&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;类成员属性&#34;&gt;类成员属性&lt;/h1&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//读锁&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; ReentrantReadWriteLock.&lt;span style=&#34;color:#a6e22e&#34;&gt;ReadLock&lt;/span&gt; readerLock;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//写锁&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; ReentrantReadWriteLock.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteLock&lt;/span&gt; writerLock;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//Sync是AQS的实现类&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; Sync sync;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//Unsafe实例&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; sun.&lt;span style=&#34;color:#a6e22e&#34;&gt;misc&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Unsafe&lt;/span&gt; UNSAFE;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//获取Thread.tid的内存偏移值&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; TID_OFFSET;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            UNSAFE &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; sun.&lt;span style=&#34;color:#a6e22e&#34;&gt;misc&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;getUnsafe&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Class&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;?&amp;gt;&lt;/span&gt; tk &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Thread.&lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            TID_OFFSET &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; UNSAFE.&lt;span style=&#34;color:#a6e22e&#34;&gt;objectFieldOffset&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (tk.&lt;span style=&#34;color:#a6e22e&#34;&gt;getDeclaredField&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tid&amp;#34;&lt;/span&gt;));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (Exception e) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Error(e);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;构造方法&#34;&gt;构造方法&lt;/h1&gt;&#xA;&lt;p&gt;默认的构造方法创建非公平策略的&lt;code&gt;ReentrantReadWriteLock&lt;/code&gt;，传入&lt;code&gt;true&lt;/code&gt;则可以创建公平策略的&lt;code&gt;ReentrantReadWriteLock&lt;/code&gt;。&lt;/p&gt;</description>
    </item>
    <item>
      <title>ReentrantLock源码分析</title>
      <link>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/reentrantlock%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</link>
      <pubDate>Fri, 20 Nov 2020 12:40:08 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/reentrantlock%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</guid>
      <description>&lt;h1 id=&#34;简介&#34;&gt;简介&lt;/h1&gt;&#xA;&lt;p&gt;相对于&lt;code&gt;synchronized&lt;/code&gt;关键字，&lt;code&gt;ReentrantLock&lt;/code&gt;具备以下特点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;可中断&lt;/li&gt;&#xA;&lt;li&gt;可设置超时时间&lt;/li&gt;&#xA;&lt;li&gt;可设置为公平锁&lt;/li&gt;&#xA;&lt;li&gt;支持多个条件变量&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h1 id=&#34;源码实现&#34;&gt;源码实现&lt;/h1&gt;&#xA;&lt;p&gt;可重入锁的实现上，主要关注两点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;可重入线程的再次获取锁的处理&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;可重入锁的释放机制&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;类的继承关系&#34;&gt;类的继承关系&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;ReentrantLock&lt;/code&gt;实现了&lt;code&gt;Lock&lt;/code&gt;接口，&lt;code&gt;Lock&lt;/code&gt;接口定义了锁的通用方法。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ReentrantLock&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; Lock, java.&lt;span style=&#34;color:#a6e22e&#34;&gt;io&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Serializable&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;成员变量&#34;&gt;成员变量&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;sync&lt;/code&gt;代表当前&lt;code&gt;ReentrantLock&lt;/code&gt;使用的获取策略。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; Sync sync;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; serialVersionUID &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 7373984872572414699L;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;构造方法&#34;&gt;构造方法&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;无参构造方法&#xA;&lt;ul&gt;&#xA;&lt;li&gt;默认是非公平策略&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;有参构造方法&#xA;&lt;ul&gt;&#xA;&lt;li&gt;传入&lt;code&gt;true&lt;/code&gt;使用公平策略。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * Creates an instance of {@code ReentrantLock}.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * This is equivalent to using {@code ReentrantLock(false)}.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ReentrantLock&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        sync &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; NonfairSync();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * Creates an instance of {@code ReentrantLock} with the&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * given fairness policy.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     *&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * @param fair {@code true} if this lock should use a fair ordering policy&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ReentrantLock&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; fair) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        sync &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; fair &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; FairSync() : &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; NonfairSync();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;获取锁的策略&#34;&gt;获取锁的策略&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;ReentrantLock&lt;/code&gt;内部有三个内部类，其中&lt;code&gt;Sync&lt;/code&gt;是其它两个类&lt;code&gt;NonfairSync&lt;/code&gt;和&lt;code&gt;FairSync&lt;/code&gt;的父类，分别代表着非公平策略和公平策略。&lt;/p&gt;</description>
    </item>
    <item>
      <title>《程序员练级攻略》 阅读总结</title>
      <link>http://localhost:1313/posts/%E9%9A%8F%E7%AC%94/programmer-study-manual/</link>
      <pubDate>Tue, 17 Nov 2020 14:41:20 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E9%9A%8F%E7%AC%94/programmer-study-manual/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;​&#x9;&#x9;陈皓叔叔的这个专栏之前就有所耳闻并大致过了一遍，如今重新精读本专栏，认真学习，对整体的学习方向进行把握，并且进行总结。&lt;/p&gt;&#xA;&lt;p&gt;如何入门？&lt;/p&gt;&#xA;&lt;p&gt;学习Python，JavaScript，学习使用操作系统Linux，编程工具VS Code，Web开发等，这些更容易获得编程的成就感。&lt;/p&gt;&#xA;&lt;p&gt;如何成为专业的程序员？&lt;/p&gt;&#xA;&lt;p&gt;拥有程序员的自我修养。这是反映出程序员的工程师特质和价值观，决定了这条路你到底能走多远。&lt;strong&gt;有修养的程序员才可能成长为真正的工程师和架构师，没有修养的程序员智能沦为码农，这是码农和工程师的关键区分点。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;英文能力&lt;/li&gt;&#xA;&lt;li&gt;提问的能力&lt;/li&gt;&#xA;&lt;li&gt;写代码的修养&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://book.douban.com/subject/4262627/&#34;&gt;重构：改善既有代码的设计&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://book.douban.com/subject/4199741/&#34;&gt;代码整洁之道&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://book.douban.com/subject/11614538/&#34;&gt;程序员的职业素养&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;Code Review&#xA;&lt;ul&gt;&#xA;&lt;li&gt;对自我成长非常有帮助&lt;/li&gt;&#xA;&lt;li&gt;不做Code Review的公司没有必要呆&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Unit Test&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;安全防范意识&#xA;&lt;ul&gt;&#xA;&lt;li&gt;代码安全&lt;/li&gt;&#xA;&lt;li&gt;防御性编程&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;软件工程和上线规范&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://book.douban.com/subject/4187479/&#34;&gt;完美软件：对软件测试的各种幻想&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://book.douban.com/subject/25742200/&#34;&gt;Google软件测试之道&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;编程规范&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;专业基础包括哪些？&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;编程语言：推荐C、C++、Java这三个工业级的编程语言。&lt;/li&gt;&#xA;&lt;li&gt;理论学科：数据结构和算法，计算机网络，计算机组成原理，操作系统，编译原理&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;从业方向？&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;如果你对操作系统、文件系统、数据库、网络等比较感兴趣，那么可以考虑从事底层方面的工作。&lt;/li&gt;&#xA;&lt;li&gt;如果对分布式系统架构、微服务、DevOps、Cloud Native 等有热情，那么可以从事架构方面的工作。&lt;/li&gt;&#xA;&lt;li&gt;如果是对大数据、机器学习、人工智能等比较关注，那么数据领域可以成为你一展身手的地方。&lt;/li&gt;&#xA;&lt;li&gt;如果你对用户体验或者交互等更感兴趣，那么前端工程师也是个不错的选择。&lt;/li&gt;&#xA;&lt;li&gt;此外，安全开发、运维开发、嵌入式开发等几大方向中，也为你提供了丰富多彩的发展空间。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;两个观点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;各种技术方向不是鱼和熊掌，是可以兼得的。&lt;/li&gt;&#xA;&lt;li&gt;很多技术都是相通的，关键是要学的深入本质。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;几个问题：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;理论和现实的差距：学院派的知识是成为专家的必经之路，&lt;strong&gt;这就是“工人”和“工程师&lt;/strong&gt;”的差别，是“建筑工人”和“建筑架构师”的差别。&lt;/li&gt;&#xA;&lt;li&gt;技术太多学不过来/技术能力的瓶颈：自己懒惰的借口，&lt;strong&gt;以绝大多数人努力的程度，和为自己不努力找借口的程度为参考，只要你坚持正常的学习就可以超过大多数人了。&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;学习建议？&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;一定要坚持，要保持长时间学习，甚至终身学习的态度。&lt;/li&gt;&#xA;&lt;li&gt;一定要动手，不管例子多么简单，建议至少自己动手敲一遍看看是否理解了里面的细枝末节。&lt;/li&gt;&#xA;&lt;li&gt;一定要学会思考，思考为什么会这样，要学会举一反三。&lt;/li&gt;&#xA;&lt;li&gt;不要乱买书，不要乱追新技术新名词，基础的东西经过很长时间积累，会在未来至少十年通用。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;编程入门&#34;&gt;编程入门&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;入门语言Python&lt;/li&gt;&#xA;&lt;li&gt;入门语言JavaScript&lt;/li&gt;&#xA;&lt;li&gt;操作系统LInux&lt;/li&gt;&#xA;&lt;li&gt;编程工具VS Code&lt;/li&gt;&#xA;&lt;li&gt;Web入门&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;正式入门&#34;&gt;正式入门&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;编程技能&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;http://blog.thefirehoseproject.com/posts/learn-to-code-and-be-self-reliant/&#34;&gt;如何快速提升自己的编程能力&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;编程技巧&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://book.douban.com/subject/1477390/&#34;&gt;代码大全&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;编程语言&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Java&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;操作系统&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://book.douban.com/subject/30359954/&#34;&gt;鸟哥的Linux私房菜&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;网络协议&#xA;&lt;ul&gt;&#xA;&lt;li&gt;系统了解HTTP协议&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;数据库设计&#xA;&lt;ul&gt;&#xA;&lt;li&gt;基本的设计知识&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://book.douban.com/subject/3354490/&#34;&gt;MySQL必知必会&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;前端&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Vue&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;字符编码方面&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Character_encoding&#34;&gt;Wikipedia&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;为什么转成Java语言？&lt;/p&gt;</description>
    </item>
    <item>
      <title>秒杀系统设计总结</title>
      <link>http://localhost:1313/posts/%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/seckill-summary/</link>
      <pubDate>Mon, 09 Nov 2020 13:29:50 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/seckill-summary/</guid>
      <description>&lt;h1 id=&#34;简介&#34;&gt;简介&lt;/h1&gt;&#xA;&lt;p&gt;秒杀从规模上可以分为以下两类：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;大秒：类似双十一，商品数量规模大，价格低，流量超大的活动。&lt;/li&gt;&#xA;&lt;li&gt;小秒：商家自己配置的一些时段类型的活动，由商家自己指定时间上架。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;秒杀系统面对的问题&#34;&gt;秒杀系统面对的问题&lt;/h2&gt;&#xA;&lt;p&gt;秒杀系统本质上就是一个满足大并发、高性能和高可用的分布式系统。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;高并发环境下的系统稳定性：如何保证系统在面对巨大的流量情况下，不被打崩？&#xA;&lt;ul&gt;&#xA;&lt;li&gt;两个问题&#xA;&lt;ul&gt;&#xA;&lt;li&gt;并发读&#xA;&lt;ul&gt;&#xA;&lt;li&gt;核心优化理念：减少用户到服务端来读数据。或者让他们读取更少的数据。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;并发写&#xA;&lt;ul&gt;&#xA;&lt;li&gt;核心优化理念：在数据库层面独立出来一个库，做特殊的处理。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;大流量会产生以下实际待解决问题&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Redis缓存击穿/雪崩/穿透等问题&lt;/li&gt;&#xA;&lt;li&gt;关系型数据库性能问题，锁竞争对性能的消耗&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;保证数据的最终一致性：库存不能超卖。&lt;/li&gt;&#xA;&lt;li&gt;大数据分析功能：分析本次秒杀活动的商业效益。&lt;/li&gt;&#xA;&lt;li&gt;需要有一个兜底方案，以防最坏的情况发生。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h1 id=&#34;设计&#34;&gt;设计&lt;/h1&gt;&#xA;&lt;h2 id=&#34;架构原则-4要1不要&#34;&gt;架构原则： &amp;ldquo;4要1不要&amp;rdquo;&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;架构是一种平衡的艺术，最好的架构一旦脱离了它所适应的场景，一切都将是空谈。&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;数据要尽量少&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;用户请求的数据能少就少，包括上传给系统的数据和系统返回给用户的数据。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;HTTP请求数尽量少&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;合并CSS，JS文件&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;路径要尽量短&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;用户发出请求到返回数据的过程中，经过的节点要尽量短&#xA;&lt;ul&gt;&#xA;&lt;li&gt;通常，每经过一个节点，都会产生一个新的Socket连接。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;会减少时延&lt;/li&gt;&#xA;&lt;li&gt;可以选择将多个相互强依赖的引用部署在一起，将RPC变成JVM内部的方法调用&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;依赖要尽量少&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;完成一次用户请求必须依赖的系统或服务要少（指的是强依赖）&#xA;&lt;ul&gt;&#xA;&lt;li&gt;比如展示秒杀页面，它强依赖商品信息，用户信息，但是优惠券，成交列表等非必要模块是可以在紧急情况下去掉。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;对系统模块进行分级，0级，1级，2级等&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;不要有单点&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;系统中的单点是系统架构上的一个大忌，单点意味着没有备份，风险不可控。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;如何避免单点？&#xA;&lt;ul&gt;&#xA;&lt;li&gt;避免将服务的状态和机器绑定（服务无状态化）&#xA;&lt;ul&gt;&#xA;&lt;li&gt;把服务的配置动态化（使用配置中心Nacos等）&lt;/li&gt;&#xA;&lt;li&gt;存储服务不好实现，因为数据持久化存储在机器的磁盘里面。文件存储可以通过冗余多个备份的方式来解决单点问题。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;流量过滤&#34;&gt;流量过滤&lt;/h2&gt;&#xA;&lt;p&gt;本质：逐级过滤掉无效的流量。基本有以下一些解决方案：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;活动开始前前端页面的Button无法点击，防止活动尚未开始时，用户进行点击产生流量。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;同时后端需要做相关校验。避免用户直接请求秒杀接口。&lt;/li&gt;&#xA;&lt;li&gt;秒杀url实现动态化，可以选择进行md5加密随机字符串，然后通过另一个接口校验秒杀接口的合法性&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;错峰：前端添加验证码或者答题，防止瞬间产生超高的流量，增加题目辨别难度，避免以图像识别等技术进行破解。&lt;/li&gt;&#xA;&lt;li&gt;校验：对参与活动的用户进行校验拦截。主要从以下几个方面进行判断&#xA;&lt;ul&gt;&#xA;&lt;li&gt;用户白名单&lt;/li&gt;&#xA;&lt;li&gt;用户终端校验：对用户终端类型进行判断&lt;/li&gt;&#xA;&lt;li&gt;IP、MAC、ID校验&lt;/li&gt;&#xA;&lt;li&gt;参与次数校验：避免多次参与活动&lt;/li&gt;&#xA;&lt;li&gt;用户黑名单：避免羊毛党等&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;限流：通过接口限流策略判断请求是否放行&#xA;&lt;ul&gt;&#xA;&lt;li&gt;令牌桶算法&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;性能优化&#34;&gt;性能优化&lt;/h2&gt;&#xA;&lt;p&gt;前面的流量过滤基本过滤掉大部分流量，但是系统性能还需进行优化，主要有以下的解决方案：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;动静分离&lt;/li&gt;&#xA;&lt;li&gt;活动预热：将参加活动的商品独立出来，不和普通的商品库存共享服务，提前将数据缓存到&lt;code&gt;Redis&lt;/code&gt;，查询全部走缓存，扣减库存视情况而定。&lt;/li&gt;&#xA;&lt;li&gt;选择&lt;code&gt;Nginx&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;采用微服务架构部署，提高部署量，均摊请求。&lt;/li&gt;&#xA;&lt;li&gt;秒杀是典型的读多写少的场景，考虑到单体redis的性能问题，可以考虑：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;Redis&lt;/code&gt;集群&lt;/li&gt;&#xA;&lt;li&gt;主从同步&lt;/li&gt;&#xA;&lt;li&gt;读写分离&lt;/li&gt;&#xA;&lt;li&gt;如果使用&lt;code&gt;Redis&lt;/code&gt;集群，同时需要考虑保证多节点的数据一致性&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;异步处理：采用消息队列&#xA;&lt;ul&gt;&#xA;&lt;li&gt;异步，削峰，解耦&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;动静分离&#34;&gt;动静分离&lt;/h3&gt;&#xA;&lt;p&gt;&lt;strong&gt;“动态数据”和“静态数据”的主要区别就是看页面中输出的数据是否和 URL、浏览者、时间、地域相关，以及是否含有 Cookie 等私密数据&lt;/strong&gt;。&lt;/p&gt;</description>
    </item>
    <item>
      <title>LockSupport源码分析</title>
      <link>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/locksupport%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</link>
      <pubDate>Sun, 08 Nov 2020 12:46:28 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/locksupport%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/</guid>
      <description>&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Basic thread blocking primitives for creating locks and other synchronization classes.   &amp;ndash; Java Doc&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;&lt;code&gt;LockSupport&lt;/code&gt;是用来创建锁和其它同步类的基本线程阻塞原语。底层依赖&lt;code&gt;Unsafe&lt;/code&gt;实现，我们可以在其它的并发同步工具类的实现中看到该类的使用。&lt;code&gt;LockSupport&lt;/code&gt;提供了&lt;code&gt;park()&lt;/code&gt;和&lt;code&gt;unpark()&lt;/code&gt;方法来分别实现阻塞线程和唤醒线程，每个使用&lt;code&gt;LockSupport&lt;/code&gt;的线程都有一个&lt;code&gt;permit&lt;/code&gt;，该值默认为0，取值0,1。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;unpark()&lt;/code&gt;：如果&lt;code&gt;permit&lt;/code&gt;当前值为0，将其自增1。&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;park()&lt;/code&gt;：如果当前&lt;code&gt;permit&lt;/code&gt;为1，将其自减1并立即返回，如果为0，直接阻塞。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这两个方法不会有&lt;code&gt;Thread.suspend&lt;/code&gt; 和&lt;code&gt;Thread.resume&lt;/code&gt;所可能引发的死锁问题，因为&lt;code&gt;permit&lt;/code&gt;存在，调用 &lt;code&gt;park &lt;/code&gt;的线程和另一个试图将其 &lt;code&gt;unpark &lt;/code&gt;的线程之间的竞争将保持活性。&lt;/p&gt;&#xA;&lt;p&gt;如果调用线程被中断，那么&lt;code&gt;park&lt;/code&gt;将会返回。&lt;code&gt;park&lt;/code&gt;方法可能在任何时间&lt;strong&gt;no reason&lt;/strong&gt;地返回，因此通常在重新检查返回条件地循环里调用此方法。在某种意义上，&lt;code&gt;park&lt;/code&gt;是&lt;strong&gt;busy wait&lt;/strong&gt;（忙则等待）的一种优化，减少了自旋对性能的消耗。当时必须与&lt;code&gt;unpark&lt;/code&gt;配合使用才会更加高效。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;park&lt;/code&gt;还提供了支持&lt;code&gt;blocker&lt;/code&gt;参数的方法，&lt;code&gt;blocker&lt;/code&gt;对象在线程受阻塞时被记录，用于允许监视和诊断工具确定线程被阻塞的原因。提供了&lt;code&gt;getBlocker(Thread t)&lt;/code&gt;来访问&lt;code&gt;blocker&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;下面是&lt;code&gt;Java Docs&lt;/code&gt;中的示例用法：一个先进先出非重入锁类的基本框架：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;FIFOMutex&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; AtomicBoolean locked &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; AtomicBoolean(&lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; Queue&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Thread&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; waiters&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ConcurrentLinkedQueue&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Thread&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;lock&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; wasInterrupted &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Thread current &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Thread.&lt;span style=&#34;color:#a6e22e&#34;&gt;currentThread&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      waiters.&lt;span style=&#34;color:#a6e22e&#34;&gt;add&lt;/span&gt;(current);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;// Block while not first in queue or cannot acquire lock&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; (waiters.&lt;span style=&#34;color:#a6e22e&#34;&gt;peek&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; current &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;locked.&lt;span style=&#34;color:#a6e22e&#34;&gt;compareAndSet&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;)) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        LockSupport.&lt;span style=&#34;color:#a6e22e&#34;&gt;park&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (Thread.&lt;span style=&#34;color:#a6e22e&#34;&gt;interrupted&lt;/span&gt;()) &lt;span style=&#34;color:#75715e&#34;&gt;// ignore interrupts while waiting&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          wasInterrupted &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      waiters.&lt;span style=&#34;color:#a6e22e&#34;&gt;remove&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (wasInterrupted)          &lt;span style=&#34;color:#75715e&#34;&gt;// reassert interrupt status on exit&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        current.&lt;span style=&#34;color:#a6e22e&#34;&gt;interrupt&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;unlock&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      locked.&lt;span style=&#34;color:#a6e22e&#34;&gt;set&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      LockSupport.&lt;span style=&#34;color:#a6e22e&#34;&gt;unpark&lt;/span&gt;(waiters.&lt;span style=&#34;color:#a6e22e&#34;&gt;peek&lt;/span&gt;());&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#xA;&lt;h2 id=&#34;源码解读&#34;&gt;源码解读&lt;/h2&gt;&#xA;&lt;h3 id=&#34;成员变量&#34;&gt;成员变量&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;UNSAFE：用于进行内存级别操作的工具类。&lt;/li&gt;&#xA;&lt;li&gt;parkBlockerOffset：存储&lt;code&gt;Thread.parkBlocker&lt;/code&gt;的内存偏移地址，记录线程被谁阻塞的。用于线程监控和分析工具用来定位原因的。可以通过&lt;code&gt;getBlocker&lt;/code&gt;获取到阻塞的对象。&lt;/li&gt;&#xA;&lt;li&gt;SEED：存储&lt;code&gt;Thread.threadLocalRandomSeed&lt;/code&gt;的内存偏移地址&lt;/li&gt;&#xA;&lt;li&gt;PROBE：存储&lt;code&gt;Thread.threadLocalRandomProbe&lt;/code&gt;的内存偏移地址&lt;/li&gt;&#xA;&lt;li&gt;SECONDARY：存储&lt;code&gt;Thread.threadLocalRandomSecondarySeed&lt;/code&gt;的内存偏移地址&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; sun.&lt;span style=&#34;color:#a6e22e&#34;&gt;misc&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Unsafe&lt;/span&gt; UNSAFE;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; parkBlockerOffset;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; SEED;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; PROBE;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; SECONDARY;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;构造方法&#34;&gt;构造方法&lt;/h3&gt;&#xA;&lt;p&gt;不允许实例化，只能通过调用静态方法来完成操作。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Java原子类的使用与实现</title>
      <link>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/java%E5%8E%9F%E5%AD%90%E7%B1%BB%E7%9A%84%E4%BD%BF%E7%94%A8%E4%B8%8E%E5%AE%9E%E7%8E%B0/</link>
      <pubDate>Thu, 29 Oct 2020 19:39:23 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/java%E5%8E%9F%E5%AD%90%E7%B1%BB%E7%9A%84%E4%BD%BF%E7%94%A8%E4%B8%8E%E5%AE%9E%E7%8E%B0/</guid>
      <description>&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;&#xA;&lt;p&gt;通常情况下，在Java中，&lt;code&gt;++i&lt;/code&gt;这类自增/自减运算符在并发环境中不能保证并发安全。需要通过加锁才能解决并发环境下的原子性问题。Atomic原子类通过CAS方式来解决线程安全问题，CAS是一种无锁算法（乐观锁），乐观锁多用于“读多写少“的环境，避免频繁加锁影响性能；而悲观锁多用于”写多读少“的环境，避免频繁失败和重试影响性能。&lt;/p&gt;&#xA;&lt;p&gt;Atomic原子类分为以下几类：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;基本类型：AtomicInteger，AtomicLong，AtomicBoolean&lt;/li&gt;&#xA;&lt;li&gt;数组类型：AtomicIntegerArray，AtomicLongArray，AtomicReferenceArray&lt;/li&gt;&#xA;&lt;li&gt;引用类型：AtomicReference，AtomicStampedRerence，AtomicMarkableReference&lt;/li&gt;&#xA;&lt;li&gt;更新字段类：AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater&lt;/li&gt;&#xA;&lt;li&gt;Java8 新增类：DoubleAccumulator，DoubleAdder，LongAccumulator，LongAdder&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;使用&#34;&gt;使用&lt;/h2&gt;&#xA;&lt;h3 id=&#34;原子基本类型&#34;&gt;原子基本类型&lt;/h3&gt;&#xA;&lt;p&gt;使用原子的方式更新基本类型。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;AtomicBoolean: 原子布尔类型。&lt;/li&gt;&#xA;&lt;li&gt;AtomicInteger: 原子整型。&lt;/li&gt;&#xA;&lt;li&gt;AtomicLong: 原子长整型。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;以下以&lt;code&gt;AtomInteger&lt;/code&gt;举例：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//以原子方式将给定值与当前值相加，线程安全的i = i + delta&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;addAndGet&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; delta);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//如果当前值== except，则以原子方式将当前值设置为update，成功返回true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;compareAndSet&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; expect, &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; update);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//以原子方式将当前值减1，相当于线程安全的i--&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;decrementAndGet&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//以原子方式将当前值加1，相当于线程安全的i++&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;incrementAndGet&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; Unsafe unsafe &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Unsafe.&lt;span style=&#34;color:#a6e22e&#34;&gt;getUnsafe&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; valueOffset;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            valueOffset &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; unsafe.&lt;span style=&#34;color:#a6e22e&#34;&gt;objectFieldOffset&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                (AtomicInteger.&lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;getDeclaredField&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;value&amp;#34;&lt;/span&gt;));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt; (Exception ex) { &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Error(ex); }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;volatile&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; value;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * Atomically increments by one the current value.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     *&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * @return the updated value&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;incrementAndGet&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; unsafe.&lt;span style=&#34;color:#a6e22e&#34;&gt;getAndAddInt&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;, valueOffset, 1) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; 1;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * Atomically decrements by one the current value.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     *&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * @return the updated value&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;decrementAndGet&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; unsafe.&lt;span style=&#34;color:#a6e22e&#34;&gt;getAndAddInt&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;, valueOffset, &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;1) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; 1;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从上面代码可以看出，AtomicInteger底层使用&lt;code&gt;volatile&lt;/code&gt;关键字和CAS来保证线程安全。其中：&lt;/p&gt;</description>
    </item>
    <item>
      <title>volatile关键字剖析</title>
      <link>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/volatile%E5%85%B3%E9%94%AE%E5%AD%97%E5%89%96%E6%9E%90/</link>
      <pubDate>Sat, 24 Oct 2020 21:59:36 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/volatile%E5%85%B3%E9%94%AE%E5%AD%97%E5%89%96%E6%9E%90/</guid>
      <description>&lt;h2 id=&#34;定义&#34;&gt;定义&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;The Java programming language allows threads to access shared variables (§17.1).As a rule, to ensure that shared variables are consistently and reliably updated, a thread should ensure that it has exclusive use of such variables by obtaining a lock that, conventionally, enforces mutual exclusion for those shared variables.The Java programming language provides a second mechanism, volatile fields,that is more convenient than locking for some purposes.A field may be declared volatile, in which case the Java Memory Model ensures that all threads see a consistent value for the variable (§17.4).&lt;/p&gt;</description>
    </item>
    <item>
      <title>synchronized关键字剖析</title>
      <link>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/synchronized%E5%85%B3%E9%94%AE%E5%AD%97%E5%89%96%E6%9E%90/</link>
      <pubDate>Sun, 11 Oct 2020 22:59:39 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/synchronized%E5%85%B3%E9%94%AE%E5%AD%97%E5%89%96%E6%9E%90/</guid>
      <description>&lt;h2 id=&#34;使用&#34;&gt;使用&lt;/h2&gt;&#xA;&lt;p&gt;在使用&lt;code&gt;Synchronized&lt;/code&gt;关键字需要把握以下注意点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;一把锁只能同时被一个线程获取，没有获得锁的线程只能等待。&lt;/li&gt;&#xA;&lt;li&gt;每一个实例都有自己的一个锁资源，存放于对象头中（2bit表示锁信息）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;对象锁&#34;&gt;对象锁&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;同步代码块锁（可以指定锁定对象）&lt;/li&gt;&#xA;&lt;li&gt;方法锁（默认锁定对象为this（当前实例对象））&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;test&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;synchronized&lt;/span&gt; (obj){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;synchronized&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;test&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;类锁&#34;&gt;类锁&lt;/h3&gt;&#xA;&lt;p&gt;&lt;code&gt;synchronized&lt;/code&gt;修饰静态方法或指定锁对象为Class对象。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;synchronized&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;method&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//do something&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;synchronized&lt;/span&gt;(ObjectDemo.&lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;理论基础&#34;&gt;理论基础&lt;/h2&gt;&#xA;&lt;p&gt;在操作系统进程管理中，对进程并发问题主要提供了两种解决方法：信号量和管程。在Java 1.5之前，提供的唯一并发原语就是管程，Java 1.5之后提供的JUC包也是以管程技术为基础的。&lt;/p&gt;&#xA;&lt;h3 id=&#34;管程定义&#34;&gt;管程定义&lt;/h3&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;一个管程定义了一个数据结构和能为并发进程所执行的一组操作，这组操作能同步进程和改变管程中的数据。&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;通俗而言：管程（Monitor）是管理共享变量以及对共享变量的操作过程，让他们支持并发。在OS领域一般称为管程，Java中可以称为&lt;strong&gt;监视器&lt;/strong&gt;（monitor）。&lt;/p&gt;&#xA;&lt;h3 id=&#34;mesa模型&#34;&gt;MESA模型&lt;/h3&gt;&#xA;&lt;p&gt;MESA模型是当今广泛使用的MESA模型，Java管程的实现参考的也是MESA模型。并对其进行了精简。Java内置的管程只有一个条件变量。&lt;/p&gt;&#xA;&lt;p&gt;如下图所示：管程X将共享变量queue、入队操作于出队操作封装起来。如果线程A和线程B访问共享变量queue，只能通过调用管程提供的&lt;code&gt;enq()&lt;/code&gt;和&lt;code&gt;deq()&lt;/code&gt;来实现。两个方法保证互斥性，，只允许一个线程进入管程并操作。该模型能实现并发编程中的互斥问题。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/java/concurrent/sync/MESA.jpg&#34; alt=&#34;管程&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;下图为MESA管程模型示意图，框中即是封装的管程，所有线程通过入口等待队列进入管程。管程还引入了条件变量的概念，&lt;strong&gt;每一个条件变量都对应一个等待队列&lt;/strong&gt;。管程的同步主要通过&lt;code&gt;Condition&lt;/code&gt;（条件变量）实现。&lt;code&gt;Condition&lt;/code&gt;可以执行&lt;code&gt;wait()&lt;/code&gt;和&lt;code&gt;signal()&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;假设线程T1执行出队操作，同时有个前提条件：队列不为空，这是条件变量。如果T1进入管程发现队列为空，则会在条件变量的等待队列进行等待。调用&lt;code&gt;wait()&lt;/code&gt;实现。此刻允许其它线程进入管程。&lt;/p&gt;&#xA;&lt;p&gt;此时线程T2执行入队操作，入队成功后，队列不空条件对于T1已经满足，T2调用&lt;code&gt;notify()&lt;/code&gt;来通知T1。通知他条件已满足。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/java/concurrent/sync/MESA1.jpg&#34; alt=&#34;MESA管程模型&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;两个操作&#34;&gt;两个操作&lt;/h3&gt;&#xA;&lt;h4 id=&#34;wait&#34;&gt;wait&lt;/h4&gt;&#xA;&lt;p&gt;MESA模型提供了一个特有的编程范式，通过循环检查条件调用&lt;code&gt;wait()&lt;/code&gt;。管程模型中：条件满足后，如何通知相关线程。管程要求同一时刻只能有一个线程能执行，那么上述问题中T1，T2谁执行呢？&lt;/p&gt;&#xA;&lt;p&gt;在MESA中，T2通过&lt;code&gt;notify()&lt;/code&gt;通知完后，继续执行，T1从条件变量的等待队列进入入口等待队列中。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt;(条件不满足) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;wait();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;signal&#34;&gt;signal&lt;/h4&gt;&#xA;&lt;p&gt;尽量使用&lt;code&gt;notifyAll()&lt;/code&gt;，如果满足以下三个条件则可以使用&lt;code&gt;notify()&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;所有等待线程拥有相同的等待条件&lt;/li&gt;&#xA;&lt;li&gt;所有等待线程被唤醒后，执行相同的操作&lt;/li&gt;&#xA;&lt;li&gt;只需要唤醒一个线程&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;实现&#34;&gt;实现&lt;/h2&gt;&#xA;&lt;h3 id=&#34;jvm字节码层面&#34;&gt;JVM字节码层面&lt;/h3&gt;&#xA;&lt;p&gt;从JVM层面来看，主要通过两个字节码指令实现，&lt;code&gt;monitorenter&lt;/code&gt;与&lt;code&gt;monitorexit&lt;/code&gt;。这两个字节码需要指定一个对象引用作为参数。这个对象引用就是monitor object。它就是synchronized传入的对象实例，该对象充当着维护了mutex以及顶层父类&lt;code&gt;Object&lt;/code&gt;提供的&lt;code&gt;wait/notify&lt;/code&gt;机制。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;wang&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;l1n&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;volatile1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Demo02&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; wang.&lt;span style=&#34;color:#a6e22e&#34;&gt;l1n&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;volatile1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Demo02&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Code:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       0: aload_0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       1: invokespecial &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;1                  &lt;span style=&#34;color:#75715e&#34;&gt;// Method java/lang/Object.&amp;#34;&amp;lt;init&amp;gt;&amp;#34;:()V&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       4: &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;(java.&lt;span style=&#34;color:#a6e22e&#34;&gt;lang&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;String&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Code:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       0: getstatic     &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;2                  &lt;span style=&#34;color:#75715e&#34;&gt;// Field object:Ljava/lang/Object;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       3: dup&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       4: astore_1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       5: monitorenter&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       6: getstatic     &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;3                  &lt;span style=&#34;color:#75715e&#34;&gt;// Field java/lang/System.out:Ljava/io/PrintStream;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       9: ldc           &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;4                  &lt;span style=&#34;color:#75715e&#34;&gt;// String hello world&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      11: invokevirtual &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;5                  &lt;span style=&#34;color:#75715e&#34;&gt;// Method java/io/PrintStream.println:(Ljava/lang/String;)V&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      14: aload_1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      15: monitorexit&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      16: &lt;span style=&#34;color:#66d9ef&#34;&gt;goto&lt;/span&gt;          24&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      19: astore_2&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      20: aload_1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      21: monitorexit&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      22: aload_2&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      23: athrow&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      24: &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Exception table:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       from    to  target type&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           6    16    19   any&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          19    22    19   any&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; {};&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Code:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       0: &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt;           &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;6                  &lt;span style=&#34;color:#75715e&#34;&gt;// class java/lang/Object&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       3: dup&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       4: invokespecial &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;1                  &lt;span style=&#34;color:#75715e&#34;&gt;// Method java/lang/Object.&amp;#34;&amp;lt;init&amp;gt;&amp;#34;:()V&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       7: putstatic     &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;2                  &lt;span style=&#34;color:#75715e&#34;&gt;// Field object:Ljava/lang/Object;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      10: &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;jvm实现层面&#34;&gt;JVM实现层面&lt;/h3&gt;&#xA;&lt;p&gt;每个Java对象都关联一个Monitor对象，如果使用&lt;code&gt;synchronized&lt;/code&gt;给对象上锁，该对象的&lt;code&gt;MarkWord&lt;/code&gt;中就被设置指向Monitor对象的指针。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Java8特性</title>
      <link>http://localhost:1313/posts/java%E5%9F%BA%E7%A1%80/java8-note/</link>
      <pubDate>Thu, 13 Aug 2020 13:31:02 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%9F%BA%E7%A1%80/java8-note/</guid>
      <description>&lt;h2 id=&#34;lambda表达式&#34;&gt;Lambda表达式&lt;/h2&gt;&#xA;&lt;h3 id=&#34;函数式编程简介&#34;&gt;函数式编程简介&lt;/h3&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;函数式编程（英语：functional programming）或称函数程序设计、泛函编程，是一种编程范式，它将电脑运算视为函数运算，并且避免使用程序状态以及易变对象。其中，λ演算（lambda calculus）为该语言最重要的基础。而且，λ演算的函数可以接受函数当作输入（引数）和输出（传出值）。（摘自Wikipedia）&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;面向对象编程是对数据进行抽象；函数式编程是对行为进行抽象。&lt;/p&gt;&#xA;&lt;p&gt;核心思想: 使用不可变值和函数，函数对一个值进行处理，映射成另一个值。&lt;/p&gt;&#xA;&lt;h3 id=&#34;lambda语法格式&#34;&gt;Lambda语法格式&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//无参数，无返回值&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Runnable runnable &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ()&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello world&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        runnable.&lt;span style=&#34;color:#a6e22e&#34;&gt;run&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//有一个参数，无返回值&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Consumer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;String&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; consumer &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (e) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(e);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        consumer.&lt;span style=&#34;color:#a6e22e&#34;&gt;accept&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello world&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//两个参数，多条语句&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Comparator&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Integer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; comparator &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (a, b) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello world&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; Integer.&lt;span style=&#34;color:#a6e22e&#34;&gt;compare&lt;/span&gt;(a, b);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//lambda中只有一条语句，可简写&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Comparator&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Integer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; comparator1 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (a, b) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Integer.&lt;span style=&#34;color:#a6e22e&#34;&gt;compare&lt;/span&gt;(a, b);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//省略参数类型&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Comparator&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Integer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; comparator2 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (Integer a, Integer b) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Integer.&lt;span style=&#34;color:#a6e22e&#34;&gt;compare&lt;/span&gt;(a, b);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Comparator&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Integer&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; comparator3 &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (a, b) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; Integer.&lt;span style=&#34;color:#a6e22e&#34;&gt;compare&lt;/span&gt;(a, b);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;函数式接口&#34;&gt;函数式接口&lt;/h3&gt;&#xA;&lt;p&gt;接口中只有一个抽象方法的接口（不包括默认方法），称为函数式接口。使用&lt;code&gt;@FunctionInterface&lt;/code&gt;注解修饰，用来检查是否满足条件。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Integer小细节</title>
      <link>http://localhost:1313/posts/java%E5%9F%BA%E7%A1%80/java-type/</link>
      <pubDate>Thu, 06 Aug 2020 21:55:21 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%9F%BA%E7%A1%80/java-type/</guid>
      <description>&lt;h2 id=&#34;integer&#34;&gt;Integer&lt;/h2&gt;&#xA;&lt;h3 id=&#34;integercache&#34;&gt;IntegerCache&lt;/h3&gt;&#xA;&lt;p&gt;在Java中，创建的对象会存储在堆内存，·IntegerCache·主要用来做缓存，减少内存的重复消耗。但是&lt;code&gt;IntegerCache&lt;/code&gt;缓存的数据范围在-128到127之间。可以通过 &lt;code&gt;-XX:AutoBoxCacheMax=high&lt;/code&gt; 来指定这个缓冲池的大小，JVM通过&lt;code&gt; java.lang.IntegerCache.high&lt;/code&gt; 系统属性来存储该值，&lt;code&gt;IntegerCache&lt;/code&gt;初始化的时候就会读取该系统属性来决定大小。以下为源码：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IntegerCache&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; low &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;128;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; high;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; Integer cache&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// high value may be configured by property&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; h &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 127;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;//读取JVM参数值&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            String integerCacheHighPropValue &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                sun.&lt;span style=&#34;color:#a6e22e&#34;&gt;misc&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;VM&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;getSavedProperty&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;java.lang.Integer.IntegerCache.high&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;//初始化high&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (integerCacheHighPropValue &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;try&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; parseInt(integerCacheHighPropValue);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Math.&lt;span style=&#34;color:#a6e22e&#34;&gt;max&lt;/span&gt;(i, 127);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#75715e&#34;&gt;// Maximum array size is Integer.MAX_VALUE&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    h &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Math.&lt;span style=&#34;color:#a6e22e&#34;&gt;min&lt;/span&gt;(i, Integer.&lt;span style=&#34;color:#a6e22e&#34;&gt;MAX_VALUE&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;low) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;1);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                } &lt;span style=&#34;color:#66d9ef&#34;&gt;catch&lt;/span&gt;( NumberFormatException nfe) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    &lt;span style=&#34;color:#75715e&#34;&gt;// If the property cannot be parsed into an int, ignore it.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            high &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; h;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;//127 - (-128) + 1为数组容量&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            cache &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Integer&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;(high &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; low) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;//初始化Cache数组&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; j &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; low;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; k &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0; k &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; cache.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;; k&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                cache&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;k&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Integer(j&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// range [-128, 127] must be interned (JLS7 5.1.7)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;assert&lt;/span&gt; IntegerCache.&lt;span style=&#34;color:#a6e22e&#34;&gt;high&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; 127;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IntegerCache&lt;/span&gt;() {}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;integervalueof&#34;&gt;Integer.valueOf()&lt;/h3&gt;&#xA;&lt;p&gt;首先看一下关于该方法的实现：&lt;/p&gt;</description>
    </item>
    <item>
      <title>TreeMap源码分析</title>
      <link>http://localhost:1313/posts/java%E9%9B%86%E5%90%88/java-treemap/</link>
      <pubDate>Wed, 05 Aug 2020 09:17:29 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E9%9B%86%E5%90%88/java-treemap/</guid>
      <description>&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;TreeMap&lt;/code&gt;底层通过红黑树实现，在查询性能上能达到&lt;code&gt;O(logn)&lt;/code&gt;，由于使用红黑树结构进行存储，所以&lt;code&gt;TreeMap&lt;/code&gt;的元素都是有序的。同时，这也是一个非线程安全的&lt;code&gt;Map&lt;/code&gt;，无法在并发环境下使用。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;TreeMap&lt;/code&gt;继承自&lt;code&gt;AbstractMap&lt;/code&gt;，该类Map接口的抽象实现。实现了 &lt;code&gt;NavigableMap&lt;/code&gt;、&lt;code&gt;Cloneable&lt;/code&gt;和 &lt;code&gt;Serializable&lt;/code&gt;接口。其中&lt;code&gt;NavigableMap&lt;/code&gt;继承自&lt;code&gt;SortedMap&lt;/code&gt;，这保证了&lt;code&gt;TreeMap&lt;/code&gt;的有序性。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;TreeMap&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K,V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; AbstractMap&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K,V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; NavigableMap&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K,V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;, Cloneable, java.&lt;span style=&#34;color:#a6e22e&#34;&gt;io&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Serializable&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;数据结构&#34;&gt;数据结构&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;TreeMap&lt;/code&gt;采用红黑树进行构建，红黑树是一种自平衡二叉查找树。插入、删除、查找的时间复杂度为&lt;code&gt;O(logn)&lt;/code&gt;。与另一个自平衡二叉查找树&lt;code&gt;AVL Tree&lt;/code&gt;相比，红黑树以减少旋转操作牺牲部分平衡性，但是其整体性能优于&lt;code&gt;AVL Tree&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;有关红黑树的定义如下（摘自wikipedia）：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;节点是红色或黑色。&lt;/li&gt;&#xA;&lt;li&gt;根是黑色。&lt;/li&gt;&#xA;&lt;li&gt;所有叶子都是黑色（叶子是NIL节点）。&lt;/li&gt;&#xA;&lt;li&gt;每个红色节点必须有两个黑色的子节点。（从每个叶子到根的所有路径上不能有两个连续的红色节点。）&lt;/li&gt;&#xA;&lt;li&gt;从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/java/treemap/rbtree-construction.png&#34; alt=&#34;红黑树结构示意图（摘自Wikipedia）&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;TreeMap&lt;/code&gt;中树节点的定义如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Entry&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K,V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; Map.&lt;span style=&#34;color:#a6e22e&#34;&gt;Entry&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K,V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        K key;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        V value;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Entry&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K,V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; left;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Entry&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K,V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; right;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Entry&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K,V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; parent;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; color &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; BLACK;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Entry(K key, V value, Entry&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K,V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; parent) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; key;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; value;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;parent&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; parent;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; K &lt;span style=&#34;color:#a6e22e&#34;&gt;getKey&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; key;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; V &lt;span style=&#34;color:#a6e22e&#34;&gt;getValue&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; value;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; V &lt;span style=&#34;color:#a6e22e&#34;&gt;setValue&lt;/span&gt;(V value) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            V oldValue &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; value;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; oldValue;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;equals&lt;/span&gt;(Object o) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;(o &lt;span style=&#34;color:#66d9ef&#34;&gt;instanceof&lt;/span&gt; Map.&lt;span style=&#34;color:#a6e22e&#34;&gt;Entry&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            Map.&lt;span style=&#34;color:#a6e22e&#34;&gt;Entry&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;?&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;?&amp;gt;&lt;/span&gt; e &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (Map.&lt;span style=&#34;color:#a6e22e&#34;&gt;Entry&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;?&lt;/span&gt;,&lt;span style=&#34;color:#f92672&#34;&gt;?&amp;gt;&lt;/span&gt;)o;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; valEquals(key,e.&lt;span style=&#34;color:#a6e22e&#34;&gt;getKey&lt;/span&gt;()) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; valEquals(value,e.&lt;span style=&#34;color:#a6e22e&#34;&gt;getValue&lt;/span&gt;());&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hashCode&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; keyHash &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (key&lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; 0 : key.&lt;span style=&#34;color:#a6e22e&#34;&gt;hashCode&lt;/span&gt;());&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; valueHash &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (value&lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; 0 : value.&lt;span style=&#34;color:#a6e22e&#34;&gt;hashCode&lt;/span&gt;());&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; keyHash &lt;span style=&#34;color:#f92672&#34;&gt;^&lt;/span&gt; valueHash;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; String &lt;span style=&#34;color:#a6e22e&#34;&gt;toString&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; key &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;=&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; value;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;成员变量&#34;&gt;成员变量&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//TreeMap中用来确定顺序的comparator&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; Comparator&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;?&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;super&lt;/span&gt; K&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; comparator;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//树的根节点&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;transient&lt;/span&gt; Entry&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K,V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; root;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//树的大小&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;transient&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; size &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//结构变化计数器&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;transient&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; modCount &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//EntrySet&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;transient&lt;/span&gt; EntrySet entrySet;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;transient&lt;/span&gt; KeySet&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; navigableKeySet;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;transient&lt;/span&gt; NavigableMap&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K,V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; descendingMap;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//SubMapIterator中fence == null时，key的值&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; Object UNBOUNDED &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Object();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//RB Tree的颜色变量&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; RED   &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; BLACK &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;构造方法&#34;&gt;构造方法&lt;/h2&gt;&#xA;&lt;p&gt;共有四个构造方法：&lt;/p&gt;</description>
    </item>
    <item>
      <title>HashMap源码分析</title>
      <link>http://localhost:1313/posts/java%E9%9B%86%E5%90%88/java-hashmap/</link>
      <pubDate>Sun, 02 Aug 2020 17:15:18 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E9%9B%86%E5%90%88/java-hashmap/</guid>
      <description>&lt;h2 id=&#34;概述&#34;&gt;概述&lt;/h2&gt;&#xA;&lt;p&gt;​&#x9;Java中对于Map数据结构，提供了&lt;code&gt;java.util.Map&lt;/code&gt;接口，该接口下主要有四个常见的实现类，分别是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;HashMap&lt;/code&gt;：根据&lt;code&gt;key.hashCode&lt;/code&gt;计算存储位置，能在$O(1)$完成查询，但是遍历顺序是不确定的，&lt;code&gt;HashMap&lt;/code&gt;最多存储一个键为null，允许多条entry的值为null。&lt;code&gt;HashMap&lt;/code&gt;非线程安全。&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;HashTable&lt;/code&gt;：线程安全的Map，常用方法全部通过&lt;code&gt;synchronized&lt;/code&gt;保证线程安全，可以使用&lt;code&gt;ConcurrentHashMap&lt;/code&gt;达到目的，此类不建议使用。&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;LinkedHashMap&lt;/code&gt;：继承自&lt;code&gt;HashMap&lt;/code&gt;，内部通过双向链表将所有entry连接起来，保证了迭代顺序和插入顺序相同。&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;TreeMap&lt;/code&gt;：实现了SortedMap接口，能够将保存的记录按照键排序。内部通过红黑树进行存储。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;code&gt;HashMap&lt;/code&gt;在&lt;code&gt;JDK 7&lt;/code&gt;中采用了数组+链表的数据结构，在&lt;code&gt;JDK 8&lt;/code&gt;后，底层数据结构转变为：数组+链表+红黑树，也就是当出现Hash冲突时，当链表长度大于阈值(或者红黑树的边界值，默认为8)并且当前数组的长度大于64，链表会转为红黑树存储节点提高搜索效率。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;HashMap&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K,V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; AbstractMap&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K,V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; Map&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K,V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;, Cloneable, Serializable&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;HashMap&lt;/code&gt; 继承了 &lt;code&gt;AbstractMap&lt;/code&gt; ，该类提供了Map接口的抽象实现，并提供了一些方法的基本实现。实现了 &lt;code&gt;Map&lt;/code&gt;、&lt;code&gt;Cloneable&lt;/code&gt;和 &lt;code&gt;Serializable&lt;/code&gt;接口。&lt;/p&gt;&#xA;&lt;h2 id=&#34;成员变量&#34;&gt;成员变量&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;loadFactor：该变量控制table数组存放数据的疏密程度，越趋向1时，数组中存放的数据越多越密。链表的长度会增加，因此会导致查找效率变低。该值越小，则数组中存放的数据越少，越稀疏，则会导致空间利用率下降。默认值0.75是较好的默认值，可以最大程度减少rehash的次数，避免过多的性能消耗。&lt;/li&gt;&#xA;&lt;li&gt;threshold：当前 &lt;code&gt;HashMap&lt;/code&gt;所能容纳键值对数量的最大值，超过这个值，则需扩容。&lt;strong&gt;threshold = capacity * loadFactor&lt;/strong&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;默认容量为16，默认负载因子为0.75，当size达到16 * 0.75 = 12时，需要进行扩容(resize)，&lt;strong&gt;即默认扩容阈值为12。&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;扩容倍数为：2倍&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;DEFAULT_INITIAL_CAPACITY：默认初始容量为16&lt;/li&gt;&#xA;&lt;li&gt;table：存储Node的数组，链表状态下的节点。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;length大小必须为2的n次方，减少hash冲突的现象。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;entrySet：存储entry的set集合&lt;/li&gt;&#xA;&lt;li&gt;size：实际存储的键值对数量&lt;/li&gt;&#xA;&lt;li&gt;modCount：对map结构操作的次数。&lt;/li&gt;&#xA;&lt;li&gt;TREEIFY_THRESHOLD：转为红黑树的链表节点阈值（条件之一）。&lt;/li&gt;&#xA;&lt;li&gt;MIN_TREEIFY_CAPACITY：树化的数组长度阈值（条件之一）。&lt;/li&gt;&#xA;&lt;li&gt;UNTREEIFY_THRESHOLD：树退化成链表的阈值。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//存储元素的数组，大小为2的幂次&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;transient&lt;/span&gt; Node&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K,V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;[]&lt;/span&gt; table;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//存放具体元素的集合&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;transient&lt;/span&gt; Set&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Map.&lt;span style=&#34;color:#a6e22e&#34;&gt;Entry&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;K,V&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; entrySet;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//已经存放了的数组大小&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;transient&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; size;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//结构修改的计数器&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;transient&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; modCount;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//临界值，实际大小超过该值，则进行扩容&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; threshold;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//负载因子&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt; loadFactor;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//默认初始容量：16&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; DEFAULT_INITIAL_CAPACITY &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 1 &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; 4; &lt;span style=&#34;color:#75715e&#34;&gt;// aka 16&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//最大容量&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; MAXIMUM_CAPACITY &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 1 &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; 30;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//默认的负载因子&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;float&lt;/span&gt; DEFAULT_LOAD_FACTOR &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0.&lt;span style=&#34;color:#a6e22e&#34;&gt;75f&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//链表节点数大于该阈值，转为红黑树存储&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; TREEIFY_THRESHOLD &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 8;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//红黑树节点数小于该值，转为链表存储&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; UNTREEIFY_THRESHOLD &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 6;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//树化时，检查table数组长度是否大于该值，小于则扩容&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; MIN_TREEIFY_CAPACITY &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 64;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;数据结构&#34;&gt;数据结构&lt;/h2&gt;&#xA;&lt;p&gt;链表状态下的节点，继承自&lt;code&gt;Map.Entry&amp;lt;K,V&amp;gt;&lt;/code&gt;。&lt;/p&gt;</description>
    </item>
    <item>
      <title>LinkedList源码分析</title>
      <link>http://localhost:1313/posts/java%E9%9B%86%E5%90%88/java-linkedlist/</link>
      <pubDate>Sat, 01 Aug 2020 13:59:58 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E9%9B%86%E5%90%88/java-linkedlist/</guid>
      <description>&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;LinkedList&lt;/code&gt;底层采用双向链表结构实现，所以在存储元素功能上，并不需要扩容机制，但是需要额外的空间存储指针，头插和尾插的时间复杂度为&lt;code&gt;O(1)&lt;/code&gt;，指定位置插入的时间复杂度为&lt;code&gt;O(n)&lt;/code&gt;，&lt;code&gt;LinkedList&lt;/code&gt;是非线程安全的集合。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;LinkedList&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;E&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; AbstractSequentialList&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;E&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; List&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;E&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;, Deque&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;E&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;, Cloneable, java.&lt;span style=&#34;color:#a6e22e&#34;&gt;io&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Serializable&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;LinkedList&lt;/code&gt;继承了&lt;code&gt;AbstractSequentialList&lt;/code&gt;。该类提供了一套基于顺序访问的接口。&lt;/p&gt;&#xA;&lt;p&gt;实现了&lt;code&gt;List&lt;/code&gt;接口和&lt;code&gt;Deque&lt;/code&gt;接口，使得&lt;code&gt;LinkedList&lt;/code&gt;同时具备了&lt;code&gt;List&lt;/code&gt;和双端队列的特性。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;LinkedList&lt;/code&gt;实现了&lt;code&gt;Serializable&lt;/code&gt;接口，表明&lt;code&gt;ArrayList&lt;/code&gt;支持序列化。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;LinkedList&lt;/code&gt;实现了&lt;code&gt;Cloneable&lt;/code&gt;接口，能被克隆。&lt;/p&gt;&#xA;&lt;h2 id=&#34;数据结构&#34;&gt;数据结构&lt;/h2&gt;&#xA;&lt;p&gt;Node节点包括数据，前驱节点和后继节点。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Node&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;E&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        E item;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Node&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;E&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; next;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Node&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;E&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; prev;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        Node(Node&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;E&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; prev, E element, Node&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;E&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; next) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;item&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; element;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;next&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; next;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;prev&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; prev;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;成员变量&#34;&gt;成员变量&lt;/h2&gt;&#xA;&lt;p&gt;分别是链表长度，头节点，尾节点。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;transient&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; size &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 0;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;transient&lt;/span&gt; Node&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;E&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; first;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;transient&lt;/span&gt; Node&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;E&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; last;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;构造方法&#34;&gt;构造方法&lt;/h2&gt;&#xA;&lt;p&gt;构造方法有两种，注释如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//空构造方法&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;LinkedList&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//传入集合，调用addAll进行添加&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;LinkedList&lt;/span&gt;(Collection&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;?&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; E&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; c) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        addAll(c);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;api&#34;&gt;API&lt;/h2&gt;&#xA;&lt;h3 id=&#34;linkfirst&#34;&gt;linkFirst&lt;/h3&gt;&#xA;&lt;p&gt;将元素添加到头部。&lt;/p&gt;</description>
    </item>
    <item>
      <title>ArrayList源码分析</title>
      <link>http://localhost:1313/posts/java%E9%9B%86%E5%90%88/java-arraylist/</link>
      <pubDate>Thu, 30 Jul 2020 17:59:58 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E9%9B%86%E5%90%88/java-arraylist/</guid>
      <description>&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;ArrayList&lt;/code&gt;是&lt;code&gt;List&lt;/code&gt;接口的实现类，其底层通过数组实现。当空间不够会通过内部的扩容机制进行扩容。时间复杂度与数组类似，&lt;code&gt;ArrayList&lt;/code&gt;是非线程安全的集合，在并发环境下使用会产生错误。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ArrayList&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;E&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; AbstractList&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;E&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; List&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;E&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;, RandomAccess, Cloneable, java.&lt;span style=&#34;color:#a6e22e&#34;&gt;io&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Serializable&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;ArrayList&lt;/code&gt;继承了&lt;code&gt;AbstractList&lt;/code&gt;，实现了&lt;code&gt;List&lt;/code&gt;接口，提供了添加、删除、修改、遍历等功能&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;ArrayList&lt;/code&gt;实现了&lt;code&gt;RandomAccess&lt;/code&gt;接口，实现该接口表明&lt;code&gt;ArrayList&lt;/code&gt;支持快速随机访问。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;ArrayList&lt;/code&gt;实现了&lt;code&gt;Serializable&lt;/code&gt;接口，表明&lt;code&gt;ArrayList&lt;/code&gt;支持序列化。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;ArrayList&lt;/code&gt;实现了&lt;code&gt;Cloneable&lt;/code&gt;接口，能被克隆。&lt;/p&gt;&#xA;&lt;h2 id=&#34;成员变量&#34;&gt;成员变量&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//默认初始化大小&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; DEFAULT_CAPACITY &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 10;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//传入initialCapacity为0时，elementData指向该变量&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; Object&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; EMPTY_ELEMENTDATA &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {};&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//不传initialCapacity时，elementData指向该变量&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; Object&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; DEFAULTCAPACITY_EMPTY_ELEMENTDATA &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {};&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//存放数据的数组&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;transient&lt;/span&gt; Object&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; elementData;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//list大小&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; size;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;构造方法&#34;&gt;构造方法&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;ArrayList&lt;/code&gt;共有三个构造方法。注释如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//传递了长度的构造方法&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ArrayList&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; initialCapacity) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//边界检查&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (initialCapacity &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; 0) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;elementData&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Object&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;initialCapacity&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (initialCapacity &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; 0) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;elementData&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; EMPTY_ELEMENTDATA;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; IllegalArgumentException(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Illegal Capacity: &amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                                               initialCapacity);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//无参构造&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ArrayList&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;elementData&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; DEFAULTCAPACITY_EMPTY_ELEMENTDATA;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//传递集合&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ArrayList&lt;/span&gt;(Collection&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;?&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; E&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; c) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//获取初始值数组&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        elementData &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; c.&lt;span style=&#34;color:#a6e22e&#34;&gt;toArray&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//如果传入的为非空集合&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ((size &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; elementData.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; 0) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// c.toArray可能返回的不是Object[]类型&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (elementData.&lt;span style=&#34;color:#a6e22e&#34;&gt;getClass&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; Object&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                elementData &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Arrays.&lt;span style=&#34;color:#a6e22e&#34;&gt;copyOf&lt;/span&gt;(elementData, size, Object&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;//传递空集合，将elementData指向空数组&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;elementData&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; EMPTY_ELEMENTDATA;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;api&#34;&gt;API&lt;/h2&gt;&#xA;&lt;h3 id=&#34;get&#34;&gt;get&lt;/h3&gt;&#xA;&lt;p&gt;获取对应下标的元素，时间复杂度&lt;code&gt;O(1)&lt;/code&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>缓存更新策略总结</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/%E7%BC%93%E5%AD%98%E6%9B%B4%E6%96%B0%E7%AD%96%E7%95%A5%E6%80%BB%E7%BB%93/</link>
      <pubDate>Sat, 25 Jul 2020 18:12:10 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/%E7%BC%93%E5%AD%98%E6%9B%B4%E6%96%B0%E7%AD%96%E7%95%A5%E6%80%BB%E7%BB%93/</guid>
      <description>&lt;h2 id=&#34;cache-aside&#34;&gt;Cache Aside&lt;/h2&gt;&#xA;&lt;p&gt;具体逻辑如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;写策略：更DB数据，再删除cache数据&lt;/li&gt;&#xA;&lt;li&gt;读策略：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;cache hit：直接返回命中数据。&lt;/li&gt;&#xA;&lt;li&gt;cache miss：从数据库中读取，然后将数据写入cache，并返回。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;适用场景：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;适合读多写少的场景，不适合写多的场景。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;readwrite-through&#34;&gt;Read/Write Through&lt;/h2&gt;&#xA;&lt;p&gt;具体逻辑如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Read Through：写入时先查询cache是否hit，hit直接返回，miss则有cache组件负责去DB查，并写入cache，再返回。&lt;/li&gt;&#xA;&lt;li&gt;Write Through：更新先查询cache是否hit，hit则更新缓存中数据，然后有cache组件更新到DB，完成后通知更新完成。若miss则直接更新数据库&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;write-back&#34;&gt;Write Back&lt;/h2&gt;&#xA;&lt;p&gt;具体逻辑如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;只更新缓存，立即返回，持久层更新采用异步更新方式。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;广泛用于OS，比如CPU Cache、文件系统Cache，数据非强一致性，存在丢数据的问题。&lt;/p&gt;&#xA;&lt;p&gt;适用场景：写多场景&lt;/p&gt;</description>
    </item>
    <item>
      <title>Redis内存优化</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis%E5%86%85%E5%AD%98%E4%BC%98%E5%8C%96/</link>
      <pubDate>Mon, 20 Jul 2020 18:12:10 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis%E5%86%85%E5%AD%98%E4%BC%98%E5%8C%96/</guid>
      <description>&lt;h2 id=&#34;查看内存使用情况&#34;&gt;查看内存使用情况&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;info memory&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;used_memory:701520                      redis分配器分配的内存量，也就是实际存储数据的内润使用总量&#xD;&#xA;used_memory_human:685.08K               以可读格式返回redis使用的内存总量&#xD;&#xA;used_memory_rss:664584                  从操作系统角度，redis进程占用的总物理内存&#xD;&#xA;used_memory_rss_human:649.01K          &#xD;&#xA;used_memory_peak:778480                  内存分配器分配的最大内存，代表`used_memory`的历史峰值&#xD;&#xA;used_memory_peak_human:760.23K          以可读的格式显示内存的消耗峰值&#xD;&#xA;total_system_memory:0&#xD;&#xA;total_system_memory_human:0B&#xD;&#xA;used_memory_lua:37888                   Lua引擎消耗的内存&#xD;&#xA;used_memory_lua_human:37.00K&#xD;&#xA;maxmemory:0&#xD;&#xA;maxmemory_human:0B&#xD;&#xA;maxmemory_policy:noeviction&#xD;&#xA;mem_fragmentation_ratio:0.95            内存碎片率，used_memory_rss/used_memory&#xD;&#xA;mem_allocator:jemalloc-3.6.0            redis使用的内存分配器&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;内存划分&#34;&gt;内存划分&lt;/h2&gt;&#xA;&lt;p&gt;Redis中使用的内存可分为如下几类：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;自身内存：自身维护的数据字典等元数据，占用较少&lt;/li&gt;&#xA;&lt;li&gt;对象内存：存储的所有entry对象&lt;/li&gt;&#xA;&lt;li&gt;缓存：客户端缓冲区+AOF缓冲区等&lt;/li&gt;&#xA;&lt;li&gt;Lua内存：用于加载Lua脚本&lt;/li&gt;&#xA;&lt;li&gt;子进程内存：一般是持久化时fork出来的子进程占用的内存&lt;/li&gt;&#xA;&lt;li&gt;运行内存：运行时消耗的内存&lt;/li&gt;&#xA;&lt;li&gt;内存碎片：Redis使用jemalloc来分配内存，按照固定大小划分，当删除数据后，释放的内存不会立即返回给OS，Redis无法有效利用，因此形成碎片。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;内存优化方案&#34;&gt;内存优化方案&lt;/h2&gt;&#xA;&lt;h3 id=&#34;对象内存&#34;&gt;对象内存&lt;/h3&gt;&#xA;&lt;p&gt;Redis中对象大多有两种存储方案，尽量将大小控制在较为节省的存储阈值之内。&lt;/p&gt;&#xA;&lt;h3 id=&#34;客户端缓冲区&#34;&gt;客户端缓冲区&lt;/h3&gt;&#xA;&lt;p&gt;客户端缓冲区占用内存较大的原因如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;client访问大key，导致client输出缓存异常增长。&lt;/li&gt;&#xA;&lt;li&gt;client使用monitor命令，它会将所有访问redis的命令持续放到输出缓冲区，导致输出缓冲区异常增长。&lt;/li&gt;&#xA;&lt;li&gt;clinet使用pipeline封装了大量命令&lt;/li&gt;&#xA;&lt;li&gt;从节点复制慢，导致主节点输出缓冲区积压。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;优化方案:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;大key需要进行拆分&lt;/li&gt;&#xA;&lt;li&gt;尽量避免使用monitor等指令&lt;/li&gt;&#xA;&lt;li&gt;使用pipeline设置最大阈值&lt;/li&gt;&#xA;&lt;li&gt;主从复制区设置阈值&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;内存碎片&#34;&gt;内存碎片&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;手动执行memory purge命令&lt;/li&gt;&#xA;&lt;li&gt;通过配置参数进行控制&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;activedefrag yes：启用自动碎片清理开关&#xD;&#xA;active-defrag-ignore-bytes 100mb：内存碎片空间达到多少才开启碎片整理&#xD;&#xA;active-defrag-threshold-lower 10：碎片率达到百分之多少才开启碎片整理&#xD;&#xA;active-defrag-threshold-upper 100：内存碎片率超过多少，则尽最大努力整理（占用最大资源去做碎片整理）&#xD;&#xA;active-defrag-cycle-min 25：内存自动整理占用资源最小百分比&#xD;&#xA;active-defrag-cycle-max 75：内存自动整理占用资源最大百分比&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;子进程优化&#34;&gt;子进程优化&lt;/h3&gt;&#xA;&lt;p&gt;Linux中的fork使用了copy on write机制，fork之后与父进程共享内存空间，只有发生写操作修改内存数据时，才会真正分配内存空间。&lt;/p&gt;&#xA;&lt;h2 id=&#34;其他注意事项&#34;&gt;其他注意事项&lt;/h2&gt;&#xA;&lt;h3 id=&#34;键值生命周期&#34;&gt;键值生命周期&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;周期数据需要设置过期时间，&lt;code&gt;object idle time&lt;/code&gt;可以找垃圾key-value&lt;/li&gt;&#xA;&lt;li&gt;过期时间不宜集中，会导致缓存穿透和雪崩等问题&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;命令使用技巧&#34;&gt;命令使用技巧&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;O(n)以上命令关注n的数量&#xA;&lt;ul&gt;&#xA;&lt;li&gt;hgetall,lrange,smembers,zrange,sinter等&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;禁用命令&#xA;&lt;ul&gt;&#xA;&lt;li&gt;禁止线上使用keys,flushall,flushdb，通过redis的rename机制禁用掉命令，或者使用scan的方式渐进式处理&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;合理使用select&#xA;&lt;ul&gt;&#xA;&lt;li&gt;redis的多数据库较弱，使用数字进行区分&lt;/li&gt;&#xA;&lt;li&gt;很多客户端支持较差&lt;/li&gt;&#xA;&lt;li&gt;同时多业务用多数据库实际上还是单线程处理，会有干扰&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;redis的事务功能较弱，不建议过多使用&#xA;&lt;ul&gt;&#xA;&lt;li&gt;不支持回滚&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;redis集群版本在使用Lua上有特殊要求&#xA;&lt;ul&gt;&#xA;&lt;li&gt;所有的key，必须爱一个slot上，否则返回error&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;必要情况下使用monitor命令时，注意不要长时间使用&lt;/li&gt;&#xA;&lt;/ul&gt;</description>
    </item>
    <item>
      <title>Redis集群机制分析</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis%E9%9B%86%E7%BE%A4%E6%9C%BA%E5%88%B6%E5%88%86%E6%9E%90/</link>
      <pubDate>Mon, 13 Jul 2020 18:12:10 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis%E9%9B%86%E7%BE%A4%E6%9C%BA%E5%88%B6%E5%88%86%E6%9E%90/</guid>
      <description>&lt;h2 id=&#34;主从复制模式&#34;&gt;主从复制模式&lt;/h2&gt;&#xA;&lt;p&gt;Redis集群实现数据同步，保证服务高可用。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;一主多从&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;数据流向是单向的，master-&amp;gt;slave&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;开启指令：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;slaveof 192.168.1.10 6379&#x9;&#x9;//当前服务节点称为指定IP的从节点&#xD;&#xA;slaveof no one                  //取消从属关系&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;配置文件：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;slaveof ip port&#xD;&#xA;slave-read-only yes             //从节点只读&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;全量复制的开销：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;bgsave的时间&lt;/li&gt;&#xA;&lt;li&gt;RDB文件网络传输时间&lt;/li&gt;&#xA;&lt;li&gt;从节点清空数据时间&lt;/li&gt;&#xA;&lt;li&gt;从节点加载RDB的时间&lt;/li&gt;&#xA;&lt;li&gt;可能的AOF重写时间&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;实现&#34;&gt;实现&lt;/h3&gt;&#xA;&lt;p&gt;Redis复制分为同步和命令传播两个操作：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;同步：将从服务器的数据库状态更新为主库状态&lt;/li&gt;&#xA;&lt;li&gt;命令传播：同步完后，主库状态又发生变化，此时使用命令传播完成状态同步。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Redis使用&lt;code&gt;PSYNC&lt;/code&gt;可以同时解决全量复制和部分复制两种情况。&lt;/p&gt;&#xA;&lt;p&gt;需要维护的变量包括 ：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;runID：每个Redis实例启动生成的随机ID&lt;/li&gt;&#xA;&lt;li&gt;offset：复制进度&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;执行&lt;code&gt;slaveof&lt;/code&gt;时，slave节点会将master的地址保存在：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; redisServer {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;masterhost;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; masterport;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;slave节点会将该命令封装成通信协议并发给master，完成socket建立，并发送PING检查socket是否正常。&lt;/p&gt;&#xA;&lt;h3 id=&#34;心跳检测&#34;&gt;心跳检测&lt;/h3&gt;&#xA;&lt;p&gt;命令传播的阶段，slave默认每秒一次的频率，向master发送心跳：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;REPLCONF ACK &amp;lt;replication_offset&amp;gt;&#xD;&#xA;&#xD;&#xA;replication_offset为slave当前的复制偏移量&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;心跳主要有三个作用：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;检测主从之间连接状态：节点保活机制&lt;/li&gt;&#xA;&lt;li&gt;辅助实现min-slaves：防止master在不安全的情况下执行写命令。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;min-slaves-to-write&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;min-slaves-max-log&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;检测命令丢失：如果因为网络原因产生命令丢失，master发现slave的offset小于自己当前offset，则认为产生命令丢失，并按照slave的offset传递数据。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;sentinel机制&#34;&gt;sentinel机制&lt;/h2&gt;&#xA;&lt;p&gt;主从复制存在的问题&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;手动故障转移：master发生宕机，需要手动切换&lt;/li&gt;&#xA;&lt;li&gt;写能力和存储能力受限&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Sentinel（机制）是Redis官方推荐的高可用性(HA)解决方案，由一个或多个sentinel组成的sentinel system，可以监视主从集群的状态，当master发生宕机，自动将master下面的某个slave升级为新的master。&lt;/p&gt;&#xA;&lt;h3 id=&#34;启动&#34;&gt;启动&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;./redis-sentinel /path/to/sentinel.conf&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;启动流程会执行以下步骤：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;初始化server：sentinel本质上是一个运行在特殊模式的Redis服务器。&lt;/li&gt;&#xA;&lt;li&gt;代码：sentinel使用&lt;code&gt;sentinel.c/REDIS_SENTINEL_PORT&lt;/code&gt;作为默认端口，使用&lt;code&gt;sentinel.c/sentinelcmds&lt;/code&gt;作为命令表&lt;/li&gt;&#xA;&lt;li&gt;初始化sentinel状态：&lt;code&gt;sentinel.c/sentinelState&lt;/code&gt;结构&lt;/li&gt;&#xA;&lt;li&gt;根据配置文件，初始化sentinel监视的主服务器列表：上面的结构使用&lt;code&gt;dict&lt;/code&gt;保存master信息，key为master的名称，value为master对应的&lt;code&gt;sentinel.c/sentinelRedisInstance&lt;/code&gt;，每个被监视的Redis服务器实例都被使用该结构存储。master的IP端口信息使用&lt;code&gt;struct sentinelAddr&lt;/code&gt;进行存储。该数据sentinel初始化时从&lt;code&gt;sentinel.conf&lt;/code&gt;完成加载。&lt;/li&gt;&#xA;&lt;li&gt;创建连向master的socket连接：sentinel节点对master创建两个异步连接：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;命令连接：专门向master发送命令，并接收回复&lt;/li&gt;&#xA;&lt;li&gt;订阅连接：订阅master的&lt;code&gt;__sentinel__:hello&lt;/code&gt;频道，用于sentinel发现其他sentinel节点&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;获取信息&#34;&gt;获取信息&lt;/h3&gt;&#xA;&lt;p&gt;每10s每个sentinel会对master发送&lt;code&gt;info&lt;/code&gt;命令，sentinel主要获取两方面信息：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Redis持久化机制分析</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis%E6%8C%81%E4%B9%85%E5%8C%96%E6%9C%BA%E5%88%B6%E5%88%86%E6%9E%90/</link>
      <pubDate>Sun, 12 Jul 2020 17:54:10 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis%E6%8C%81%E4%B9%85%E5%8C%96%E6%9C%BA%E5%88%B6%E5%88%86%E6%9E%90/</guid>
      <description>&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;&#xA;&lt;p&gt;Redis数据保存在内存中，为了防止进程异常退出而导致数据丢失，可以考虑将数据保存到磁盘上。&lt;/p&gt;&#xA;&lt;p&gt;Redis提供的两种持久化方案：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;RDB：直接将数据库状态写到文件，既可以手动执行，也可以配置为定期执行。&lt;/li&gt;&#xA;&lt;li&gt;AOF：将写命令append到AOF文件中。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;rdb&#34;&gt;RDB&lt;/h2&gt;&#xA;&lt;p&gt;两种方案：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;save：直接执行&lt;/li&gt;&#xA;&lt;li&gt;bgsave：fork一个子进程执行&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;code&gt;rdbSave&lt;/code&gt;是save的具体实现函数，bgsave与其区别是通过fork子进程完成备份，并在完成后给父进程发送信号。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;rdbSave&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;filename) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    dictIterator &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;di &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; NULL;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    dictEntry &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;de;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; tmpfile[&lt;span style=&#34;color:#ae81ff&#34;&gt;256&lt;/span&gt;];&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; magic[&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;];&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; j;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; now &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mstime&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    FILE &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;fp;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rio rdb;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; cksum;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 创建临时文件&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;snprintf&lt;/span&gt;(tmpfile,&lt;span style=&#34;color:#ae81ff&#34;&gt;256&lt;/span&gt;,&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;temp-%d.rdb&amp;#34;&lt;/span&gt;, (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;getpid&lt;/span&gt;());&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    fp &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fopen&lt;/span&gt;(tmpfile,&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;w&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;fp) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;redisLog&lt;/span&gt;(REDIS_WARNING, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Failed opening .rdb for saving: %s&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;strerror&lt;/span&gt;(errno));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; REDIS_ERR;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 初始化 I/O&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;rioInitWithFile&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;rdb,fp);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 设置校验和函数&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (server.rdb_checksum)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        rdb.update_cksum &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; rioGenericUpdateChecksum;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 写入 RDB 版本号&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;snprintf&lt;/span&gt;(magic,&lt;span style=&#34;color:#66d9ef&#34;&gt;sizeof&lt;/span&gt;(magic),&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;REDIS%04d&amp;#34;&lt;/span&gt;,REDIS_RDB_VERSION);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;rdbWriteRaw&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;rdb,magic,&lt;span style=&#34;color:#ae81ff&#34;&gt;9&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;goto&lt;/span&gt; werr;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 遍历所有数据库&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (j &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; j &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; server.dbnum; j&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 指向数据库&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        redisDb &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;db &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; server.db&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;j;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 指向数据库键空间&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        dict &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;d &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; db&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;dict;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 跳过空数据库&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;dictSize&lt;/span&gt;(d) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;continue&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// 创建键空间迭代器&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        di &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dictGetSafeIterator&lt;/span&gt;(d);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;di) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;fclose&lt;/span&gt;(fp);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; REDIS_ERR;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;/* Write the SELECT DB opcode &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;         *&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;         * 写入 DB 选择器&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;         */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;rdbSaveType&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;rdb,REDIS_RDB_OPCODE_SELECTDB) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;goto&lt;/span&gt; werr;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;rdbSaveLen&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;rdb,j) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;goto&lt;/span&gt; werr;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;/* Iterate this DB writing every entry &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;         *&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;         * 遍历数据库，并写入每个键值对的数据&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;         */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt;((de &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dictNext&lt;/span&gt;(di)) &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; NULL) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            sds keystr &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dictGetKey&lt;/span&gt;(de);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            robj key, &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;o &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dictGetVal&lt;/span&gt;(de);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; expire;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// 根据 keystr ，在栈中创建一个 key 对象&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;initStaticStringObject&lt;/span&gt;(key,keystr);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// 获取键的过期时间&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;            expire &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getExpire&lt;/span&gt;(db,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;key);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// 保存键值对数据&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;rdbSaveKeyValuePair&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;rdb,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;key,o,expire,now) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;goto&lt;/span&gt; werr;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;dictReleaseIterator&lt;/span&gt;(di);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    di &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; NULL; &lt;span style=&#34;color:#75715e&#34;&gt;/* So that we don&amp;#39;t release it again on error. */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/* EOF opcode &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     *&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * 写入 EOF 代码&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;rdbSaveType&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;rdb,REDIS_RDB_OPCODE_EOF) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;goto&lt;/span&gt; werr;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/* CRC64 checksum. It will be zero if checksum computation is disabled, the&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * loading code skips the check in this case. &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     *&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * CRC64 校验和。&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     *&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * 如果校验和功能已关闭，那么 rdb.cksum 将为 0 ，&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * 在这种情况下， RDB 载入时会跳过校验和检查。&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    cksum &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; rdb.cksum;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;memrev64ifbe&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;cksum);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;rioWrite&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;rdb,&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;cksum,&lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/* Make sure data will not remain on the OS&amp;#39;s output buffers */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 冲洗缓存，确保数据已写入磁盘&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;fflush&lt;/span&gt;(fp) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; EOF) &lt;span style=&#34;color:#66d9ef&#34;&gt;goto&lt;/span&gt; werr;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;fsync&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;fileno&lt;/span&gt;(fp)) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;goto&lt;/span&gt; werr;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;fclose&lt;/span&gt;(fp) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; EOF) &lt;span style=&#34;color:#66d9ef&#34;&gt;goto&lt;/span&gt; werr;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/* Use RENAME to make sure the DB file is changed atomically only&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * if the generate DB file is ok. &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     *&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * 使用 RENAME ，原子性地对临时文件进行改名，覆盖原来的 RDB 文件。&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;rename&lt;/span&gt;(tmpfile,filename) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;redisLog&lt;/span&gt;(REDIS_WARNING,&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Error moving temp DB file on the final destination: %s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;strerror&lt;/span&gt;(errno));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;unlink&lt;/span&gt;(tmpfile);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; REDIS_ERR;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 写入完成，打印日志&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;redisLog&lt;/span&gt;(REDIS_NOTICE,&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;DB saved on disk&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 清零数据库脏状态&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    server.dirty &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 记录最后一次完成 SAVE 的时间&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    server.lastsave &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;(NULL);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 记录最后一次执行 SAVE 的状态&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    server.lastbgsave_status &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; REDIS_OK;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; REDIS_OK;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;werr:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 关闭文件&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fclose&lt;/span&gt;(fp);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 删除文件&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;unlink&lt;/span&gt;(tmpfile);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;redisLog&lt;/span&gt;(REDIS_WARNING,&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Write error saving DB on disk: %s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;strerror&lt;/span&gt;(errno));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (di) &lt;span style=&#34;color:#a6e22e&#34;&gt;dictReleaseIterator&lt;/span&gt;(di);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; REDIS_ERR;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;rdb载入还原&#34;&gt;RDB载入还原&lt;/h3&gt;&#xA;&lt;p&gt;Redis对RDB文件的载入还原步骤如下：&lt;/p&gt;</description>
    </item>
    <item>
      <title>MySQL体系结构和存储引擎</title>
      <link>http://localhost:1313/posts/mysql/mysql-structure-and-engine/</link>
      <pubDate>Sat, 11 Jul 2020 16:25:46 +0000</pubDate>
      <guid>http://localhost:1313/posts/mysql/mysql-structure-and-engine/</guid>
      <description>&lt;h2 id=&#34;体系结构&#34;&gt;体系结构&lt;/h2&gt;&#xA;&lt;p&gt;MySQL体系结构如图所示：&#xA;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/mysql/structure/MySQL%E4%BD%93%E7%B3%BB%E7%BB%93%E6%9E%84.png&#34; alt=&#34;MySQL体系结构&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;分别由Client Connectors层、MySQL Server层以及存储引擎层组成。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Client Connectors层：负责处理客户端的连接请求，与客户端创建连接。&lt;/li&gt;&#xA;&lt;li&gt;MySQL Server层：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Connection Pool：负责处理和存储数据库与客户端创建的连接，一个线程负责管理一个连接，包括了用户认证模块，就是用户登录身份的认证和鉴权以及安全管理&lt;/li&gt;&#xA;&lt;li&gt;Service &amp;amp; utilities：管理服务&amp;amp;工具集，包括备份恢复、安全管理、集群管理、工具&lt;/li&gt;&#xA;&lt;li&gt;SQL interface：负责接受客户端发送的各种语句&lt;/li&gt;&#xA;&lt;li&gt;Parser：对SQL语句进行语法解析生成解析树&lt;/li&gt;&#xA;&lt;li&gt;Optimizer：查询优化器会根据解析树生成执行计划，并选择合适的索引，然后按照执行计划执行SQL并与各个存储引擎交互&lt;/li&gt;&#xA;&lt;li&gt;Caches：包括各个存储引擎的缓存部分，例如InnoDB的Buffer Pool&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;存储引擎层：包括InnoDB，MyISAM以及支持归档的Archive和内存的Memory&lt;/li&gt;&#xA;&lt;li&gt;存储引擎底部是物理存储层，包括二进制日志，数据文件，错误日志，慢查询日志，全日志，redo/undo日志&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;一条SQL语句的执行过程可以参照如下图示：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/mysql/structure/SQL%20process.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;与MySQL建立连接。&lt;/li&gt;&#xA;&lt;li&gt;查询缓存，如果开启了Query。 Cache并且查询缓存中存在该查询语句，则直接将结果返回到客户端，没有开启或缓存未命中则由解析器进行语法语义解析，并生成解析树。&lt;/li&gt;&#xA;&lt;li&gt;预处理器生成新的解析树。&lt;/li&gt;&#xA;&lt;li&gt;查询优化器进行优化。&lt;/li&gt;&#xA;&lt;li&gt;查询执行引擎执行SQL，通过API接口查询物理存储层的数据，并返回结果。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;其中，查询缓存于MySQL 8.0中移除，具体原因：查询缓存往往弊大于利。查询缓存的失效非常频繁，只要有对一个表的更新，这个表上的所有的查询缓存都会被清空。&lt;/p&gt;&#xA;&lt;p&gt;MySQL官方博客关于该技术移除的解释&lt;a href=&#34;https://mysqlserverteam.com/mysql-8-0-retiring-support-for-the-query-cache/&#34;&gt;https://mysqlserverteam.com/mysql-8-0-retiring-support-for-the-query-cache/&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;存储引擎&#34;&gt;存储引擎&lt;/h2&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/mysql/structure/%E5%AD%98%E5%82%A8%E5%BC%95%E6%93%8E.png&#34; alt=&#34;MySQL存储引擎&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;在 MySQL 5.6 版本之前，默认的存储引擎都是 MyISAM，但 5.6 版本以后默认的存储引擎就是 InnoDB。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/mysql/structure/InnoDB%E7%BB%93%E6%9E%84.png&#34; alt=&#34;InnoDB结构&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;InnoDB上半部分是实例层，位于内存中，下半部分是物理层，位于文件系统中。&#xA;其中实例层分为线程和内存，InnoDB中重要的线程有Master Thread（主线程），其优先级最高，主要负责调度其他线程，其内部有几个循环：主循环，后台循环，刷新循环，暂停循环，Master Thread 会根据其内部运行的相关状态在各循环间进行切换。&lt;/p&gt;&#xA;&lt;p&gt;大部分操作在主循环中完成，其包含1s和10s两种操作：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;1s操作&#xA;&lt;ul&gt;&#xA;&lt;li&gt;日志缓冲刷新到磁盘（即使事务未提交，也被执行）&lt;/li&gt;&#xA;&lt;li&gt;最多可以刷100个新脏页到磁盘&lt;/li&gt;&#xA;&lt;li&gt;执行并改变缓冲的操作&lt;/li&gt;&#xA;&lt;li&gt;若当前没有用户活动，可以切换到后台循环&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;10s操作&#xA;&lt;ul&gt;&#xA;&lt;li&gt;最多可以刷新100个脏页到磁盘&lt;/li&gt;&#xA;&lt;li&gt;合并至多5个被改变的缓冲&lt;/li&gt;&#xA;&lt;li&gt;日志缓冲刷新到磁盘&lt;/li&gt;&#xA;&lt;li&gt;删除无用的Undo页&lt;/li&gt;&#xA;&lt;li&gt;刷新100个或10个脏页到磁盘，产生一个检查点&lt;/li&gt;&#xA;&lt;li&gt;buf_dump_thread 负责将 buffer pool 中的内容 dump 到物理文件中，以便再次启动 MySQL 时，可以快速加热数据。&lt;/li&gt;&#xA;&lt;li&gt;page_cleaner_thread 负责将 buffer pool 中的脏页刷新到磁盘，在 5.6 版本之前没有这个线程，刷新操作都是由主线程完成的，所以在刷新脏页时会非常影响 MySQL 的处理能力，在5.7 版本之后可以通过参数设置开启多个 page_cleaner_thread。&lt;/li&gt;&#xA;&lt;li&gt;purge_thread 负责将不再使用的 Undo 日志进行回收。&lt;/li&gt;&#xA;&lt;li&gt;read_thread 处理用户的读请求，并负责将数据页从磁盘上读取出来，可以通过参数设置线程数量。&lt;/li&gt;&#xA;&lt;li&gt;write_thread 负责将数据页从缓冲区写入磁盘，也可以通过参数设置线程数量，page_cleaner 线程发起刷脏页操作后 write_thread 就开始工作了。&lt;/li&gt;&#xA;&lt;li&gt;redo_log_thread 负责把日志缓冲中的内容刷新到 Redo log 文件中。&lt;/li&gt;&#xA;&lt;li&gt;insert_buffer_thread 负责把 Insert Buffer 中的内容刷新到磁盘。实例层的内存部分主要包含 InnoDB Buffer Pool，这里包含 InnoDB 最重要的缓存内容。数据和索引页、undo 页、insert buffer 页、自适应 Hash 索引页、数据字典页和锁信息等。additional memory pool 后续已不再使用。Redo buffer 里存储数据修改所产生的 Redo log。double write buffer 是 double write 所需的 buffer，主要解决由于宕机引起的物理写入操作中断，数据页不完整的问题。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;物理层在逻辑上分为系统表空间、用户表空间和Redo日志。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Redis对象机制分析</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis%E5%AF%B9%E8%B1%A1%E6%9C%BA%E5%88%B6%E5%88%86%E6%9E%90/</link>
      <pubDate>Sat, 11 Jul 2020 08:12:54 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis%E5%AF%B9%E8%B1%A1%E6%9C%BA%E5%88%B6%E5%88%86%E6%9E%90/</guid>
      <description>&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;&#xA;&lt;p&gt;Redis中提供的数据结构都使用了下面的redisObject进行包装，通过包装可以提供不同场景下使用不同的数据结构的实现。Redis的对象机制还使用了&lt;strong&gt;引用计数&lt;/strong&gt;方式的内存回收机制。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; redisObject {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 类型&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; type:&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 编码&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; encoding:&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 对象最后一次被访问的时间&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; lru:REDIS_LRU_BITS; &lt;span style=&#34;color:#75715e&#34;&gt;/* lru time (relative to server.lruclock) */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 引用计数&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; refcount;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 指向实际值的指针&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;ptr;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} robj;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;type值可选：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define REDIS_STRING 0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define REDIS_LIST 1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define REDIS_SET 2&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define REDIS_ZSET 3&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define REDIS_HASH 4&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;encoding可选：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define REDIS_ENCODING_RAW 0     &lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* Raw representation */&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define REDIS_ENCODING_INT 1     &lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* Encoded as integer */&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define REDIS_ENCODING_HT 2      &lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* Encoded as hash table */&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define REDIS_ENCODING_ZIPMAP 3  &lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* Encoded as zipmap */&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define REDIS_ENCODING_LINKEDLIST 4 &lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* Encoded as regular linked list */&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define REDIS_ENCODING_ZIPLIST 5 &lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* Encoded as ziplist */&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define REDIS_ENCODING_INTSET 6  &lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* Encoded as intset */&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define REDIS_ENCODING_SKIPLIST 7  &lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* Encoded as skiplist */&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define REDIS_ENCODING_EMBSTR 8  &lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* Embedded sds string encoding */&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;结构的编码方案&#34;&gt;结构的编码方案&lt;/h2&gt;&#xA;&lt;h3 id=&#34;string&#34;&gt;String&lt;/h3&gt;&#xA;&lt;p&gt;编码策略如下：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Redis过期删除策略与内存淘汰机制</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis%E8%BF%87%E6%9C%9F%E5%88%A0%E9%99%A4%E7%AD%96%E7%95%A5%E4%B8%8E%E5%86%85%E5%AD%98%E6%B7%98%E6%B1%B0%E6%9C%BA%E5%88%B6/</link>
      <pubDate>Fri, 10 Jul 2020 13:12:24 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis%E8%BF%87%E6%9C%9F%E5%88%A0%E9%99%A4%E7%AD%96%E7%95%A5%E4%B8%8E%E5%86%85%E5%AD%98%E6%B7%98%E6%B1%B0%E6%9C%BA%E5%88%B6/</guid>
      <description>&lt;h2 id=&#34;过期删除策略&#34;&gt;过期删除策略&lt;/h2&gt;&#xA;&lt;p&gt;过期删除策略主要有以下三种：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;定时删除：设置过期时间的同时，创建一个定时器，当到达过期时间后，执行删除操作。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;优点：对内存友好，不会长时间占用内存&lt;/li&gt;&#xA;&lt;li&gt;缺点：对CPU不友好，当过期entry过多会占用大量CPU时间，并且创建定时器存在性能消耗。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;惰性删除：每次查询到该entry时，检查是否过期，若过期就删除，否则返回。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;优点：对CPU友好&lt;/li&gt;&#xA;&lt;li&gt;缺点：无用数据占用大量内存空间，依赖于客户端请求对过期数据进行删除。有内存泄漏的风险。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;定期删除：每隔一段时间对数据库进行检查，删除其中的过期entry。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;综合考虑上述策略的优缺点，可以合理设置执行时长和频率。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Redis中主要配合使用&lt;strong&gt;惰性删除&lt;/strong&gt;和&lt;strong&gt;定期删除&lt;/strong&gt;两种策略，在内存和CPU性能中取得平衡。&#xA;使用过期字典存储所有key的过期时间。key是一个指针，指向key对象，value是一个long long类型的整数，保存key的过期时间。&lt;/p&gt;&#xA;&lt;p&gt;实现：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;惰性删除：&lt;code&gt;db.c/expireIfNeeded&lt;/code&gt;在读写之前对key进行检查.&lt;/li&gt;&#xA;&lt;li&gt;定期删除：&lt;code&gt;redis.c/activeExpireCycle&lt;/code&gt;实现，每当Redis的&lt;code&gt;serverCron&lt;/code&gt;执行时，都会主动清除过期数据。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;activeExpireCycle&lt;/code&gt;的工作流程如下：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;每次取出一定数量的随机key进行检查，并删除其中的过期数据&lt;/li&gt;&#xA;&lt;li&gt;全局变量&lt;code&gt;current_db&lt;/code&gt;存储当前的检查进度（db编号），并且下次&lt;code&gt;activeExpireCycle&lt;/code&gt;执行会接着上次进度进行处理。全部检查完毕后该变量置为0。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;内存淘汰策略&#34;&gt;内存淘汰策略&lt;/h2&gt;&#xA;&lt;p&gt;当Redis的运行内存已经超过设置的最大内存时，会使用内存淘汰策略删除符合相关条件的key。&#xA;最大内存通过设置&lt;code&gt;maxmemory &amp;lt;bytes&amp;gt;&lt;/code&gt;即可。默认为0，表示没有内存大小的限制。&lt;/p&gt;&#xA;&lt;p&gt;Redis的内存淘汰策略如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;不淘汰&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;noeviction：不淘汰任何数据、直接返回错误。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;对设置了过期时间的数据进行淘汰&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;volatile-random： 随意淘汰设置了过期时间的任意entry。&lt;/li&gt;&#xA;&lt;li&gt;volatile-ttl：优先淘汰更早过期的entry。&lt;/li&gt;&#xA;&lt;li&gt;volatile-lru：淘汰所有设置了过期时间的entry中最近最久未使用的entry。&lt;/li&gt;&#xA;&lt;li&gt;volatile-lfu：淘汰所有设置了过期时间的entry中最少使用的entry。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;对全部数据进行淘汰&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;allkeys-random：随即淘汰任意entry。&lt;/li&gt;&#xA;&lt;li&gt;allkeys-lru：使用LRU策略淘汰任意entry。&lt;/li&gt;&#xA;&lt;li&gt;allkeys-lfu：使用LFU策略淘汰任意entry。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;修改redis.conf中的&lt;code&gt;maxmemory-policy &amp;lt;策略&amp;gt;&lt;/code&gt;即可。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Redis基础知识总结</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86%E6%80%BB%E7%BB%93/</link>
      <pubDate>Thu, 09 Jul 2020 17:06:33 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86%E6%80%BB%E7%BB%93/</guid>
      <description>&lt;h2 id=&#34;redis简介&#34;&gt;Redis简介&lt;/h2&gt;&#xA;&lt;h3 id=&#34;redis特性&#34;&gt;Redis特性&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;速度快（内存，10w QPS, C , 单线程）&lt;/li&gt;&#xA;&lt;li&gt;持久化（将内存数据异步更新到磁盘,RDB&amp;amp;AOF）&lt;/li&gt;&#xA;&lt;li&gt;多种数据结构（string list set zset hash BitMaps HyperLogLog GEO）&lt;/li&gt;&#xA;&lt;li&gt;支持多语言&lt;/li&gt;&#xA;&lt;li&gt;功能丰富（发布订阅 事务 Lua脚本 pipeline）&lt;/li&gt;&#xA;&lt;li&gt;简单（23000 lines of code 不依赖外部库 单线程模型）&lt;/li&gt;&#xA;&lt;li&gt;主从复制&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;单线程为什么这么快？&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;纯内存&lt;/li&gt;&#xA;&lt;li&gt;非阻塞IO，使用多路复用机制，提升连接并发度。&lt;/li&gt;&#xA;&lt;li&gt;避免多线程切换和竞态消耗&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;redis典型应用场景&#34;&gt;Redis典型应用场景&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;缓存系统（缓存）&lt;/li&gt;&#xA;&lt;li&gt;计数器（微博转发和评论）&lt;/li&gt;&#xA;&lt;li&gt;消息队列系统&lt;/li&gt;&#xA;&lt;li&gt;排行榜&lt;/li&gt;&#xA;&lt;li&gt;社交网络&lt;/li&gt;&#xA;&lt;li&gt;实时系统（垃圾邮件&amp;ndash;布隆过滤器）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;redis可执行文件说明&#34;&gt;Redis可执行文件说明&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;redis-server      ---&amp;gt;    Redis服务器&#xD;&#xA;redis-cli         ---&amp;gt;    Redis客户端&#xD;&#xA;redis-benchmark   ---&amp;gt;    Redis性能测试&#xD;&#xA;redis-check-aof   ---&amp;gt;    AOF文件修复&#xD;&#xA;redis-check-dump  ---&amp;gt;    RDB文件检查&#xD;&#xA;redis-sentinel    ---&amp;gt;    Sentinel服务器&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;redis-通用api&#34;&gt;Redis 通用API&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;keys                ---&amp;gt;    遍历所有key，热备从节点         O(n)&#xD;&#xA;dbsize              ---&amp;gt;    计算key的总数                   O(1)&#xD;&#xA;exist key           ---&amp;gt;    检查key是否存在，返回0或1       O(1)&#xD;&#xA;del key             ---&amp;gt;    删除指定的key                   O(1)&#xD;&#xA;expire key seconds  ---&amp;gt;    key在seconds秒后过期            O(1)         &#xD;&#xA;ttl key             ---&amp;gt;    查看key的剩余过期时间           O(1) &#xD;&#xA;persist key         ---&amp;gt;    去掉key的过期时间               O(1) &#xD;&#xA;type key            ---&amp;gt;    查看当前key的类型               O(1)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;常见数据结构&#34;&gt;常见数据结构&lt;/h2&gt;&#xA;&lt;p&gt;String应用场景：字符串缓存、计数器、分布式锁&lt;/p&gt;</description>
    </item>
    <item>
      <title>Redis底层数据结构-Stream源码分析</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis-stream/</link>
      <pubDate>Sat, 27 Jun 2020 14:21:30 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis-stream/</guid>
      <description>&lt;h1 id=&#34;简介&#34;&gt;简介&lt;/h1&gt;&#xA;&lt;p&gt;Redis在5.0.0版本中引进了消息队列的功能，该功能由Stream实现，本文主要介绍Stream的相关实现。&lt;/p&gt;&#xA;&lt;h1 id=&#34;数据结构&#34;&gt;数据结构&lt;/h1&gt;&#xA;&lt;h2 id=&#34;stream&#34;&gt;stream&lt;/h2&gt;&#xA;&lt;p&gt;Stream的实现依赖于Rax树与&lt;code&gt;listpack&lt;/code&gt;结构，每个消息流都包含一个Rax树，以消息ID为key，listpack为value存储在Rax树中。其基本结构如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;rax：rax存储生产者生产的具体消息，每个消息有唯一ID为键&lt;/li&gt;&#xA;&lt;li&gt;length：代表当前stream中消息个数。&lt;/li&gt;&#xA;&lt;li&gt;last_id：为当前stream中最后插入的消息ID，stream为空时，该值为0。&lt;/li&gt;&#xA;&lt;li&gt;cgroups：存储了当前stream相关的消费组，以消费组组名为键，streamCG为值存储在rax中。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; stream {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rax &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;rax;               &lt;span style=&#34;color:#75715e&#34;&gt;/* The radix tree holding the stream. */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; length;        &lt;span style=&#34;color:#75715e&#34;&gt;/* Number of elements inside this stream. */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    streamID last_id;       &lt;span style=&#34;color:#75715e&#34;&gt;/* Zero if there are yet no items. */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rax &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;cgroups;           &lt;span style=&#34;color:#75715e&#34;&gt;/* Consumer groups dictionary: name -&amp;gt; streamCG */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} stream;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一个Stream的基本结构如图所示：&#xA;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/redis/stream/structure.PNG&#34; alt=&#34;Stream结构&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;每一个listpack都有一个master entry，该结构存储了该listpack待插入消息的所有field。&lt;/p&gt;&#xA;&lt;h3 id=&#34;streamid&#34;&gt;streamID&lt;/h3&gt;&#xA;&lt;p&gt;消息ID的基本结构如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;ms：消息创建时的时间&lt;/li&gt;&#xA;&lt;li&gt;seq：序号&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; streamID {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; ms;        &lt;span style=&#34;color:#75715e&#34;&gt;/* Unix time in milliseconds. */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; seq;       &lt;span style=&#34;color:#75715e&#34;&gt;/* Sequence number. */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} streamID;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;streamcg&#34;&gt;streamCG&lt;/h3&gt;&#xA;&lt;p&gt;每个stream会有多个消费组，每个消费组通过组名称进行唯一标识，同时关联一个streamCG结构。该结构如下：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Redis底层数据结构-Quicklist源码分析</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis-quicklist/</link>
      <pubDate>Thu, 25 Jun 2020 10:34:21 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis-quicklist/</guid>
      <description>&lt;h1 id=&#34;简介&#34;&gt;简介&lt;/h1&gt;&#xA;&lt;p&gt;quicklist是Redis 3.2中引入的数据结构，其本质是一个双向链表，链表的节点类型是ziplist，当ziplist节点过多，quicklist会退化成双向链表，以提高效率。&lt;/p&gt;&#xA;&lt;h1 id=&#34;数据结构&#34;&gt;数据结构&lt;/h1&gt;&#xA;&lt;h2 id=&#34;quicklistnode&#34;&gt;quicklistNode&lt;/h2&gt;&#xA;&lt;p&gt;该结构为节点类型。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;prev：指向前驱节点&lt;/li&gt;&#xA;&lt;li&gt;next：指向后继节点&lt;/li&gt;&#xA;&lt;li&gt;zl：指向对应的压缩列表&lt;/li&gt;&#xA;&lt;li&gt;sz：压缩列表的大小&lt;/li&gt;&#xA;&lt;li&gt;encoding：采用的编码方式，1为原生，2代表使用LZF进行压缩&lt;/li&gt;&#xA;&lt;li&gt;container：为节点指向的容器类型，1代表none，2代表ziplist存储数据&lt;/li&gt;&#xA;&lt;li&gt;recompress：代表这个节点是否是压缩节点，如果是，则使用压缩节点前先进行解压缩，使用后重新压缩&lt;/li&gt;&#xA;&lt;li&gt;attempted_compress：测试时使用&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; quicklistNode {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; quicklistNode &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;prev;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; quicklistNode &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;next;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;zl;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; sz;             &lt;span style=&#34;color:#75715e&#34;&gt;/* ziplist size in bytes */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; count : &lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;;     &lt;span style=&#34;color:#75715e&#34;&gt;/* count of items in ziplist */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; encoding : &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;;   &lt;span style=&#34;color:#75715e&#34;&gt;/* RAW==1 or LZF==2 */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; container : &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;;  &lt;span style=&#34;color:#75715e&#34;&gt;/* NONE==1 or ZIPLIST==2 */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; recompress : &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;/* was this node previous compressed? */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; attempted_compress : &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;/* node can&amp;#39;t compress; too small */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; extra : &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;/* more bits to steal for future usage */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} quicklistNode;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;quicklistlzf&#34;&gt;quicklistLZF&lt;/h2&gt;&#xA;&lt;p&gt;如果使用LZF算法进行压缩，节点指向的结构为quicklistLZF，其中sz表示compressed数组所占用字节大小。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Redis底层数据结构-Intset源码分析</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis-intset/</link>
      <pubDate>Sat, 20 Jun 2020 15:28:27 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis-intset/</guid>
      <description>&lt;h1 id=&#34;简介&#34;&gt;简介&lt;/h1&gt;&#xA;&lt;p&gt;Intset是一个有序的，存储Integer类型数据的结构，当元素为64位有符号整数范围之内时，它是Redis数据结构中有序集合ZSET的底层实现，但是当元素个数超过一定数量时（默认为512），会转为hashtable进行存储，由配置项&lt;code&gt;set-max-intset-entries 512&lt;/code&gt;决定。如果向有序集合中添加非整型变量，底层实现也会装欢为hashtable。&lt;/p&gt;&#xA;&lt;h1 id=&#34;数据结构&#34;&gt;数据结构&lt;/h1&gt;&#xA;&lt;p&gt;intset结构如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define INTSET_ENC_INT16 (sizeof(int16_t))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define INTSET_ENC_INT32： (sizeof(int32_t))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define INTSET_ENC_INT64 (sizeof(int64_t))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; intset {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt; encoding;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt; length;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int8_t&lt;/span&gt; contents[];&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} intset;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;各字段含义：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;encoding：编码类型，决定每个元素占用几个字节&#xA;&lt;ul&gt;&#xA;&lt;li&gt;INTSET_ENC_INT16：当元素大小位于&lt;code&gt;INT16_MIN&lt;/code&gt;和&lt;code&gt;INT16_MAX&lt;/code&gt;之间使用，每个元素占用两个字节。&lt;/li&gt;&#xA;&lt;li&gt;INTSET_ENC_INT32：元素大小位于&lt;code&gt;INT16_MAX&lt;/code&gt;和&lt;code&gt;INT32_MAX&lt;/code&gt;之间或&lt;code&gt;INT32_MIN&lt;/code&gt;到&lt;code&gt;INT16_MIN&lt;/code&gt;之间，该编码方式占用四个字节。&lt;/li&gt;&#xA;&lt;li&gt;INTSET_ENC_INT64：元素大小位于&lt;code&gt;INT32_MAX&lt;/code&gt;到&lt;code&gt;INT64_MAX&lt;/code&gt;或&lt;code&gt;INT64_MIN&lt;/code&gt;到&lt;code&gt;INT32_MIN&lt;/code&gt;之间，该编码方式每个元素占用八个字节。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;length：元素个数&lt;/li&gt;&#xA;&lt;li&gt;contents：存储具体元素的数组，从小到大排序，并且不包含任何重复项&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;当添加的新元素比集合里面所有元素类型都长时，集合需要整体进行upgrade，然后完成添加。&lt;/p&gt;&#xA;&lt;h1 id=&#34;接口&#34;&gt;接口&lt;/h1&gt;&#xA;&lt;h2 id=&#34;intsetfind&#34;&gt;intsetFind&lt;/h2&gt;&#xA;&lt;p&gt;查找算法主要通过二分查找实现。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* Determine whether a value belongs to this set */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;uint8_t&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;intsetFind&lt;/span&gt;(intset &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;is, &lt;span style=&#34;color:#66d9ef&#34;&gt;int64_t&lt;/span&gt; value) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//判断编码方式&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint8_t&lt;/span&gt; valenc &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_intsetValueEncoding&lt;/span&gt;(value);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//编码方式如果当前intset的编码方式，直接返回0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//否则调用intsetSearch函数进行查找&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; valenc &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;intrev32ifbe&lt;/span&gt;(is&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;encoding) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;intsetSearch&lt;/span&gt;(is,value,NULL);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint8_t&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;intsetSearch&lt;/span&gt;(intset &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;is, &lt;span style=&#34;color:#66d9ef&#34;&gt;int64_t&lt;/span&gt; value, &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;pos) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; min &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, max &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;intrev32ifbe&lt;/span&gt;(is&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;length)&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, mid &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int64_t&lt;/span&gt; cur &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/* The value can never be found when the set is empty */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//intset如果为空，直接返回0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;intrev32ifbe&lt;/span&gt;(is&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;length) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (pos) &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;pos &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;当前元素如果大于当前有序集合最大值或者小于最小值，直接返回&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (value &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_intsetGet&lt;/span&gt;(is,max)) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (pos) &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;pos &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;intrev32ifbe&lt;/span&gt;(is&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;length);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (value &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_intsetGet&lt;/span&gt;(is,&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (pos) &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;pos &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//由于集合有序，采用二分查找&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt;(max &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; min) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        mid &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ((&lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;)min &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;)max) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        cur &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_intsetGet&lt;/span&gt;(is,mid);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (value &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; cur) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            min &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; mid&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (value &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; cur) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            max &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; mid&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (value &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; cur) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (pos) &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;pos &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; mid;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (pos) &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;pos &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; min;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;intsetadd&#34;&gt;intsetAdd&lt;/h2&gt;&#xA;&lt;p&gt;主要逻辑如下：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Redis底层数据结构-Dict源码分析</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis-dict/</link>
      <pubDate>Fri, 29 May 2020 18:30:20 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis-dict/</guid>
      <description>&lt;h1 id=&#34;简介&#34;&gt;简介&lt;/h1&gt;&#xA;&lt;p&gt;字典是一种用来存储键值对的数据结构。Redis本身就是KV型数据库，整个数据库就是用字典进行存储的，对Redis的增删改查操作，实际上就是对字典中的数据进行增删改查操作。&lt;/p&gt;&#xA;&lt;h1 id=&#34;数据结构&#34;&gt;数据结构&lt;/h1&gt;&#xA;&lt;h2 id=&#34;hashtable&#34;&gt;HashTable&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;table：指针数组，用于存储键值对，指向的是&lt;code&gt;dictEntry&lt;/code&gt;结构体，每个&lt;code&gt;dictEntry&lt;/code&gt;存有键值对&lt;/li&gt;&#xA;&lt;li&gt;size：table数组的大小&lt;/li&gt;&#xA;&lt;li&gt;sizemask：掩码，用来计算键的索引值。值恒为size -1&lt;/li&gt;&#xA;&lt;li&gt;used：table数组已存键值对个数&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Hash表的数组容量初始值为4，扩容倍数为当前一倍，所以sizemask大小为&lt;code&gt;3,7,11,31&lt;/code&gt;，二进制表示为&lt;code&gt;111111...&lt;/code&gt;，在计算索引值时，首先计算hash值，通过&lt;code&gt;hash = dict-&amp;gt; type-&amp;gt;hashFunction(k0)&lt;/code&gt;得到对应hash。再通过&lt;code&gt;idx = hash &amp;amp; d-&amp;gt;dt[table].sizemask&lt;/code&gt;计算entry存储的索引位置，位运算速度快于取余运算，Redis使用链地址法来解决&lt;strong&gt;hash冲突&lt;/strong&gt;问题。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; dictht {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    dictEntry &lt;span style=&#34;color:#f92672&#34;&gt;**&lt;/span&gt;table;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; size;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; sizemask;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; used;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} dictht;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;rehash&#34;&gt;rehash&lt;/h3&gt;&#xA;&lt;p&gt;hashtable一般需要将负载因子维护在一个合理的范围，使得其达到最大的操作效率，当键值对数量太多或太少时，都需要对hashtable进行相应的扩展或缩容。rehash动作是分批次、渐进式完成的，这是为了避免rehash对server性能造成影响。&lt;/p&gt;&#xA;&lt;p&gt;Redis进行rehash的执行步骤如下：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;为&lt;code&gt;ht[1]&lt;/code&gt;分配空间，空间大小取决于&lt;code&gt;ht[0]&lt;/code&gt;包含的键值对数量。&lt;/li&gt;&#xA;&lt;li&gt;将所有保存在&lt;code&gt;ht[0]&lt;/code&gt;的键值对rehash到&lt;code&gt;ht[1]&lt;/code&gt;上，即重新计算对应hash和index，并存储在&lt;code&gt;ht[1]&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;释放&lt;code&gt;ht[0]&lt;/code&gt;空间，将&lt;code&gt;ht[1]&lt;/code&gt;设置为&lt;code&gt;ht[0]&lt;/code&gt;，并在&lt;code&gt;ht[1]&lt;/code&gt;新建一个空白hashtable，为下一次rehash服务。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;在渐进式rehash过程中，查询等操作同时使用两个hashtable。&lt;/p&gt;&#xA;&lt;h3 id=&#34;dictentry&#34;&gt;dictEntry&lt;/h3&gt;&#xA;&lt;p&gt;键值对节点，存放键值对数据。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; dictEntry {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//键&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;key;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;union&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//存储值&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;val;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; u64;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//存储过期时间&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;int64_t&lt;/span&gt; s64;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;double&lt;/span&gt; d;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } v;&lt;span style=&#34;color:#75715e&#34;&gt;//值，联合体&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//next指针，Hash冲突时的单链表法&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; dictEntry &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;next;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} dictEntry;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;dicttype&#34;&gt;dictType&lt;/h3&gt;&#xA;&lt;p&gt;存放的是对字典操作的函数指针&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; dictType {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//Hash函数，默认使用MurmurHash2算法来计算hash值&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;hashFunction)(&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;key);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//键对应的复制函数&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;keyDup)(&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;privdata, &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;key);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//值对应的复制函数&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;valDup)(&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;privdata, &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;obj);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//键的比对函数&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;keyCompare)(&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;privdata, &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;key1, &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;key2);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//键的销毁函数&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;keyDestructor)(&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;privdata, &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;key);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//值得销毁函数&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;valDestructor)(&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;privdata, &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;obj);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} dictType;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;dict&#34;&gt;dict&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;type：字典操作函数指针，指向一个dictType结构的指针&lt;/li&gt;&#xA;&lt;li&gt;privdata：私有数据，配合tyoe指针指向的函数一起使用&lt;/li&gt;&#xA;&lt;li&gt;ht：大小为2的数组，默认使用ht[0]，当字典扩容缩容时进行rehash时，才会用到ht[1]&lt;/li&gt;&#xA;&lt;li&gt;rehashidx：标记该字典是否在进行rehash，没进行为-1，用来记录rehash到了哪个元素，值为下标值&lt;/li&gt;&#xA;&lt;li&gt;iterators：用来记录当前运行的安全迭代器数，当有安全迭代器，会暂停rehash&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;基本结构图如图所示：&#xA;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/redis/dict/dict.png&#34; alt=&#34;字典结构图&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Redis底层数据结构-ZipList源码分析</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis-ziplist/</link>
      <pubDate>Tue, 26 May 2020 16:58:29 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis-ziplist/</guid>
      <description>&lt;h1 id=&#34;简介&#34;&gt;简介&lt;/h1&gt;&#xA;&lt;p&gt;压缩列表（ziplist）的本质是一个字节数组，主要是Redis为了节省内存而设计的数据结构。在Redis的list和hash都使用了ziplist，&lt;strong&gt;当list或hash的元素个数比较少，并且元素都是短字符串或小整数值时&lt;/strong&gt;，使用ziplist作为其底层数据结构。&lt;/p&gt;&#xA;&lt;p&gt;压缩列表的基本结构基本如下所示：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;zlbytes&amp;gt; &amp;lt;zltail&amp;gt; &amp;lt;zllen&amp;gt; &amp;lt;entry&amp;gt; &amp;lt;entry&amp;gt; ... &amp;lt;entry&amp;gt; &amp;lt;zlend&amp;gt;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&#xA;&lt;li&gt;uint32_t zlbytes：压缩列表的字节长度，占4个字节&lt;/li&gt;&#xA;&lt;li&gt;uint32_t zltail：压缩列表尾元素相对于起始地址的偏移量，占4个字节，方便从列表尾部进行操作&lt;/li&gt;&#xA;&lt;li&gt;uint16_t zllen：元素个数，占2个字节，元素个数无法超过2^16-1，只能通过遍历整个列表才能获取到个数&lt;/li&gt;&#xA;&lt;li&gt;uint8_t zlend：列表的结尾元素，占1个字节，值为255（0xff）&lt;/li&gt;&#xA;&lt;li&gt;entry：列表的元素，可以是字节数组或者整数&#xA;&lt;ul&gt;&#xA;&lt;li&gt;prevlen：表示前一个元素的字节长度，1~5个字节表示，当前一个元素长度小于254字节，用1个字节表示，大于或等于254字节时，用5个字节表示，该情况下，第一个字节为&lt;code&gt;0xFE&lt;/code&gt;，剩余4个字节表示真正长度&lt;/li&gt;&#xA;&lt;li&gt;encoding：表示当前元素的编码，编码表示当前存储的是字节数组还是整数&lt;/li&gt;&#xA;&lt;li&gt;entry：存储数据内容&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;encoding选项：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define ZIP_STR_06B (0 &amp;lt;&amp;lt; 6)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define ZIP_STR_14B (1 &amp;lt;&amp;lt; 6)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define ZIP_STR_32B (2 &amp;lt;&amp;lt; 6)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define ZIP_INT_16B (0xc0 | 0&amp;lt;&amp;lt;4)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define ZIP_INT_32B (0xc0 | 1&amp;lt;&amp;lt;4)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define ZIP_INT_64B (0xc0 | 2&amp;lt;&amp;lt;4)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define ZIP_INT_24B (0xc0 | 3&amp;lt;&amp;lt;4)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define ZIP_INT_8B 0xfe&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;下面是一个包含两个元素的ziplist，存储的数据为字符串“2”和“5”。它由15个字节组成&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;   [0f 00 00 00] [0c 00 00 00] [02 00] [00 f3] [02 f6] [ff]&#xD;&#xA;         |             |          |       |       |     |&#xD;&#xA;      zlbytes        zltail    entries   &amp;#34;2&amp;#34;     &amp;#34;5&amp;#34;   end&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Redis通过宏定义来对以上部分进行快速定位，zl为压缩列表首地址指针。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Redis底层数据结构-SkipList源码分析</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis-zskiplist/</link>
      <pubDate>Mon, 25 May 2020 21:31:00 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis-zskiplist/</guid>
      <description>&lt;h1 id=&#34;简介&#34;&gt;简介&lt;/h1&gt;&#xA;&lt;p&gt;跳表(SkipList)通过对有序链表添加多级索引，从而实现类似于二分查找效果的有序链表，它的插入/删除/搜索的平均时间复杂度为&lt;code&gt;O(log n)&lt;/code&gt;，该数据结构可以用来代替平衡树以提高效率。其基本结构如 下图所示：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/redis/skiplist/skiplist.png&#34; alt=&#34;跳表基本结构&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;如果此时查找51的节点，步骤基本如下：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;从第二层开始查找，1比51小，向后比较&lt;/li&gt;&#xA;&lt;li&gt;21比51小，21后面为NULL，下降到第一层的21先后比较&lt;/li&gt;&#xA;&lt;li&gt;第一层中21的next节点为41，41比51小，41的next节点61比51大，下降到第0层比较&lt;/li&gt;&#xA;&lt;li&gt;41的next节点为51，查找完成。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h1 id=&#34;数据结构&#34;&gt;数据结构&lt;/h1&gt;&#xA;&lt;p&gt;zskiplistNode：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;ele：存储SDS类型的数据&lt;/li&gt;&#xA;&lt;li&gt;score：排序用的分值&lt;/li&gt;&#xA;&lt;li&gt;backward：后退指针，指向当前节点最底层的前驱节点，第一个指向NULL&lt;/li&gt;&#xA;&lt;li&gt;level：数组，它的长度在生成时随机生成一个1 ~ 64的值，值越大出现概率越低&#xA;&lt;ul&gt;&#xA;&lt;li&gt;forward：指向本层的下一个节点，尾节点指向NULL&lt;/li&gt;&#xA;&lt;li&gt;span：指向的节点与本节点之间的元素个数&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;zskiplist：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;header：指向跳表的头节点&lt;/li&gt;&#xA;&lt;li&gt;tail：指向跳表的尾节点&lt;/li&gt;&#xA;&lt;li&gt;length：跳表的长度&lt;/li&gt;&#xA;&lt;li&gt;level：跳表的高度&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* ZSETs use a specialized version of Skiplists */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; zskiplistNode {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sds ele;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;double&lt;/span&gt; score;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; zskiplistNode &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;backward;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; zskiplistLevel {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; zskiplistNode &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;forward;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; span;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } level[];&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} zskiplistNode;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; zskiplist {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; zskiplistNode &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;header, &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;tail;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; length;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; level;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} zskiplist;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; zset {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    dict &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;dict;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    zskiplist &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;zsl;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} zset;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;接口&#34;&gt;接口&lt;/h1&gt;&#xA;&lt;h2 id=&#34;zslcreate&#34;&gt;zslCreate&lt;/h2&gt;&#xA;&lt;h3 id=&#34;zslcreatenode&#34;&gt;zslCreateNode&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* Create a skiplist node with the specified number of levels.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * The SDS string &amp;#39;ele&amp;#39; is referenced by the node after the call. */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;zskiplistNode &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;zslCreateNode&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; level, &lt;span style=&#34;color:#66d9ef&#34;&gt;double&lt;/span&gt; score, sds ele) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//申请内存空间&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    zskiplistNode &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;zn &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;zmalloc&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;sizeof&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;zn)&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;level&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;sizeof&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; zskiplistLevel));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//初始化&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    zn&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;score &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; score;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    zn&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;ele &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ele;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; zn;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;zslcreate-1&#34;&gt;zslCreate&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/* Create a new skiplist. */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;zskiplist &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;zslCreate&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; j;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//指向跳表的指针&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    zskiplist &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;zsl;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//申请内存空间&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    zsl &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;zmalloc&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;sizeof&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;zsl));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//设置默认值&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    zsl&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;level &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    zsl&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;length &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//创建头节点&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    zsl&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;header &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;zslCreateNode&lt;/span&gt;(ZSKIPLIST_MAXLEVEL,&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,NULL);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//将头节点的level数组的forward设置为NULL，span设置为0&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (j &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; j &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; ZSKIPLIST_MAXLEVEL; j&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        zsl&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;header&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;level[j].forward &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; NULL;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        zsl&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;header&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;level[j].span &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//设置头尾节点&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    zsl&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;header&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;backward &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; NULL;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    zsl&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;tail &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; NULL;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; zsl;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;zslrandomlevel&#34;&gt;zslRandomLevel&lt;/h2&gt;&#xA;&lt;p&gt;level最小值为1，最大值为64，该方法随机生成1 ~ 64的值。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Redis底层数据结构-SDS</title>
      <link>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis%E5%BA%95%E5%B1%82%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84-sds/</link>
      <pubDate>Sun, 24 May 2020 18:59:27 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E4%B8%AD%E9%97%B4%E4%BB%B6/redis/redis%E5%BA%95%E5%B1%82%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84-sds/</guid>
      <description>&lt;h1 id=&#34;简介&#34;&gt;简介&lt;/h1&gt;&#xA;&lt;p&gt;简单动态字符串(Simple Dynamic Strings)是Redis的基本数据结构之一，主要用于存储字符串和整型数据。SDS兼容C语言标准字符串处理函数，同时保证了二进制安全。&lt;/p&gt;&#xA;&lt;h1 id=&#34;数据结构&#34;&gt;数据结构&lt;/h1&gt;&#xA;&lt;h2 id=&#34;原始版本&#34;&gt;原始版本&lt;/h2&gt;&#xA;&lt;p&gt;在Redis 3.2之前，SDS基本结构如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//buf中已使用字节数&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; len;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//buf中剩余字节数&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; free;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;//数据&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; buf[];&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;该结构有如下几个优点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;有单独的变量存储字符串长度，由于有长度，不会依赖于&lt;code&gt;\0&lt;/code&gt;终止符，保证二进制安全。&lt;/li&gt;&#xA;&lt;li&gt;杜绝了缓冲区溢出问题。&lt;/li&gt;&#xA;&lt;li&gt;获取字符串长度为O(1)&lt;/li&gt;&#xA;&lt;li&gt;字符串存储在buf数组中，兼容C处理字符串的函数。&lt;/li&gt;&#xA;&lt;li&gt;减少修改字符串时带来的内存分配次数。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;SDS的空间是预先分配的&lt;/li&gt;&#xA;&lt;li&gt;惰性空间释放：当SDS保存的字符串缩短后，并不会立即将内存空间free&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;改进&#34;&gt;改进&lt;/h2&gt;&#xA;&lt;p&gt;Redis 3.2之后，采用如下结构进行存储。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;__attribute__&lt;/span&gt; ((__packed__)) sdshdr5 {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; flags; &lt;span style=&#34;color:#75715e&#34;&gt;/* 3 lsb of type, and 5 msb of string length */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; buf[];&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;__attribute__&lt;/span&gt; ((__packed__)) sdshdr8 {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint8_t&lt;/span&gt; len; &lt;span style=&#34;color:#75715e&#34;&gt;/* used */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint8_t&lt;/span&gt; alloc; &lt;span style=&#34;color:#75715e&#34;&gt;/* excluding the header and null terminator */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; flags; &lt;span style=&#34;color:#75715e&#34;&gt;/* 3 lsb of type, 5 unused bits */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; buf[];&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;__attribute__&lt;/span&gt; ((__packed__)) sdshdr16 {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint16_t&lt;/span&gt; len; &lt;span style=&#34;color:#75715e&#34;&gt;/* used */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint16_t&lt;/span&gt; alloc; &lt;span style=&#34;color:#75715e&#34;&gt;/* excluding the header and null terminator */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; flags; &lt;span style=&#34;color:#75715e&#34;&gt;/* 3 lsb of type, 5 unused bits */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; buf[];&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;__attribute__&lt;/span&gt; ((__packed__)) sdshdr32 {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt; len; &lt;span style=&#34;color:#75715e&#34;&gt;/* used */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt; alloc; &lt;span style=&#34;color:#75715e&#34;&gt;/* excluding the header and null terminator */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; flags; &lt;span style=&#34;color:#75715e&#34;&gt;/* 3 lsb of type, 5 unused bits */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; buf[];&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;__attribute__&lt;/span&gt; ((__packed__)) sdshdr64 {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; len; &lt;span style=&#34;color:#75715e&#34;&gt;/* used */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; alloc; &lt;span style=&#34;color:#75715e&#34;&gt;/* excluding the header and null terminator */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;unsigned&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; flags; &lt;span style=&#34;color:#75715e&#34;&gt;/* 3 lsb of type, 5 unused bits */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; buf[];&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;sdshdr5中采用位来存储相关信息，其中flags占1字节，其中低3位用来表示type，高5位表示长度，所以长度区间为（0 ~ 31），所以长度大于31的字符串需要采用sdshdr8及以上存储。sdshdr8中flags低3位存储类型，剩余5位闲置。以下是字符串类型的宏定义：&lt;/p&gt;</description>
    </item>
    <item>
      <title>设计模式之行为型模式（四）</title>
      <link>http://localhost:1313/posts/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/design-pattern-behavior/</link>
      <pubDate>Sat, 23 May 2020 19:12:51 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/design-pattern-behavior/</guid>
      <description>&lt;h1 id=&#34;模板方法模式&#34;&gt;模板方法模式&lt;/h1&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;定义一个操作中的算法的框架，而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;模板方法模式涉及两个角色：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;抽象模板角色（Abstract Template）：该角色定义多个抽象操作，以便让子类实现。&lt;/li&gt;&#xA;&lt;li&gt;具体模板角色（Concrete Template）：该角色实现抽象模板中的抽象方法&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;AbstractClass&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;operation&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;templateMethod&lt;/span&gt;(){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;operation&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ConcreteClass&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; AbstractClass {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;operation&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//业务&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Client&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;(String&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; args) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        AbstractClass ac &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ConcreteClass();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ac.&lt;span style=&#34;color:#a6e22e&#34;&gt;templateMethod&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;优点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;封装不变的部分，扩展可变部分。不变的部分封装到父类去实现，可变的通过继承进行扩展。&lt;/li&gt;&#xA;&lt;li&gt;提取公共代码，便于维护，将公共部分的代码抽取出来放在父类中，维护时只需要修改父类中的代码。&lt;/li&gt;&#xA;&lt;li&gt;行为由父类控制，子类实现。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h1 id=&#34;命令模式&#34;&gt;命令模式&lt;/h1&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;将一个请求封装成一个对象，从而让你使用不同的请求把客户端参数化，对请求排队或者记录请求日志，可以提供命令的撤销和恢复功能。&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;该模式有四个角色：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;命令角色：该角色声明抽象接口&lt;/li&gt;&#xA;&lt;li&gt;具体命令角色：定义一个接收者和行为之间的弱耦合，实现命令方法，并调用接收者的相应操作。&lt;/li&gt;&#xA;&lt;li&gt;调用者：负责调用命令对象执行请求。&lt;/li&gt;&#xA;&lt;li&gt;接收者：该角色负责具体实施和执行一个请求。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Command&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;execute&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ConcreteCommand&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; Command {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Receiver receiver;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ConcreteCommand&lt;/span&gt;(Receiver receiver) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;receiver&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; receiver;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;execute&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;receiver&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;action&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Receiver&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;action&lt;/span&gt;(){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;执行动作&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Invoker&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Command command;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setCommand&lt;/span&gt;(Command command) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; command;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;action&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;execute&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;优点：&lt;/p&gt;</description>
    </item>
    <item>
      <title>设计模式之结构型模式（三）</title>
      <link>http://localhost:1313/posts/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/design-pattern-structure/</link>
      <pubDate>Thu, 21 May 2020 17:51:48 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/design-pattern-structure/</guid>
      <description>&lt;h1 id=&#34;适配器模式&#34;&gt;适配器模式&lt;/h1&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;适配器模式将某个类的接口转换成客户端期望的另一个接口表示，主要目的是兼容性，让原本因接口不匹配不能在一起工作的两个类可以协同工作，别名为包装器（Wrapper）。&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;h2 id=&#34;类适配器&#34;&gt;类适配器&lt;/h2&gt;&#xA;&lt;p&gt;注意：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;类适配器需要继承src类，这要求dst必须是接口，有一定的局限性&lt;/li&gt;&#xA;&lt;li&gt;src类的方法在Adapter中会被暴露出来&lt;/li&gt;&#xA;&lt;li&gt;Adapter需要重写src的方法&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @author ：L1nker4&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @date ： 创建于  2020/5/19 11:40&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @description： 被适配的类&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Voltage220V&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;output220V&lt;/span&gt;(){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; src &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 220;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;电压：&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; src &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;伏&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; src;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * 适配接口&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IVoltage5V&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;output5V&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @author ：L1nker4&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @date ： 创建于  2020/5/19 11:42&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @description： 适配器类&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;VoltageAdapter&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; Voltage220V &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; IVoltage5V{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;output5V&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; src &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; output220V();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; src &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; 44;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @author ：L1nker4&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @date ： 创建于  2020/5/19 11:44&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @description： 手机类&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Phone&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;charging&lt;/span&gt;(IVoltage5V iVoltage5V){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (iVoltage5V.&lt;span style=&#34;color:#a6e22e&#34;&gt;output5V&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; 5){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;电压为：5V，可以充电&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;电压不正常，无法充电&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;对象适配器&#34;&gt;对象适配器&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;基本思路和类适配器模式相同，只是将Adapter类作修改，不是继承src类，而是持有src类的实例，以解决兼容性的问题，即：持有src类，实现dst接口，完成src-&amp;gt;dst的适配。&lt;/li&gt;&#xA;&lt;li&gt;根据合成复用原则，在系统中使用关联关系替代继承关系。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @author ：L1nker4&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @date ： 创建于  2020/5/19 11:42&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @description： 适配器类&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;VoltageAdapter&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;implements&lt;/span&gt; IVoltage5V {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; Voltage220V voltage220V;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;VoltageAdapter&lt;/span&gt;(Voltage220V voltage220V) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;voltage220V&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; voltage220V;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;@Override&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;output5V&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; voltage220V){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; src &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; voltage220V.&lt;span style=&#34;color:#a6e22e&#34;&gt;output220V&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;适配完成&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; src &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; 44;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;适配失败&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; 0;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;应用&#34;&gt;应用&lt;/h2&gt;&#xA;&lt;p&gt;Spring MVC - HandlerAdapter&lt;/p&gt;</description>
    </item>
    <item>
      <title>设计模式之创建型模式（二）</title>
      <link>http://localhost:1313/posts/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/design-pattern-creational/</link>
      <pubDate>Sun, 17 May 2020 16:39:24 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/design-pattern-creational/</guid>
      <description>&lt;h1 id=&#34;单例模式&#34;&gt;单例模式&lt;/h1&gt;&#xA;&lt;p&gt;采取一定的方法保证在整个软件系统中，对某个类只能存在一个对象实例，并且该类只提供一个取得其对象实例的方法（静态方法）。&lt;/p&gt;&#xA;&lt;p&gt;比如Hibernate的SessionFactory，它充当数据存储源的代理，并负责创建Session对象。&lt;/p&gt;&#xA;&lt;h2 id=&#34;饿汉式&#34;&gt;饿汉式&lt;/h2&gt;&#xA;&lt;h3 id=&#34;静态常量方法&#34;&gt;静态常量方法&lt;/h3&gt;&#xA;&lt;p&gt;demo：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Singleton&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * 构造器私有化，外部不能new&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Singleton&lt;/span&gt;(){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;final&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; Singleton INSTANCE &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Singleton();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; Singleton &lt;span style=&#34;color:#a6e22e&#34;&gt;getInstance&lt;/span&gt;(){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; INSTANCE;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;优点&#xA;&lt;ul&gt;&#xA;&lt;li&gt;写法简单，在类装载的时候就完成实例化，避免了线程安全问题。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;缺点&#xA;&lt;ul&gt;&#xA;&lt;li&gt;没有达到&lt;code&gt;lazy loading&lt;/code&gt;的效果，如果一直没有使用，就会造成内存浪费。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;静态代码块&#34;&gt;静态代码块&lt;/h3&gt;&#xA;&lt;p&gt;demo：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Singleton&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * 构造器私有化，外部不能new&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Singleton&lt;/span&gt;(){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        INSTANCE &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Singleton();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; Singleton INSTANCE ;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; Singleton &lt;span style=&#34;color:#a6e22e&#34;&gt;getInstance&lt;/span&gt;(){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; INSTANCE;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;懒汉式&#34;&gt;懒汉式&lt;/h2&gt;&#xA;&lt;h3 id=&#34;线程不安全&#34;&gt;线程不安全&lt;/h3&gt;&#xA;&lt;p&gt;demo：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Singleton&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     * 构造器私有化，外部不能new&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;     */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Singleton&lt;/span&gt;(){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; Singleton INSTANCE ;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; Singleton &lt;span style=&#34;color:#a6e22e&#34;&gt;getInstance&lt;/span&gt;(){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (INSTANCE &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            INSTANCE &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Singleton();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; INSTANCE;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;优点&#xA;&lt;ul&gt;&#xA;&lt;li&gt;起到了&lt;code&gt;lazy loading&lt;/code&gt;的效果，当时只能在单线程下使用&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;缺点&#xA;&lt;ul&gt;&#xA;&lt;li&gt;多线程下会出现线程安全问题。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;线程安全&#34;&gt;线程安全&lt;/h3&gt;&#xA;&lt;p&gt;加上&lt;code&gt;synchronized&lt;/code&gt;关键字。&lt;/p&gt;</description>
    </item>
    <item>
      <title>设计模式之设计原则（一）</title>
      <link>http://localhost:1313/posts/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/design-principle/</link>
      <pubDate>Sun, 03 May 2020 18:55:28 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/design-principle/</guid>
      <description>&lt;h1 id=&#34;简介&#34;&gt;简介&lt;/h1&gt;&#xA;&lt;h2 id=&#34;什么是设计模式&#34;&gt;什么是设计模式？&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;每一个模式描述了一个在我们周围不断重复发生的问题，以及该问题的解决方案的核心，这样，你就能不必一次又一次地使用该方案而不必重复劳动。&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;h2 id=&#34;深入理解面向对象&#34;&gt;深入理解面向对象&lt;/h2&gt;&#xA;&lt;p&gt;向下：三大面向对象机制&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;封装：隐藏内部实现&lt;/li&gt;&#xA;&lt;li&gt;继承：复用现有代码&lt;/li&gt;&#xA;&lt;li&gt;多态：改写对象行为&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;现上：深刻把握面向对象机制带来的抽象意义，理解如何使用这些机制来表达现实世界，掌握什么是“好的面向对象设计”&lt;/p&gt;&#xA;&lt;h2 id=&#34;软件设计复杂的根本原因&#34;&gt;软件设计复杂的根本原因&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;变化&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;客户需求的变化&lt;/li&gt;&#xA;&lt;li&gt;技术平台的变化&lt;/li&gt;&#xA;&lt;li&gt;开发团队的变化&lt;/li&gt;&#xA;&lt;li&gt;市场环境的变化&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;如何解决复杂性&#34;&gt;如何解决复杂性？&lt;/h2&gt;&#xA;&lt;p&gt;分解&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;人们面对复杂性有一个常见的作法：分而治之，将大问题分解为多个小问题，将复杂问题分解为多个简单问题。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;抽象&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;更高层次来讲，人们处理复杂性有一个通用的计数，即抽象。由于不能掌握全部的复杂对象，我们选择忽视它的非本质细节，而去处理泛化和理想化了的对象模型。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h1 id=&#34;设计原则&#34;&gt;设计原则&lt;/h1&gt;&#xA;&lt;h2 id=&#34;单一职责原则srp&#34;&gt;单一职责原则（SRP）&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;一个接口仅负责一个职责，一个类只能由一个原因引起变化。&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;优点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;类的复杂性降低，实现什么职责都有清晰明确的定义&lt;/li&gt;&#xA;&lt;li&gt;可读性提高&lt;/li&gt;&#xA;&lt;li&gt;可维护性提高&lt;/li&gt;&#xA;&lt;li&gt;变更引起的风险降低，变更时必不可少的，如果接口的单一职责做好，一个接口的修改只对相对应的实现类有影响。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;里氏替换原则lsp&#34;&gt;里氏替换原则（LSP）&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;所有引用基类的地方必须能透明的使用其子类的对象。&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;只要父类能出现的地方子类就可以出现，而且替换为子类也不会产生任何错误或异常。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;子类必须完全实现父类的方法&lt;/li&gt;&#xA;&lt;li&gt;子类可以有自己的方法和属性&lt;/li&gt;&#xA;&lt;li&gt;覆盖或实现父类的方法时输入参数可以被放大&lt;/li&gt;&#xA;&lt;li&gt;覆写或实现父类的方法时输出结果可以被缩小&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;依赖倒置原则dip&#34;&gt;依赖倒置原则（DIP）&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;高层模块不应该依赖低层模块，两者都应该依赖其抽象&lt;/li&gt;&#xA;&lt;li&gt;抽象不应该依赖细节&lt;/li&gt;&#xA;&lt;li&gt;细节应该依赖抽象&lt;/li&gt;&#xA;&lt;/ul&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;在Java语言中的表现：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;模块间的依赖通过抽象发生，实现类之间不发生直接的依赖关系，其依赖关系是通过接口或抽象类产生的&lt;/li&gt;&#xA;&lt;li&gt;接口或抽象类不依赖于实现类&lt;/li&gt;&#xA;&lt;li&gt;实现类依赖接口或抽象类&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;对象的依赖关系有三种方式来传递：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;构造函数传递依赖对象&lt;/li&gt;&#xA;&lt;li&gt;Setter方法传递依赖对象&lt;/li&gt;&#xA;&lt;li&gt;接口声明依赖对象&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;如何实践？&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;每个类尽量都有接口或抽象类，或者抽象类与接口两者都具备&lt;/li&gt;&#xA;&lt;li&gt;变量的表面类型尽量是接口或者抽象类&lt;/li&gt;&#xA;&lt;li&gt;任何类都不应该从具体类派生&lt;/li&gt;&#xA;&lt;li&gt;尽量不要覆写基类的方法&lt;/li&gt;&#xA;&lt;li&gt;结合里氏替换原则使用：接口负责定义public属性和方法，并且声明与其他对象的依赖关系，抽象类负责公共内部构造部分的实现，实现类准确的实现业务逻辑，统统实在适当的时候对父类进行细化。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;接口隔离原则isp&#34;&gt;接口隔离原则（ISP）&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;客户端不应该依赖它不需要的接口&lt;/li&gt;&#xA;&lt;li&gt;类间的依赖关系应该建立在最小的接口上&lt;/li&gt;&#xA;&lt;/ul&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;接口分为两种：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;实例接口：在Java中声明一个类，然后用new关键字产生一个实例，它就是对一个类型的事物的描述，这是一种接口&lt;/li&gt;&#xA;&lt;li&gt;类接口：interface关键字定义的接口&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;接口隔离原则对接口进行规范约束，包含以下四个含义：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;接口要尽量小&lt;/li&gt;&#xA;&lt;li&gt;接口要高内聚，减少对外的交互（尽量少公布public方法）&lt;/li&gt;&#xA;&lt;li&gt;定制服务（只提供访问者需要的方法）&lt;/li&gt;&#xA;&lt;li&gt;接口设计是有限度的（粒度越小，系统越灵活，结构越复杂，开发难度增加，可维护性降低）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;如何实践？&lt;/p&gt;</description>
    </item>
    <item>
      <title>深入MySQL索引细节</title>
      <link>http://localhost:1313/posts/mysql/mysql%E7%B4%A2%E5%BC%95%E7%BB%86%E8%8A%82/</link>
      <pubDate>Fri, 01 May 2020 11:23:33 +0000</pubDate>
      <guid>http://localhost:1313/posts/mysql/mysql%E7%B4%A2%E5%BC%95%E7%BB%86%E8%8A%82/</guid>
      <description>&lt;h2 id=&#34;索引基本概念&#34;&gt;索引基本概念&lt;/h2&gt;&#xA;&lt;p&gt;维基百科对索引的定义：数据库索引是一种数据结构，它以额外的写入和存储空间为代价来提高数据库表上数据索引操作的速度。&lt;/p&gt;&#xA;&lt;p&gt;MySQL官方对索引的定义是用于快速查找记录的一种数据结构。&lt;/p&gt;&#xA;&lt;p&gt;索引是一个以空间换时间的经典案例。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;索引是物理数据页，数据页大小决定了一个页可以存储多少个索引行，以及需要多少页来存储指定大小的索引。&lt;/li&gt;&#xA;&lt;li&gt;索引可以加快检索速度，也可以降低索引列插入、删除、更新的速度，索引维护需要代价。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;有两种基本的索引类型：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;顺序索引：基于值的顺序排序&lt;/li&gt;&#xA;&lt;li&gt;散列索引：基于将值平均分布到若干bucket中，一个值所属的bucket是由一个散列函数决定。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;索引的数据结构&#34;&gt;索引的数据结构&lt;/h2&gt;&#xA;&lt;h3 id=&#34;b-tree&#34;&gt;B Tree&lt;/h3&gt;&#xA;&lt;p&gt;查询的时间主要依赖于磁盘I/O的次数，每次节点访问需要进行一次磁盘IO操作。&#xA;B Tree取代平衡二叉树主要是降低了树的高度，减少了磁盘IO的次数。其基本结构如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/mysql/index/B%20Tree.jpg&#34; alt=&#34;B Tree&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;B Tree别称平衡的多路搜索树，每个节点最多包括M个子节点，M称为B树的阶。&lt;/p&gt;&#xA;&lt;p&gt;M阶的B树（M &amp;gt; 2）有以下的特性：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;根节点的儿子数的范围是 [2,M]。&lt;/li&gt;&#xA;&lt;li&gt;每个中间节点包含 k-1 个关键字和 k 个孩子，孩子的数量 = 关键字的数量 +1，k 的取值范围为 [ceil(M/2), M]。&lt;/li&gt;&#xA;&lt;li&gt;叶子节点包括 k-1 个关键字（叶子节点没有孩子），k 的取值范围为 [ceil(M/2), M]。&lt;/li&gt;&#xA;&lt;li&gt;假设中间节点节点的关键字为：Key[1], Key[2], …, Key[k-1]，且关键字按照升序排序，即 Key[i]&amp;lt;Key[i+1]。此时 k-1 个关键字相当于划分了 k 个范围，也就是对应着 k 个指针，即为：P[1], P[2], …, P[k]，其中 P[1] 指向关键字小于 Key[1] 的子树，P[i] 指向关键字属于 (Key[i-1], Key[i]) 的子树，P[k] 指向关键字大于 Key[k-1] 的子树。&lt;/li&gt;&#xA;&lt;li&gt;所有叶子节点位于同一层。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;b-tree-1&#34;&gt;B+ Tree&lt;/h3&gt;&#xA;&lt;p&gt;B+ Tree与B Tree的差异主要有以下几点：&lt;/p&gt;</description>
    </item>
    <item>
      <title>探索MySQL的事务与锁机制</title>
      <link>http://localhost:1313/posts/mysql/%E6%8E%A2%E7%B4%A2mysql%E7%9A%84%E4%BA%8B%E5%8A%A1%E4%B8%8E%E9%94%81%E6%9C%BA%E5%88%B6/</link>
      <pubDate>Wed, 29 Apr 2020 09:47:16 +0000</pubDate>
      <guid>http://localhost:1313/posts/mysql/%E6%8E%A2%E7%B4%A2mysql%E7%9A%84%E4%BA%8B%E5%8A%A1%E4%B8%8E%E9%94%81%E6%9C%BA%E5%88%B6/</guid>
      <description>&lt;h1 id=&#34;事务概念&#34;&gt;事务概念&lt;/h1&gt;&#xA;&lt;p&gt;简单来说，事务就是要保证一组数据库操作，要么全部成功，要么全部失败。MySQL中事务支持是在存储引擎层实现的。事务拥有四个重要的特性：原子性、一致性、隔离性、持久性，简称为ACID特性，下文将逐一解释。&lt;/p&gt;&#xA;&lt;h2 id=&#34;acid特性&#34;&gt;ACID特性&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;原子性（Atomicity）&#xA;&lt;ul&gt;&#xA;&lt;li&gt;事务开始后所有操作步骤，要么全部完成，要么全部不做，不存在只执行一部分的情况。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;一致性（Consistency）&#xA;&lt;ul&gt;&#xA;&lt;li&gt;事务执行前后，数据从一个合法性状态变换到另一个合法性状态。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A、B转账业务，总金额不变。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;分为数据一致性和约束一致性。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;隔离性（Isolation）&#xA;&lt;ul&gt;&#xA;&lt;li&gt;在一个事务未执行完毕时，其它事务无法读取该事务的数据。&lt;/li&gt;&#xA;&lt;li&gt;MySQL通过锁机制来保证事务的隔离性。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;持久性（Durability）&#xA;&lt;ul&gt;&#xA;&lt;li&gt;事务一旦提交，数据将被保存下来，即使发生宕机等故障，数据库也能将数据恢复。&lt;/li&gt;&#xA;&lt;li&gt;MySQL使用&lt;code&gt;redo log&lt;/code&gt;来保证事务的持久性。当通过事务对数据进行修改时，首先会将操作记录到&lt;code&gt;redo log&lt;/code&gt;中，然后对数据库对应行进行修改，这样即使数据库宕机，也能通过&lt;code&gt;redo log&lt;/code&gt;进行恢复。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;ACID关系如下图所示：&#xA;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/mysql/structure/%E4%BA%8B%E5%8A%A1%E7%89%B9%E6%80%A7.png&#34; alt=&#34;ACID关系&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;显式事务&#34;&gt;显式事务&lt;/h2&gt;&#xA;&lt;p&gt;开始事务：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;BEGIN&lt;/span&gt;;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;或&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;START&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;TRANSACTION&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;两者区别：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;START TRANSACTION&lt;/code&gt;后面可以跟随几个修饰符：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;READ ONLY：标识为只读事务，该事务只能读取数据。&lt;/li&gt;&#xA;&lt;li&gt;READ WRITE：标识为读写事务，该事务可以读写数据。&lt;/li&gt;&#xA;&lt;li&gt;WITH CONSISTENT SNAPSHOT ：启动一致性读。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;完成事务：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;提交事务&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;COMMIT&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;回滚事务&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;ROLLBACK&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;将事务回滚到某个保存点。&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;ROLLBACK&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;TO&lt;/span&gt; [SAVEPOINT]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;隐式事务&#34;&gt;隐式事务&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;SHOW&lt;/span&gt; VARIABLES &lt;span style=&#34;color:#66d9ef&#34;&gt;LIKE&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;autocommit&amp;#39;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;隐式提交数据的情况：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;数据定义语言：CREATE、ALTER、DROP&lt;/li&gt;&#xA;&lt;li&gt;隐式修改mysql数据库中的表&lt;/li&gt;&#xA;&lt;li&gt;事务控制（连续两次BEGIN，第一个BEGIN后面的语句会自动提交）或关于锁定的语句&lt;/li&gt;&#xA;&lt;li&gt;加载数据的语句&lt;/li&gt;&#xA;&lt;li&gt;MySQL复制的语句&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;completion_type&#34;&gt;completion_type&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;set&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;@@&lt;/span&gt;completion_type &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;该变量有三种取值：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;0：默认值，当我们执行COMMIT时会提交事务，再执行下一个事务时，还需要使用BEGIN来开启。&lt;/li&gt;&#xA;&lt;li&gt;1：提交事务后，相当于执行了&lt;code&gt;COMMIT AND CHAIN&lt;/code&gt;，开启链式事务，当我们提交事务后会开启一个相同隔离级别的事务。&lt;/li&gt;&#xA;&lt;li&gt;2：相当于&lt;code&gt;COMMIT AND RELEASE&lt;/code&gt;，提交事务后，与服务器断开连接。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;事务分类&#34;&gt;事务分类&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;扁平事务：最简单的一种，使用BEGIN开启，由COMMIT或ROLLBACK结束。&lt;/li&gt;&#xA;&lt;li&gt;带有保存点的扁平事务：支持回滚到指定保存点的事务。&lt;/li&gt;&#xA;&lt;li&gt;链式事务：一个事务由多个子事务构成，提交前一个事务，触发下一个事务。&lt;/li&gt;&#xA;&lt;li&gt;嵌套事务：由顶层事务控制下面各个层次的事务。&lt;/li&gt;&#xA;&lt;li&gt;分布式事务：分布式系统中的扁平事务。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h1 id=&#34;并发事务问题&#34;&gt;并发事务问题&lt;/h1&gt;&#xA;&lt;h2 id=&#34;脏写&#34;&gt;脏写&lt;/h2&gt;&#xA;&lt;p&gt;事务A覆盖了事务B未提交的更新数据。&lt;/p&gt;</description>
    </item>
    <item>
      <title>ThreadLocalRondom原理剖析</title>
      <link>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/threadlocal-rondom/</link>
      <pubDate>Tue, 28 Apr 2020 17:31:07 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/threadlocal-rondom/</guid>
      <description>&lt;p&gt;ThreadLocalRondom是JDK 7在并发包中新增的随机数生成器，该类弥补了Random类在并发环境下的缺陷。&lt;/p&gt;&#xA;&lt;h2 id=&#34;random的局限性&#34;&gt;Random的局限性&lt;/h2&gt;&#xA;&lt;p&gt;Random生成随机数的方法如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;nextInt&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; bound) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//参数校验&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (bound &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;=&lt;/span&gt; 0)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;throw&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; IllegalArgumentException(BadBound);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//根据老的种子生成新的种子&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; r &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; next(31);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; m &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; bound &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; 1;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//根据新种子计算随机数&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ((bound &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; m) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; 0)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            r &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;)((bound &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt;)r) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; 31);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; u &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; r;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 u &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; (r &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; u &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; bound) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; m &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; 0;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                 u &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; next(31))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                ;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; r;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;next方法通过计算生成新的种子。用原子变量来存放种子，多线程的情况下，CAS操作会保证只有一个线程可以更新老的种子为新种子，更新失败的线程进行自旋，这降低了并发性能，所以产生了ThreadLocalRandom。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;next&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; bits) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; oldseed, nextseed;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        AtomicLong seed &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;this&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;seed&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            oldseed &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; seed.&lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;//seed计算公式，通过CAS操作进行更新&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            nextseed &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (oldseed &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; multiplier &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; addend) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt; mask;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;!&lt;/span&gt;seed.&lt;span style=&#34;color:#a6e22e&#34;&gt;compareAndSet&lt;/span&gt;(oldseed, nextseed));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//将得到的值进行逻辑右移&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;)(nextseed &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; (48 &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; bits));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;threadlocalrandom简介&#34;&gt;ThreadLocalRandom简介&lt;/h2&gt;&#xA;&lt;p&gt;ThreadLocalRandom和ThreadLocal的原理相似，ThreadLocalRandom使得每个线程都维护自己独有的种子变量，这样就不存在竞争问题，大大提高并发性能。&lt;/p&gt;</description>
    </item>
    <item>
      <title>MySQL数据存储结构</title>
      <link>http://localhost:1313/posts/mysql/mysql%E6%95%B0%E6%8D%AE%E5%AD%98%E5%82%A8%E7%BB%93%E6%9E%84/</link>
      <pubDate>Fri, 17 Apr 2020 13:25:04 +0000</pubDate>
      <guid>http://localhost:1313/posts/mysql/mysql%E6%95%B0%E6%8D%AE%E5%AD%98%E5%82%A8%E7%BB%93%E6%9E%84/</guid>
      <description>&lt;h2 id=&#34;索引组织表&#34;&gt;索引组织表&lt;/h2&gt;&#xA;&lt;p&gt;在InnoDB存储引擎中，表是根据主键顺序组织存放的，这种存储方式的表称为索引组织表，每张表都有一个主键，如果创建时没有显式定义主键，InnoDB存储引擎会按照如下方式进行创建主键：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;判断表中是否有非空的唯一索引，如果有，则该列为主键。&lt;/li&gt;&#xA;&lt;li&gt;如果不符合上列条件，InnoDB存储引擎会自动创建一个6字节大小的指针。&lt;/li&gt;&#xA;&lt;li&gt;当表中有多个非空唯一索引，InnoDB会选择第一个定义的非空唯一索引作为主键。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;innodb逻辑存储结构&#34;&gt;InnoDB逻辑存储结构&lt;/h2&gt;&#xA;&lt;p&gt;所有的数据被逻辑存放在表空间，表空间又由段，区，页（块）组成。存储结构如图所示：&#xA;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/mysql/table/IMG_0064.PNG&#34; alt=&#34;InnoDB逻辑存储结构&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;表空间&#34;&gt;表空间&lt;/h3&gt;&#xA;&lt;p&gt;表空间是InnoDB存储引擎逻辑结构的最高层，所有的数据都存放在表空间中。如果开启了&lt;code&gt;innodb_file_per_table&lt;/code&gt;，每张表的数据可以单独放到一个表空间中。但是每张表的表空间存放的只是数据、索引和插入缓冲Bitmap页。其他类的数据，例如回滚信息，插入缓冲索引页，系统事务信息，二次写缓冲等还是存放在原来的共享表空间中。&lt;/p&gt;&#xA;&lt;h3 id=&#34;段&#34;&gt;段&lt;/h3&gt;&#xA;&lt;p&gt;表空间由各个段构成，常见的段有：数据段、索引段、回滚段等。InnoDB存储引擎表是索引组织的，因此数据即索引，索引即数据，数据段即为B+树的叶子节点，索引段即为B+树的非索引节点。在InnoDB存储引擎中，对段的管理都是由引擎自身完成，DBA不能也没有必要对其进行控制。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;引入段的目的&lt;/strong&gt;：对于范围查询，会对B+ Tree节点进行顺序扫描，如果不区分叶子节点和非叶子节点，如果将两者放到同一个区当中，查询效率大打折扣，因此引入段来区分不同类型的页面。&lt;/p&gt;&#xA;&lt;h3 id=&#34;区&#34;&gt;区&lt;/h3&gt;&#xA;&lt;p&gt;区是由连续页组成的空间，在任何情况下每个区的大小都为1MB，为了保证区的连续性，InnoDB一次从磁盘申请4~5个区，在默认情况下，页的大小为16KB，即一个区中共有64个连续页。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;引入区的目的&lt;/strong&gt;：B+ Tree底层通过页存储数据，相邻的两个页物理地址可能离得非常远（产生随机IO），因此分配空间时，直接按区进行分配，这样会将相邻的页在物理上也是连续的，可以消除很多次随机IO，同时会造成空间浪费，整体利远大于弊。&lt;/p&gt;&#xA;&lt;p&gt;为了考虑以完整的区为单位分配给某个段对于&lt;strong&gt;数据量较小&lt;/strong&gt;的表而浪费存储空间的情况，InnoDB提出了&lt;strong&gt;碎片区&lt;/strong&gt;的概念，碎片区中的页属于不同段。&lt;/p&gt;&#xA;&lt;h3 id=&#34;页&#34;&gt;页&lt;/h3&gt;&#xA;&lt;p&gt;页是InnoDB磁盘管理的最小单位，默认每个页大小为16KB，可以通过参数&lt;code&gt;innodb_page_size&lt;/code&gt;将页的大小设置为4K，8K、16K。&lt;/p&gt;&#xA;&lt;p&gt;常见的页类型有：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;数据页&lt;/li&gt;&#xA;&lt;li&gt;undo页&lt;/li&gt;&#xA;&lt;li&gt;系统页&lt;/li&gt;&#xA;&lt;li&gt;事务数据页&lt;/li&gt;&#xA;&lt;li&gt;插入缓冲位图页&lt;/li&gt;&#xA;&lt;li&gt;插入缓冲空闲列表页&lt;/li&gt;&#xA;&lt;li&gt;未压缩的二进制大对象页&lt;/li&gt;&#xA;&lt;li&gt;压缩的二进制大对象页&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;行&#34;&gt;行&lt;/h3&gt;&#xA;&lt;p&gt;InnoDB存储引擎是面向行（row-oriented）的，每个页最多存放16K/2~200行的记录（7992行）。&lt;/p&gt;&#xA;&lt;h2 id=&#34;innodb行记录格式&#34;&gt;InnoDB行记录格式&lt;/h2&gt;&#xA;&lt;h3 id=&#34;compact行记录格式&#34;&gt;Compact行记录格式&lt;/h3&gt;&#xA;&lt;p&gt;该格式在MySQL5.0中引入，其设计目的是高效地存储数据。简单说，一个页存放的行数据越多，其性能就越高。它的存储方式如图所示：&#xA;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/mysql/table/IMG_0065%2820200416-174412%29.PNG&#34; alt=&#34;Compact行记录格式&#34;&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;变长字段长度列表：对于变长字段的真实数据占用的字节长度都存放这里。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;逆序排放，非NULL&lt;/li&gt;&#xA;&lt;li&gt;如果变长列的长度小于255 bytes，则用1 byte表示，否则用2 byte表示。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;NULL标志位：如果该数据行存在NULL值，使用1表示，该部分占用1 byte。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;头信息固定5字节（40位），每位的含义如下：&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;设置&lt;code&gt;deleted_flag&lt;/code&gt;的原因：如果物理删除的话，记录在磁盘上需要重新排列，导致性能消耗，被删除掉的记录会形成一个&lt;strong&gt;垃圾链表（可重用空间）&lt;/strong&gt;，如果之后有新纪录插入到表中，这部分空间将被覆盖掉。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/mysql/table/IMG_0066.PNG&#34; alt=&#34;Compact记录头信息&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;最后的部分就是实际存储每个列的数据，&lt;strong&gt;NULL不占用任何空间&lt;/strong&gt;，除了之前的标志位，每行数据除了用户定义的列之外，还有两个隐藏列，&lt;strong&gt;事务ID列（6字节）&lt;strong&gt;和&lt;/strong&gt;回滚指针列（7字节）&lt;/strong&gt;。如果没有定义主键，还会增加一个&lt;strong&gt;rowid&lt;/strong&gt;列做为主键（6字节）。&lt;/p&gt;&#xA;&lt;h3 id=&#34;行溢出&#34;&gt;行溢出&lt;/h3&gt;&#xA;&lt;p&gt;行溢出概念：在Compact行格式中，当列长度（例如varchar、BLOB等）达到768 byte后，会将该列的前768byte当作prefix存放在行中，多出来的数据溢出存放到溢出页中，然后通过一个偏移量指针将两者关联起来。&lt;/p&gt;&#xA;&lt;p&gt;Dynamic和Compressed行格式不会存储prefix数据，直接全部溢出，只存储页地址。&lt;/p&gt;&#xA;&lt;h2 id=&#34;innodb数据页结构&#34;&gt;InnoDB数据页结构&lt;/h2&gt;&#xA;&lt;p&gt;InnoDB数据页由以下七个部分构成，如图所示：&#xA;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/mysql/table/IMG_0067.PNG&#34; alt=&#34;数据页结构&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;其中&lt;code&gt;File Header、Page Header、File Trailer&lt;/code&gt;的大小是固定的，这些空间是用来标记该页的一些信息，如Checksum，数据页所在的B+树索引的层数。&lt;/p&gt;&#xA;&lt;h3 id=&#34;file-header&#34;&gt;File Header&lt;/h3&gt;&#xA;&lt;p&gt;该部分用来记录各种页的通用信息，共由八个部分组成，占用38字节。&#xA;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/mysql/table/IMG_0068.PNG&#34; alt=&#34;File Header组成部分&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;page-header&#34;&gt;Page Header&lt;/h3&gt;&#xA;&lt;p&gt;该部分用来记录数据页的状态信息，由14个部分组成，占用56字节，如图所示：&#xA;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/mysql/table/IMG_0069.PNG&#34; alt=&#34;Page Header组成部分&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;infimun和supremum-records&#34;&gt;Infimun和Supremum Records&lt;/h3&gt;&#xA;&lt;p&gt;Infimun用来记录是比该页中任何主键值都要小的值，Supremum Records指比任何值都大的值。这两个值在页创建时被建立。&lt;/p&gt;&#xA;&lt;h3 id=&#34;user-record和free-space&#34;&gt;User Record和Free Space&lt;/h3&gt;&#xA;&lt;p&gt;User Record是实际存储行记录的内容。Free Space指的是空闲空间（暂未被使用的空间），是一个链表数据结构，在一条记录被删除后，该空间会被加入到空闲链表中。&lt;/p&gt;</description>
    </item>
    <item>
      <title>MySQL文件种类分析</title>
      <link>http://localhost:1313/posts/mysql/mysql-file/</link>
      <pubDate>Wed, 15 Apr 2020 18:48:38 +0000</pubDate>
      <guid>http://localhost:1313/posts/mysql/mysql-file/</guid>
      <description>&lt;h2 id=&#34;参数文件&#34;&gt;参数文件&lt;/h2&gt;&#xA;&lt;p&gt;当MySQL实例启动，数据库会先去读一个配置参数文件，用来寻找数据库的各种文件所在位置以及部分初始化参数。&lt;/p&gt;&#xA;&lt;p&gt;可以通过&lt;code&gt;SHOW VARIABLES&lt;/code&gt;查看数据库中所有参数，可以通过&lt;code&gt;LIKE&lt;/code&gt;过滤参数名。&lt;/p&gt;&#xA;&lt;h3 id=&#34;参数类型&#34;&gt;参数类型&lt;/h3&gt;&#xA;&lt;p&gt;MySQL中参数分为两类：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;动态参数&#xA;&lt;ul&gt;&#xA;&lt;li&gt;在MySQL实例运行中进行更改。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;静态参数&#xA;&lt;ul&gt;&#xA;&lt;li&gt;在实例的整个生命周期内都不得进行更改。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;可以通过set命令对动态参数进行修改，例如&lt;code&gt;SET read_buffer_size=524288&lt;/code&gt;。&#xA;对变量的修改，在这次的实例生命周期内有效，下次此洞MySQL实例还是会读取参数文件。&lt;/p&gt;&#xA;&lt;h2 id=&#34;日志&#34;&gt;日志&lt;/h2&gt;&#xA;&lt;h3 id=&#34;错误日志&#34;&gt;错误日志&lt;/h3&gt;&#xA;&lt;p&gt;错误日志对MySQL的启动、运行、关闭过程进行了记录，该文件不仅记录了所有的错误信息，也记录了一些警告信息或正确的信息。&lt;/p&gt;&#xA;&lt;p&gt;可以在配置文件中设置存储位置：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[mysqld]&#xA;log-error=[path/[filename]]&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;或通过查询变量来获取错误日志信息：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;SHOW&lt;/span&gt; VARIABLES &lt;span style=&#34;color:#66d9ef&#34;&gt;LIKE&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;log_err%&amp;#39;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-log&#34; data-lang=&#34;log&#34;&gt;2020-04-13T03:04:23.391925Z 75 [Note] Aborted connection 75 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:04:23.391954Z 76 [Note] Aborted connection 76 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:08:39.802373Z 77 [Note] Aborted connection 77 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:08:39.802390Z 82 [Note] Aborted connection 82 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:08:39.809111Z 79 [Note] Aborted connection 79 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:08:39.809298Z 81 [Note] Aborted connection 81 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:08:39.809495Z 80 [Note] Aborted connection 80 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:08:39.809647Z 83 [Note] Aborted connection 83 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:08:39.818503Z 84 [Note] Aborted connection 84 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:08:39.820436Z 85 [Note] Aborted connection 85 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:08:39.822052Z 86 [Note] Aborted connection 86 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:08:39.809996Z 78 [Note] Aborted connection 78 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:17:12.627802Z 87 [Note] Aborted connection 87 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:17:12.627848Z 88 [Note] Aborted connection 88 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:17:12.627864Z 89 [Note] Aborted connection 89 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:17:12.627891Z 90 [Note] Aborted connection 90 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:17:12.627917Z 91 [Note] Aborted connection 91 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:17:12.627949Z 92 [Note] Aborted connection 92 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:17:12.627994Z 93 [Note] Aborted connection 93 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:17:12.628018Z 94 [Note] Aborted connection 94 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:17:12.628034Z 95 [Note] Aborted connection 95 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T03:17:12.628055Z 96 [Note] Aborted connection 96 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T05:29:24.573237Z 34 [Note] Aborted connection 34 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T05:29:24.573406Z 35 [Note] Aborted connection 35 to db: &amp;#39;dev&amp;#39; user: &amp;#39;root&amp;#39; host: &amp;#39;localhost&amp;#39; (Got an error reading communication packets)&#xA;2020-04-13T09:49:37.346162Z 0 [Note] InnoDB: page_cleaner: 1000ms intended loop took 4528ms. The settings might not be optimal. (flushed=0 and evicted=0, during the time.)&#xA;2020-04-14T01:35:39.190069Z 0 [Note] InnoDB: page_cleaner: 1000ms intended loop took 43183898ms. The settings might not be optimal. (flushed=0 and evicted=0, during the time.)&#xA;2020-04-14T07:30:03.500507Z 0 [Note] InnoDB: page_cleaner: 1000ms intended loop took 9873804ms. The settings might not be optimal. (flushed=0 and evicted=0, during the time.)&#xA;2020-04-15T02:39:20.019686Z 0 [Note] InnoDB: page_cleaner: 1000ms intended loop took 46274005ms. The settings might not be optimal. (flushed=0 and evicted=0, during the time.)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;慢查询日志&#34;&gt;慢查询日志&lt;/h3&gt;&#xA;&lt;p&gt;慢查询日志可以帮助DBA定位存在查询较慢的SQL语句，从而实现SQL语句层面的优化。可以通过&lt;code&gt;long_query_time&lt;/code&gt;来设置慢查询阈值。默认值为10s.&#xA;默认情况下，MySQL不开启慢查询日志，需要手动将&lt;code&gt;log_slow_queries&lt;/code&gt;设置为ON。另一个和慢查询相关的参数&lt;code&gt;log_queries_not_using_indexes&lt;/code&gt;，这个参数如果是ON，就会将运行的SQL语句没有使用索引的，记录到慢查询日志中。&#xA;MySQL 5.6.5中新增一个参数&lt;code&gt;log_throttle_queries_not_using_indexes&lt;/code&gt;，用来表示每分钟允许记录到慢查询日志且未使用索引的SQL语句次数。默认为0，表示没有限制。&lt;/p&gt;</description>
    </item>
    <item>
      <title>AQS原理与源码分析</title>
      <link>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/aqs/</link>
      <pubDate>Mon, 13 Apr 2020 15:07:10 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/aqs/</guid>
      <description>&lt;h1 id=&#34;简介&#34;&gt;简介&lt;/h1&gt;&#xA;&lt;p&gt;队列同步器AbstractQueuedSynchronizer，是用来构建锁或者其他同步组键的基础框架，它使用了一个int成员变量&lt;strong&gt;state&lt;/strong&gt;表示同步状态，通过CLH队列完成获取资源的线程排队工作。&lt;/p&gt;&#xA;&lt;p&gt;AQS的主要使用方式是继承，字类通过继承同步器并实现它的抽象方法来管理同步状态。AQS本身只是定义若干同步状态获取和释放的方法提供给字类来实现。&lt;/p&gt;&#xA;&lt;p&gt;锁是面向使用者的，它定义了使用者与锁交互的接口，隐藏了实现细节。AQS是面向锁的实现者，它简化了锁的实现方式，屏蔽了同步状态管理，线程的排队，等待与唤醒等底层操作。&lt;/p&gt;&#xA;&lt;p&gt;AQS定义了两种资源共享的方式：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Exclusive（独占）：只有一个线程能执行，如ReentrantLock，其中又可分为公平锁和非公平锁：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;公平锁：线程按照队列的顺序获取锁&lt;/li&gt;&#xA;&lt;li&gt;非公平锁：线程无视顺序，去抢锁&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Share（共享）：多个线程可同时执行，如Semaphore/CountDownLatch。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;AQS的设计是基于模板方法模式的，使用者继承AbstractQueuedSynchronizer并重写指定方法，重写的方法是对同步状态&lt;code&gt;state&lt;/code&gt;的获取释放等操作。&lt;/p&gt;&#xA;&lt;p&gt;可重写方法如下，arg参数为获取锁的次数。&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th style=&#34;text-align: center&#34;&gt;名称&lt;/th&gt;&#xA;          &lt;th style=&#34;text-align: center&#34;&gt;描述&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;protected boolean tryAcquire(int arg)&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;独占方式，尝试获取同步状态，实现该方法需要查询当前状态并判断同步状态是否符合预期，然后通过CAS设置同步状态，成功返回true，失败返回false&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;protected boolean tryRelease(int arg)&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;独占方式，尝试释放同步状态，成功返回true，失败则返回false&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;protected int tryAcquireShared(int arg)&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;共享方式，尝试获取同步状态，返回0表示成功，但是没有剩余可用资源，负数表示失败，正数表示成功，并且有剩余资源。&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;protected boolean tryReleaseShared(int arg)&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;共享方式，尝试释放同步状态，成功返回true，失败返回false&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;protected boolean isHeldExclusively()&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;判断当前线程是否正在独占资源&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;模板方法：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th style=&#34;text-align: center&#34;&gt;方法名称&lt;/th&gt;&#xA;          &lt;th style=&#34;text-align: center&#34;&gt;描述&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;void acquire(int arg)&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;独占锁获取同步状态，如果当前线程获取同步状态成功，则由该方法返回，否则，将会进入同步队列等待，该方法会调用重写的tryAcquire()方法&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;void acquireInterruptibly(int arg)&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;与acquire相同，但是该方法响应中断，当前线程未获取到同步状态而进入同步队列，如果当前线程被中断，该方法会抛出&lt;code&gt;InterruptedException&lt;/code&gt;并返回。&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;boolean tryAcquireNanos(int arg, long nanosTimeout)&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;在acquireInterruptibly的基础上增加了超时限制，如果当前线程在超时时间之内没有获取同步状态，那么将会返回false，获取到了返回true&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;void acquireShared(int arg)&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;共享式的获取同步状态，如果当前线程未获取到同步状态，将会进入同步队列等待，与独占锁获取的主要区别式同一时刻可以有多个线程获取同步状态&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;void acquireSharedInterruptibly(int arg)&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;与acquireShared相同，响应中断&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;boolean tryAcquireSharedNanos(int arg, long nanosTimeout)&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;加了超时限制&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;boolean release(int arg)&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;独占式的释放同步状态，该方法会在释放同步状态之后，将同步队列中的第一个节点线程唤醒&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;boolean releaseShared(int arg)&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;共享式的释放同步状态&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;Collection&lt;Thread&gt; getQueuedThreads()&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;获取等待在同步队列上的线程集合&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;模板方法基本分成3类：独占式获取与释放，共享式获取与释放，查询同步队列中的情况。&lt;/p&gt;</description>
    </item>
    <item>
      <title>解析Java中的锁</title>
      <link>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/java-lock/</link>
      <pubDate>Fri, 10 Apr 2020 12:07:01 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/java-lock/</guid>
      <description>&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;&#xA;&lt;p&gt;锁是用来控制多个线程访问共享资源的方式，在Lock接口出现之前，Java是靠synchronized关键字实现锁功能的。而Java 1.5之后，并发包中新增了Lock接口与其实现类用来实现锁功能，只是需要手动获取释放锁，虽然它缺少了同步关键字隐式获取释放的便捷性，但却拥有了可操作性，可中断的获取锁以及超时获取锁等功能。&lt;/p&gt;&#xA;&lt;h2 id=&#34;分类&#34;&gt;分类&lt;/h2&gt;&#xA;&lt;p&gt;Java中会按照是否有某一特性来定义锁，下图通过各种特性对锁进行分类：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/concurrency/lock/Java%E7%9A%84%E9%94%81.png&#34; alt=&#34;Java中的锁&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;悲观锁--乐观锁&#34;&gt;悲观锁 / 乐观锁&lt;/h3&gt;&#xA;&lt;p&gt;这两种锁不是具体类型的锁，体现了看待线程同步的角度，再Java和数据库中都有此概念对应的实际应用。&lt;/p&gt;&#xA;&lt;p&gt;对于同一个数据的并发操作，悲观锁认为自己在使用数据的时候，一定有别的线程来修改数据，因此在获取数据的时候会先加锁，确保数据不会被别的线程修改，在Java中，synchronized关键字和Lock的实现类都是悲观锁。&lt;/p&gt;&#xA;&lt;p&gt;而乐观锁认为自己在使用数据的时候，不会有其他线程修改数据，所以不会添加锁，只是在更新数据的时候，去判断之前有没有别的线程更新了数据，如果没有被更新，当前线程将自己修改的数据成功写入。如果数据已被其他线程更新。则根据不同的实现方式执行不同的操作（报错或自动重试）。&lt;/p&gt;&#xA;&lt;p&gt;乐观锁在Java中是通过无锁编程来实现，最常采用是CAS算法，Java原子类中的递增就是通过CAS自旋来实现的。&lt;/p&gt;&#xA;&lt;p&gt;悲观锁适合写操作多的场景，先加锁可以保证数据准确性。&lt;/p&gt;&#xA;&lt;p&gt;乐观锁适合读操作多的场景，不加锁能够提高性能。&lt;/p&gt;&#xA;&lt;h3 id=&#34;自旋锁--适应性自旋锁&#34;&gt;自旋锁 / 适应性自旋锁&lt;/h3&gt;&#xA;&lt;p&gt;在Java中，自旋锁是指尝试获取锁的线程不会立即阻塞，而实采用循环的方式去获取锁，这样做的好处是减少线程上下文切换的消耗。&lt;/p&gt;&#xA;&lt;p&gt;但是自旋锁本身是有缺点的，它不能代替阻塞，自旋虽然避免了上下文切换的开销，但它要占用处理器时间，如果锁被占用的时间很短，自旋等待的效果很好，但是如果锁占用时间过长，自旋只会白白浪费处理器资源。所以自旋等待的时间必须要有一定的限度，如果自旋超过了限定次数（默认是10次，通过**-XX:PreBlockSpin**修改）没有成功获得锁，就挂起线程，停止自旋。&lt;/p&gt;&#xA;&lt;p&gt;自旋锁的实现原理是CAS算法。自旋锁在JDK 1.4.2引入，使用**-XX:UseSpinning**开启，JDK 6开始默认开启，并且引入了自适应的自旋锁。&lt;/p&gt;&#xA;&lt;p&gt;自适应意味着自旋的时间不再固定，而实由前一次在同一个锁上的自旋时间以及锁的拥有者的状态来决定。如果在同一个锁对象上，自旋等待刚刚成功获得过锁，并且持有锁的线程正在运行中，那么JVM会认为这次自选也是很有可能再次成功，进而它将自旋等待持续更长的时间。如果某个锁自旋很少成功获得，那么就会直接省略掉自旋过程，直接阻塞线程。&lt;/p&gt;&#xA;&lt;p&gt;在自旋锁中，有三种常见的锁形式：TicketLock、CLHlock、MCSlock&lt;/p&gt;&#xA;&lt;h3 id=&#34;无锁--偏向锁--轻量级锁--重量级锁&#34;&gt;无锁 / 偏向锁 / 轻量级锁 / 重量级锁&lt;/h3&gt;&#xA;&lt;p&gt;这四种指锁的状态，并且是针对&lt;code&gt;Synchronized&lt;/code&gt;关键字，是通过&lt;code&gt;Mark Word&lt;/code&gt;中的字段表明的。&lt;/p&gt;&#xA;&lt;h4 id=&#34;无锁&#34;&gt;无锁&lt;/h4&gt;&#xA;&lt;p&gt;无锁没有对资源进行锁定，所有线程都能访问并修改同一个资源，但同时只有一个线程能修改成功。&lt;/p&gt;&#xA;&lt;p&gt;无锁的特点是修改操作在循环内进行，线程会不断尝试修改共享资源。如果没有冲突就修改成功并退出，否则就会继续循环尝试。CAS原理就是无锁的实现。&lt;/p&gt;&#xA;&lt;h4 id=&#34;偏向锁&#34;&gt;偏向锁&lt;/h4&gt;&#xA;&lt;p&gt;偏向锁是指一段同步代码一直被一个线程所访问，那么该线程就会自动获得锁，降低获得锁的代价。&lt;/p&gt;&#xA;&lt;p&gt;当一个线程通过同步代码块获得锁的时候，会在&lt;code&gt;Mark Word&lt;/code&gt;中存储锁偏向的线程ID。在线程进入或退出同步代码块时不再通过CAS操作来加锁解锁，而是检查&lt;code&gt;Mark Word&lt;/code&gt;中是否存储着指向当前线程的偏向锁，引入偏向锁是为了在无多线程竞争的情况下尽量减少不必要的轻量级锁的执行，因为轻量级锁较偏向锁消耗性能。&lt;/p&gt;&#xA;&lt;p&gt;偏向锁只有遇到其他线程竞争偏向锁时，持有偏向锁的线程才会释放偏向锁，线程不会主动释放偏向锁。&lt;/p&gt;&#xA;&lt;p&gt;偏向锁在JDK 6以后是默认启用的，可以通过&lt;code&gt;-XX:UseBiasedLocking=false&lt;/code&gt;关闭，关闭之后，程序默认进入轻量级锁状态。&lt;/p&gt;&#xA;&lt;h4 id=&#34;轻量级锁&#34;&gt;轻量级锁&lt;/h4&gt;&#xA;&lt;p&gt;轻量级锁是指当锁是偏向锁的时候，被另一个线程访问，偏向锁就会升级为轻量级锁，其他线程通过自旋的方式尝试获取锁，不会阻塞。从而提高性能。&lt;/p&gt;&#xA;&lt;h4 id=&#34;重量级锁&#34;&gt;重量级锁&lt;/h4&gt;&#xA;&lt;p&gt;若当前只有一个等待线程，则该线程通过自旋进行等待，但是当自旋超过一定次数，或是一个线程在持有锁，一个在自旋，又有第三个线程访问时，轻量级锁升级为重量级锁。&lt;/p&gt;&#xA;&lt;p&gt;综上，偏向锁通过对比&lt;code&gt;Mark Word&lt;/code&gt;解决加锁问题，避免执行CAS操作，而轻量级锁通过CAS操作和自旋来解决加锁问题，避免线程阻塞和唤醒影响性能。重量级锁将除了拥有锁的线程以外所有线程都阻塞。&lt;/p&gt;&#xA;&lt;h3 id=&#34;公平锁--非公平锁&#34;&gt;公平锁 / 非公平锁&lt;/h3&gt;&#xA;&lt;p&gt;公平锁是指多个线程按照申请锁的顺序来获取锁，线程直接进入队列进行排序，队列中第一个线程才能获得锁。&lt;/p&gt;&#xA;&lt;p&gt;公平锁的优点时等待的线程不会饿死，缺点是整体吞吐效率相对非公平锁较低，等待队列中除第一个线程以外所有线程都阻塞，CPU唤醒阻塞线程的开销较非公平锁大。&lt;/p&gt;&#xA;&lt;p&gt;非公平锁是多个线程加锁时直接尝试获得锁，获得不到才会进入等待队列中等待。如果此时锁刚好可用，那么线程可以无需阻塞直接获取到锁。非公平锁的优点是可以减少唤醒线程的开销，整体吞吐效率高，因为线程有几率不阻塞直接获得锁，缺点是处于等待队列的线程可能会饿死，或者等待很久才能获得锁。&lt;/p&gt;&#xA;&lt;h3 id=&#34;可重入锁&#34;&gt;可重入锁&lt;/h3&gt;&#xA;&lt;p&gt;可重入锁又称为递归锁，是指同一个线程在外层方法获取锁的时候，在进入内层方法会自当获得锁（前提是锁对象是同一个对象），不会因为之前获取过还没释放而阻塞，Java中&lt;code&gt;ReentrantLock&lt;/code&gt;和&lt;code&gt;Synchronized&lt;/code&gt;都是可重入锁，可重入锁的一个优点就是可一定程度避免死锁。&lt;/p&gt;&#xA;&lt;p&gt;下面是一个可重入锁的一个案例。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;synchronized&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setA&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; Exception{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;Thread.&lt;span style=&#34;color:#a6e22e&#34;&gt;sleep&lt;/span&gt;(1000);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;setB();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;synchronized&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setB&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;throws&lt;/span&gt; Exception{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;Thread.&lt;span style=&#34;color:#a6e22e&#34;&gt;sleep&lt;/span&gt;(1000);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;独享锁--共享锁&#34;&gt;独享锁 / 共享锁&lt;/h4&gt;&#xA;&lt;p&gt;独享锁也叫排他锁，是指该锁一次只能被一个线程所持有，如果线程T对数据A加上独享锁之后，则其他线程不再对A加任何类型的锁，获得独享锁的数据即能读数据又能修改数据。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Java内存模型解析</title>
      <link>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/java%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B%E8%A7%A3%E6%9E%90/</link>
      <pubDate>Thu, 09 Apr 2020 13:16:52 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/java%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B%E8%A7%A3%E6%9E%90/</guid>
      <description>&lt;h2 id=&#34;定义&#34;&gt;定义&lt;/h2&gt;&#xA;&lt;p&gt;并发编程中，需要处理两个关键问题：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;线程之间如何通信&lt;/li&gt;&#xA;&lt;li&gt;线程之间如何同步&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;通信指线程之间以何种机制来交换信息，线程之间的通信机制有两种：&lt;strong&gt;共享内存&lt;/strong&gt;和&lt;strong&gt;消息传递&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;同步指程序中用于控制不同线程间操作发生相对顺序的机制。&lt;/p&gt;&#xA;&lt;p&gt;Java采用的是共享内存模型，Java线程之间的通信由Java内存模型（JMM）控制。Java内存模型的主要目的是定义程序中各种变量的访问规则。&lt;/p&gt;&#xA;&lt;h2 id=&#34;主内存和本地内存&#34;&gt;主内存和本地内存&lt;/h2&gt;&#xA;&lt;p&gt;JMM规定了线程之间共享变量存储在主内存中，每个线程都有私有的本地内存，本地内存存储了共享变量的副本，Java内存模型的示意图如图所示：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/concurrency/JMM/IMG_0043.PNG&#34; alt=&#34;Java内存模型抽象结构&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;从图来看，线程A和线程B之间要通信的话，会进行以下操作：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;线程A把本地内存中更新过的共享变量刷新到主内存中。&lt;/li&gt;&#xA;&lt;li&gt;线程B去主内存中读取线程A之前更新的变量。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;内存间的交互操作&#34;&gt;内存间的交互操作&lt;/h3&gt;&#xA;&lt;p&gt;关于如何将一个变量从主内存拷贝到本地内存中，JMM定义了以下八种操作来完成，JVM必须保证每种操作是原子性的。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;lock：作用于主内存的变量，将一个变量标识为一个线程独占状态。&lt;/li&gt;&#xA;&lt;li&gt;unlock：作用于主内存的变量，将处于线程独占状态的变量释放出来。&lt;/li&gt;&#xA;&lt;li&gt;read：作用于主内存的变量，将一个变量的值从主内存传输到线程的本地内存中。&lt;/li&gt;&#xA;&lt;li&gt;load：作用于本地内存的变量，将read操作得到的变量放入本地内存的变量副本中。&lt;/li&gt;&#xA;&lt;li&gt;use：作用于本地内存的变量，将本地内存的一个变量值传递给执行引擎。&lt;/li&gt;&#xA;&lt;li&gt;assign：作用于本地内存的变量，它把一个从执行引擎接收到的值赋值给本地内存中的变量。&lt;/li&gt;&#xA;&lt;li&gt;store：作用于本地内存的变量，将本地内存的值传送到主内存中&lt;/li&gt;&#xA;&lt;li&gt;write：作用于主内存的变量，将store操作得到的变量值放入主内存的变量中。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;重排序&#34;&gt;重排序&lt;/h2&gt;&#xA;&lt;p&gt;重排序时指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段，重排序分为三种类型：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;编译器优化的重排序&lt;/li&gt;&#xA;&lt;li&gt;指令并行的重排序，处理器使用指令级并行技术来将多条指令重叠执行。&lt;/li&gt;&#xA;&lt;li&gt;内存系统的重排序，由于处理器使用了缓存技术和读/写缓冲区技术。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;重排序会导致多线程程序出现内存可见性问题，对于编译器，JMM的编译器重排序规则会禁止特定类型的编译器重排序。对于处理器，JMM要求编译器生成指令序列的时候，插入内存屏障指令来禁止重排序。&lt;/p&gt;&#xA;&lt;h3 id=&#34;数据依赖性&#34;&gt;数据依赖性&lt;/h3&gt;&#xA;&lt;p&gt;如果两个操作访问同一个变量，且两个操作中有一个为写操作，此时这两个操作之间就存在数据依赖性。数据依赖性分三种类型，如下表所示：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th style=&#34;text-align: center&#34;&gt;名称&lt;/th&gt;&#xA;          &lt;th style=&#34;text-align: center&#34;&gt;代码实例&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;写后读&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;a = 1; b = a;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;写后写&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;a = 1; a = 2;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;读后写&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;a = b; b = 1;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;上述现象如果执行顺序发生改变，执行结果就会被改变。&lt;/p&gt;&#xA;&lt;p&gt;编译器和处理器在重排序时，会遵守数据依赖性原则，不会改变存在依赖关系的两个操作的执行顺序。&lt;/p&gt;&#xA;&lt;h2 id=&#34;happens-before&#34;&gt;Happens-Before&lt;/h2&gt;&#xA;&lt;p&gt;JSR-133使用&lt;code&gt;Happens-Before&lt;/code&gt;的概念来阐述操作之间的内存可见性。在JMM中，如果一个操作执行的结果需要对另一个操作可见，那么这两个操作之间必须存在&lt;code&gt;Happens-Before&lt;/code&gt;关系。A &lt;code&gt;Happens-Before&lt;/code&gt; B 意味着：&lt;strong&gt;A操作的结果对B是可见的&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;通俗而言，即：A运行完成后数据结果，B都能读取到。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;Happens-Before&lt;/code&gt;原则如下：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;程序顺序规则：在一个线程内，在程序前面的操作先行发生于后面的操作。&lt;/li&gt;&#xA;&lt;li&gt;管程锁规则：一个&lt;code&gt;unlock&lt;/code&gt;操作先行发生于后面对同一个锁的&lt;code&gt;lock&lt;/code&gt;操作。&lt;/li&gt;&#xA;&lt;li&gt;volatile变量规则：对一个volatile变量的写，先行发生于任意后续对这个volatile变量的读。&lt;/li&gt;&#xA;&lt;li&gt;传递性&lt;/li&gt;&#xA;&lt;li&gt;线程&lt;code&gt;start()&lt;/code&gt;规则：&lt;code&gt;start()&lt;/code&gt;方法调用先行发生于此线程的每一个动作。&lt;/li&gt;&#xA;&lt;li&gt;线程&lt;code&gt;join()&lt;/code&gt;规则：线程的结束先行发生于&lt;code&gt;join()&lt;/code&gt;方法返回。&lt;/li&gt;&#xA;&lt;li&gt;线程&lt;code&gt;interrupt()&lt;/code&gt;规则：对线程的&lt;code&gt;interrupt()&lt;/code&gt;方法的调用先行发生于被中断线程代码检测到中断事件的发生&lt;/li&gt;&#xA;&lt;li&gt;对象终结规则：一个对象的初始化完成先行发生于它的&lt;code&gt;finalize()&lt;/code&gt;方法的开始。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;线程安全&#34;&gt;线程安全&lt;/h2&gt;&#xA;&lt;p&gt;共享资源的安全程度按照强弱顺序分为以下五类：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Java并发机制底层实现原理</title>
      <link>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/java-concurrency-implementation-principle/</link>
      <pubDate>Tue, 07 Apr 2020 17:09:22 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/java-concurrency-implementation-principle/</guid>
      <description>&lt;h2 id=&#34;volatile&#34;&gt;Volatile&lt;/h2&gt;&#xA;&lt;h3 id=&#34;定义&#34;&gt;定义&lt;/h3&gt;&#xA;&lt;p&gt;Java语言规范第3版中对volatile的定义如下：Java编程语言允许线程访问共享变量，为了能确保共享变量能被准确和一致的更新，线程应该确保通过排他锁单独获取这个变量。Java语言提供了volatile关键字，在某些情况下比锁要更加方便，如果一个变量被声明成volatile，Java线程内存模型确保所有线程看到的这个变量的值是一致的。&lt;/p&gt;&#xA;&lt;h4 id=&#34;实现原理&#34;&gt;实现原理&lt;/h4&gt;&#xA;&lt;p&gt;先看下面的CPU术语定义：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th style=&#34;text-align: center&#34;&gt;术语&lt;/th&gt;&#xA;          &lt;th style=&#34;text-align: center&#34;&gt;描述&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;内存屏障&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;是一组处理器指令，用于实现对内存操作的顺序限制&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;缓冲行&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;缓存这两个可以分配的最小存储单位，处理器填写缓存线时会加载整个缓存线，需要使用多个主内存读周期&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;原子操作&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;不可中断的一个或一系列操作&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;缓存行填充&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;当处理器识别到内存中读取操作数是可缓存的，处理器读取整个缓存行到合适的缓存&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;缓存命中&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;如果进行高速缓存行填充操作的内存位置仍然是下次处理器访问的地址时，处理器从缓存中读取操作数，而不是从内存读取&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;写命中&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;当处理器将操作数写回到一个内存缓存中的区域中，它首先会检查这个缓存的内存地址是否在缓存行中，如果存在一个有效的缓存行，则处理器将这个操作数回写到缓存，而不是回写到内存，这个操作数被称为写命中&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;写缺失&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;一个有效的缓存行被写入到不存在的内存区域&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @author ：L1nker4&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @date ： 创建于  2020/4/7 20:34&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * @description： volatile测试&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Demo01&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;volatile&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; stop &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;(String&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; args) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        stop &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; b &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; stop;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过添加VM options打印程序汇编代码：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;-XX:+UnlockDiagnosticVMOptions -XX:+LogCompilation -XX:+PrintAssembly -Xcomp -XX:CompileCommand=dontinline,*Demo01.main -XX:CompileCommand=compileonly,*Demo01.main&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果提示以下内容，需要将&lt;code&gt;hedis-amd64.dll&lt;/code&gt;放在&lt;code&gt;jre/bin/server&lt;/code&gt;目录下。&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Java HotSpot(TM) 64-Bit Server VM warning: PrintAssembly is enabled; turning on DebugNonSafepoints to gain additional output&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;截取部分的汇编代码&lt;/p&gt;</description>
    </item>
    <item>
      <title>Spring Cloud Alibaba Nacos</title>
      <link>http://localhost:1313/posts/spring-cloud/spring-cloud-alibaba-nacos/</link>
      <pubDate>Mon, 06 Apr 2020 14:19:33 +0000</pubDate>
      <guid>http://localhost:1313/posts/spring-cloud/spring-cloud-alibaba-nacos/</guid>
      <description>&lt;h2 id=&#34;什么是nacos&#34;&gt;什么是Nacos&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集，帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。&#xA;Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;Nacos的关键特性包括：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;服务发现和服务健康监测&lt;/li&gt;&#xA;&lt;li&gt;动态配置服务&lt;/li&gt;&#xA;&lt;li&gt;动态 DNS 服务&lt;/li&gt;&#xA;&lt;li&gt;服务及其元数据管理&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;nacos架构&#34;&gt;Nacos架构&lt;/h2&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/spring-cloud/nacos/nacos1.jpeg&#34; alt=&#34;Nacos架构&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;其中Nacos整体分为两大块，分别是&lt;code&gt;Nacos Server&lt;/code&gt;和&lt;code&gt;Nacos Console&lt;/code&gt;，&lt;code&gt;Nacos Server&lt;/code&gt;为核心，其中包括&lt;code&gt;Naming Service&lt;/code&gt;，&lt;code&gt;Config Service&lt;/code&gt;，&lt;code&gt;Naming Service&lt;/code&gt;主要提供服务发现和DNS功能，&lt;code&gt;Config Service&lt;/code&gt;相当于Netflix时期的Spring Cloud Config提供的分布式配置中心的功能，使得配置信息在线读取。&lt;/p&gt;&#xA;&lt;h2 id=&#34;nacos安装&#34;&gt;Nacos安装&lt;/h2&gt;&#xA;&lt;p&gt;这里笔者使用Docker方式安装，具体安装流程可以参照如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;git clone https://github.com/nacos-group/nacos-docker.git&#xA;cd nacos-docker/example&#xA;docker-compose -f standalone-mysql-5.7.yaml up -d&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Nacos 控制台：http://192.168.252.128:8848/nacos&lt;/p&gt;&#xA;&lt;h2 id=&#34;服务注册功能案例&#34;&gt;服务注册功能案例&lt;/h2&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;引入Nacos Discovery Starter依赖&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.alibaba.cloud&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-alibaba-nacos-discovery&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.2.0.RELEASE&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;2&#34;&gt;&#xA;&lt;li&gt;配置Nacos Server地址与其他信息&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;spring.application.name=service-provider&#xA;server.port=8081&#xA;spring.cloud.nacos.discovery.server-addr=192.168.252.128:8848&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ol start=&#34;3&#34;&gt;&#xA;&lt;li&gt;使用 @EnableDiscoveryClient 注解开启服务注册与发现功能&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@SpringBootApplication&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@EnableDiscoveryClient&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SpringCloudAlibabaNacosExampleApplication&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;(String&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; args) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        SpringApplication.&lt;span style=&#34;color:#a6e22e&#34;&gt;run&lt;/span&gt;(SpringCloudAlibabaNacosExampleApplication.&lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;, args);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;启动应用后，通过Nacos控制台可以看到服务已注册。&#xA;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/spring-cloud/nacos/nacos-register.png&#34; alt=&#34;Nacos控制台服务注册情况&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Java线程基础知识</title>
      <link>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/java%E7%BA%BF%E7%A8%8B%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/</link>
      <pubDate>Fri, 03 Apr 2020 20:27:03 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%B9%B6%E5%8F%91/java%E7%BA%BF%E7%A8%8B%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/</guid>
      <description>&lt;h2 id=&#34;进程与线程&#34;&gt;进程与线程&lt;/h2&gt;&#xA;&lt;h3 id=&#34;什么是进程&#34;&gt;什么是进程&lt;/h3&gt;&#xA;&lt;p&gt;操作系统在运行一个程序时，会为其创建一个进程，操作系统调度的最小单元是线程，也叫轻量级进程，在一个进程里可以创建多个线程，多个线程共享进程的堆和方法区两块内存空间。&lt;/p&gt;&#xA;&lt;h4 id=&#34;进程和线程的区别&#34;&gt;进程和线程的区别&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;进程是操作系统进行资源分配的基本单位，而线程是操作系统进行调度的基本单位。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;进程单独占有一定的内存地址空间，所以进程间存在内存隔离，数据是分开的，数据共享复杂但是同步简单，各个进程之间互不干扰；而线程共享所属进程占有的内存地址空间和资源，数据共享简单，但是同步复杂。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;进程单独占有一定的内存地址空间，一个进程出现问题不会影响其他进程，不影响主程序的稳定性，可靠性高；一个线程崩溃可能影响整个程序的稳定性，可靠性较低。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;进程单独占有一定的内存地址空间，进程的创建和销毁不仅需要保存寄存器和栈信息，还需要资源的分配回收以及页调度，开销较大；线程只需要保存寄存器和栈信息，开销较小。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;上下文切换&#34;&gt;上下文切换&lt;/h4&gt;&#xA;&lt;p&gt;上下文切换是指CPU从一个进程（线程）切换到另一个进程（线程）。&lt;strong&gt;上下文是指某一个时间点CPU寄存器和PC的数据&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;h3 id=&#34;并发和并行&#34;&gt;并发和并行&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;并发：同一时刻有多个任务在运行。&lt;/li&gt;&#xA;&lt;li&gt;并行：同一时间有多个任务在运行。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;线程的创建&#34;&gt;线程的创建&lt;/h3&gt;&#xA;&lt;p&gt;线程创建方式争议较多，在Oracle官方文档给出的创建方式为两种，分别是继承Thread类和实现Runnable接口。&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;There are two ways to create a new thread of execution. One is to declare a class to be a subclass of &lt;code&gt;Thread&lt;/code&gt;. This subclass should override the &lt;code&gt;run&lt;/code&gt; method of class &lt;code&gt;Thread&lt;/code&gt;. An instance of the subclass can then be allocated and started.&lt;/p&gt;&#xA;&lt;p&gt;The other way to create a thread is to declare a class that implements the &lt;code&gt;Runnable&lt;/code&gt; interface. That class then implements the &lt;code&gt;run&lt;/code&gt; method. An instance of the class can then be allocated, passed as an argument when creating &lt;code&gt;Thread&lt;/code&gt;, and started.&lt;/p&gt;</description>
    </item>
    <item>
      <title>JVM之字节码执行引擎（九）</title>
      <link>http://localhost:1313/posts/jvm/jvm09-bytecode-engine/</link>
      <pubDate>Fri, 03 Apr 2020 19:56:23 +0000</pubDate>
      <guid>http://localhost:1313/posts/jvm/jvm09-bytecode-engine/</guid>
      <description>&lt;h2 id=&#34;字节码执行引擎&#34;&gt;字节码执行引擎&lt;/h2&gt;&#xA;&lt;p&gt;执行引擎是JVM核心的组成部分之一，虚拟机是一个相对于物理机的概念，物理机的执行引擎是直接建立在存储器、缓存、指令集和操作系统上的，而虚拟机的执行引擎完全由软件自行实现。因此可以不受物理条件制约地定制指令集与执行引擎地结构体系。&lt;/p&gt;&#xA;&lt;p&gt;执行引擎在执行字节码地时候，通常会有解释执行和编译执行两种选择。&lt;/p&gt;&#xA;&lt;h2 id=&#34;运行时栈帧结构&#34;&gt;运行时栈帧结构&lt;/h2&gt;&#xA;&lt;p&gt;JVM以方法为最基本地执行单元，栈帧是用于支持JVM进行方法调用和方法执行背后地数据结构，它是JVM运行时数据区中虚拟机栈地栈元素，每一个方法从调用开始至执行结束的过程，都对应着一个栈帧在虚拟机栈里面的入栈到出栈的过程。&lt;/p&gt;&#xA;&lt;p&gt;对于执行引擎来说，在活动线程中，只有位于栈顶的方法才是在运行的，只有位于栈顶的栈帧才是在运行的，被称为&lt;strong&gt;当前栈帧&lt;/strong&gt;，与这个栈帧相关联的方法被称为&lt;strong&gt;当前方法&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;h3 id=&#34;局部变量表&#34;&gt;局部变量表&lt;/h3&gt;&#xA;&lt;p&gt;局部变量表是一组变量值的存储空间，用于存放方法参数和方法内部定义的局部变量。局部变量表的容量以变量槽为最小单位。&lt;/p&gt;&#xA;&lt;p&gt;当一个方法被调用时，JVM会使用局部变量表完成参数值到参数变量列表的传递过程，即实参到形参的传递。如果执行的是实例方法（没有被static修饰的方法），那局部变量表中第0位索引的变量槽默认是用于传递方法所属对象实例的引用，在方法中可以通过&lt;strong&gt;this&lt;/strong&gt;来访问到这个参数，其余参数按照参数表顺序排列，占用从1开始的局部变量槽。&lt;/p&gt;&#xA;&lt;h3 id=&#34;操作数栈&#34;&gt;操作数栈&lt;/h3&gt;&#xA;&lt;p&gt;操作数栈也被称为操作栈，它是一个后入先出栈，操作数栈的最大深度在编译时写入到Code属性的max_stacks数据项之中，操作数栈的每一个元素都可以是包括long和double在内的任何Java数据类型，32位数据类型所占的栈容量为1，64位数据类型栈容量为2.&lt;/p&gt;&#xA;&lt;p&gt;当一个方法刚刚开始执行时，这个方法的操作数栈是空的，在方法的执行过程中，会有各种字节码指令往操作数栈中写入和提取内容，也就是出栈和入栈操作。&lt;/p&gt;&#xA;&lt;p&gt;操作数栈中的数据类型必须与字节码指令的序列严格匹配，在编译程序代码时，编译器需要严格保证这一点，在类校验阶段的数据流分析中还要再次验证这一点。&lt;/p&gt;&#xA;&lt;p&gt;在概念模型中，两个不同栈帧作为不同方法的虚拟机栈的元素，是完全相互独立的。但在大多数JVM实现里会进行一些优化操作，令两个栈帧出现一部分重叠，让下面栈帧的部分操作数栈与上面栈帧的部分局部变量表重叠在一起。不仅可以节约空间，更重要的是在方法调用时可以直接共用一部分数据，无需进行额外的参数复制传递了。&lt;/p&gt;&#xA;&lt;h3 id=&#34;方法返回地址&#34;&gt;方法返回地址&lt;/h3&gt;&#xA;&lt;p&gt;当一个方法开始执行后，只有两种方式退出这个方法，第一种方式是执行引擎遇到任意一个方法返回的字节码指令，这时可能会有返回值传递给上层的方法调用者，方法是否有返回之以及返回值的类型将根据遇到何种方法返回指令来决定，这种退出方法的方式称为&lt;strong&gt;正常调用完成&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;另一种方式是在方法执行的过程中遇到了异常，并且这个异常没有在方法体内得到妥善处理。无论是JVM内部异常，还是代码中使用了&lt;code&gt;athrow&lt;/code&gt;指令产生的异常，只要在笨方法的异常表中没有搜索到匹配的异常处理器，就会导致方法退出，这种退出方法的方式称为&lt;strong&gt;异常调用完成&lt;/strong&gt;，异常调用完成的方式退出，不会给它的调用者提供任何返回值。&lt;/p&gt;&#xA;&lt;p&gt;方法退出的过程实际上等同于当前栈帧出栈，因此退出时可能执行饿操作有：恢复上层方法的局部变量表和操作数栈，把返回值压入调用者栈帧的操作数栈，调整PC计数器的值以指向方法调用指令后面的一条指令等。&lt;/p&gt;&#xA;&lt;h2 id=&#34;方法调用&#34;&gt;方法调用&lt;/h2&gt;&#xA;&lt;p&gt;一切方法调用在Class文件里面存储的都只是符号引用，而不是方法在实际运行时内存布局中的入口地址。&lt;/p&gt;&#xA;&lt;h3 id=&#34;解析&#34;&gt;解析&lt;/h3&gt;&#xA;&lt;p&gt;在类加载的解析阶段，会将其中的一部分符号引用转换成直接引用，这种解析能成立的前提是：方法在程序运行之前就有一个可确定的调用版本，并且方法的调用版本在运行期不可改变的。&lt;/p&gt;&#xA;&lt;p&gt;在Java语言中符合“编译期可知，运行期不可知”的方法，主要有静态方法和私有方法两大类，前者与类型直接关联，后者在外部不可被访问。这两种方法各自的特点决定了都不可能通过继承或别的方式重写出其他版本，因此都适合在类加载阶段进行解析。&lt;/p&gt;&#xA;&lt;p&gt;调用不同种类的方法有不同的字节码指令，分别是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;invokestatic：调用静态方法&lt;/li&gt;&#xA;&lt;li&gt;invokespecial：用于调用实例构造器&lt;init&gt;()方法、私有方法和父类中的方法&lt;/li&gt;&#xA;&lt;li&gt;invokevirtual：用于调用所有的虚方法&lt;/li&gt;&#xA;&lt;li&gt;invokeinterface：用于调用接口方法，会在运行时再确定一个实现该接口的对象&lt;/li&gt;&#xA;&lt;li&gt;invokedynamic：先在运行时动态解析出调用点限定符所引用的方法，然后执行该方法&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;只要能被invokestatic和invokespecial指令调用的方法，都可以在解析阶段中确定唯一的调用版本，Java语言中符合这个条件的有静态方法、私有方法、实例构造器、父类方法，被final修饰的方法，这五种方法调用会在类加载的时候就可以把符号引用解析为该方法的直接引用。这些方法统称为&lt;strong&gt;非虚方法&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;h3 id=&#34;分派&#34;&gt;分派&lt;/h3&gt;&#xA;&lt;p&gt;另一种主要的方法调用形式：分派调用则复杂许多，他可能是静态的，可能是动态的，按照分派依据的宗量数可分为单分派和多分派，这两种分派方式两两组合可以得到四种分派组合情况。&lt;/p&gt;&#xA;&lt;h4 id=&#34;静态分派&#34;&gt;静态分派&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;StaticDispatch&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Human&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Man&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; Human{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Woman&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; Human{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sayHello&lt;/span&gt;(Human guy){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hello,guy!&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sayHello&lt;/span&gt;(Man guy){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hello,gentlemen!&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sayHello&lt;/span&gt;(Woman guy){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hello,lady!&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;(String&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; args) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;Human man&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Man();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;Human woman&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Woman();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;sayHello(man);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;sayHello(woman);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行结果为：&lt;/p&gt;</description>
    </item>
    <item>
      <title>JVM之类加载机制（八）</title>
      <link>http://localhost:1313/posts/jvm/jvm08-class-load/</link>
      <pubDate>Sat, 28 Mar 2020 19:51:37 +0000</pubDate>
      <guid>http://localhost:1313/posts/jvm/jvm08-class-load/</guid>
      <description>&lt;h2 id=&#34;类加载机制&#34;&gt;类加载机制&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;JVM把Class描述类的数据从Class文件加载到内存，并对数据进行校验，转换解析和初始化，最终形成可以被虚拟机直接使用的Java类型，这个过程被称为类加载机制。&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;h3 id=&#34;类加载的时机&#34;&gt;类加载的时机&lt;/h3&gt;&#xA;&lt;p&gt;类加载机制的整个生命周期将经历：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;加载&lt;/li&gt;&#xA;&lt;li&gt;验证&lt;/li&gt;&#xA;&lt;li&gt;准备&lt;/li&gt;&#xA;&lt;li&gt;解析&lt;/li&gt;&#xA;&lt;li&gt;初始化&lt;/li&gt;&#xA;&lt;li&gt;使用&lt;/li&gt;&#xA;&lt;li&gt;卸载&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;其中验证，准备，解析三部分统称为连接。&#xA;加载，验证，准备，初始化，卸载这五个阶段的顺序是确定的，而解析阶段则不一定，他在某些情况下可以在初始化阶段之后再开始，这是为了支持Java语言的运行时绑定特性（也称为动态绑定或者晚期绑定）。&lt;/p&gt;&#xA;&lt;p&gt;关于在什么情况下进行类加载的第一个过程，JVM规范并没有强制约束，这点交给虚拟机的具体实现来自由把握，但是对于初始化阶段，JVM严格规定了有且仅有六种情况必须立即对类进行初始化（加载验证准备自然在此之前）：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;遇到new，getstatic，putstatic或invokestatic四条字节码指令时，如果类型没有进行初始化，则需要先出发其初始化阶段，主要场景有：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;使用new关键字实例化对象的时候&lt;/li&gt;&#xA;&lt;li&gt;读取或设置一个类型的静态字段（被final修饰，已在编译期把结果放入常量池的静态字段除外）&lt;/li&gt;&#xA;&lt;li&gt;调用一个类型的静态方法的时候&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;使用&lt;code&gt;java.lang.reflect&lt;/code&gt;包的方法对类型进行反射调用的时候，如果类型没有进行过初始化，则需要触发初始化&lt;/li&gt;&#xA;&lt;li&gt;当初始化类的时候，如果发现其父类没有进行初始化，则需要先对父类进行初始化&lt;/li&gt;&#xA;&lt;li&gt;当虚拟机启动时，用户需要指定一个要执行的主类，虚拟机会先初始化这个主类&lt;/li&gt;&#xA;&lt;li&gt;当使用JDK 7新加入的动态语言支持时，如果使用一个&lt;code&gt;java.lang.invoke.MethodHandle&lt;/code&gt;实例最后的解析结果为REF_getStatic、REF_putStatic、REF_invokeStatic 的方法句柄，并且这个方法句柄所对应的类还没初始化，则需要先触发其初始化。&lt;/li&gt;&#xA;&lt;li&gt;当一个接口定义了JDK 8新加入的默认方法（被default关键字修饰的接口方法）时，如果有这个接口的实现类发生了初始化，那么该接口要在其之前被初始化&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这六种场景中的行为被称为&lt;strong&gt;对一个类型的主动引用&lt;/strong&gt;，除此之外，所有引用类型的方式不会触发初始化，称为&lt;strong&gt;被动引用&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;h4 id=&#34;被动引用的demo&#34;&gt;被动引用的Demo&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;/**&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * 被动引用 Demo1:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; * 通过子类引用父类的静态字段，不会导致子类初始化。&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt; */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SuperClass&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SuperClass init!&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; value &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 123;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SubClass&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; SuperClass {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SubClass init!&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;NotInitialization&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;(String&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; args) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        System.&lt;span style=&#34;color:#a6e22e&#34;&gt;out&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;println&lt;/span&gt;(SubClass.&lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// SuperClass init!&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对于静态字段，只有直接定义这个字段的类才会被初始化，因此通过其子类来引用父类中定义的静态字段，只会触发父类的初始化而不会触发子类的初始化。&lt;/p&gt;</description>
    </item>
    <item>
      <title>JVM之字节码指令（七）</title>
      <link>http://localhost:1313/posts/jvm/jvm07-bytecode/</link>
      <pubDate>Fri, 27 Mar 2020 13:32:16 +0000</pubDate>
      <guid>http://localhost:1313/posts/jvm/jvm07-bytecode/</guid>
      <description>&lt;h2 id=&#34;字节码指令&#34;&gt;字节码指令&lt;/h2&gt;&#xA;&lt;p&gt;Java虚拟机的指令是由一个字节长度的，代表某种特定操作含义的数字（称为操作码，Opcode），以及跟随其后的零至多个代表此操作的参数，称为操作数（Operand）构成。由于Java虚拟机面向操作数栈而不是寄存器的架构，所以大多数指令都不包含操作数，只有一个操作码。指令参数存放在操作数栈中。&lt;/p&gt;&#xA;&lt;p&gt;由于Java虚拟机操作码的长度为一个字节（0-255），这意味着指令集的操作码总数不能超过256条。&lt;/p&gt;&#xA;&lt;h3 id=&#34;加载和存储指令&#34;&gt;加载和存储指令&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;将一个局部变量加载到操作数栈：iload、iload_&lt;n&gt;、lload、lload_&lt;n&gt;、fload、fload_&lt;n&gt;、dload、dload_&lt;n&gt;、aload、aload_&lt;n&gt;&lt;/li&gt;&#xA;&lt;li&gt;将一个数值从操作数栈存储到局部变量表：istore、istore_&lt;n&gt;、lstore、lstore_&lt;n&gt;、fstore、fstore_&lt;n&gt;、dstore、dstore_&lt;n&gt;、astore、astore_&lt;n&gt;&lt;/li&gt;&#xA;&lt;li&gt;将一个常量加载到操作数栈：bipush、sipush、ldc、ldc_w、ldc2_w、aconst_null、iconst_m1、iconst_&lt;i&gt;&lt;/li&gt;&#xA;&lt;li&gt;扩充局部变量表的访问索引的指令&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;br&gt;&#xA;&lt;h3 id=&#34;运算指令&#34;&gt;运算指令&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;加法指令：iadd、ladd、fadd、dadd&lt;/li&gt;&#xA;&lt;li&gt;减法指令：isub、lsub、fsub、dsub&lt;/li&gt;&#xA;&lt;li&gt;乘法指令：imul、lmul、fmul、dmul&lt;/li&gt;&#xA;&lt;li&gt;除法指令：idiv、ldiv、fdiv、ddiv&lt;/li&gt;&#xA;&lt;li&gt;求余指令：irem、lrem、frem、drem&lt;/li&gt;&#xA;&lt;li&gt;取反指令：ineg、lneg、fneg、dneg&lt;/li&gt;&#xA;&lt;li&gt;位移指令：ishl、ishr、iushr、lshl、lshr、lushr&lt;/li&gt;&#xA;&lt;li&gt;按位或指令：ior、lor&lt;/li&gt;&#xA;&lt;li&gt;按位与指令：iand、land&lt;/li&gt;&#xA;&lt;li&gt;按位异或指令：ixor、lxor&lt;/li&gt;&#xA;&lt;li&gt;局部变量自增指令：iinc&lt;/li&gt;&#xA;&lt;li&gt;比较指令：dcmpg、dcmpl、fcmpg、fcmpl、lcmp&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;br&gt;&#xA;&lt;h3 id=&#34;类型转换指令&#34;&gt;类型转换指令&lt;/h3&gt;&#xA;&lt;p&gt;JVM直接支持小范围类型向大范围类型的安全转换：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;int -&amp;gt; long/float/double&lt;/li&gt;&#xA;&lt;li&gt;long -&amp;gt; float/double&lt;/li&gt;&#xA;&lt;li&gt;float -&amp;gt; double&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;处理窄化类型转换时，要用转换指令来完成。包括i2b、i2c、i2s、l2i、f2i、f2l、d2i、d2l、d2f.&lt;/p&gt;&#xA;&lt;p&gt;在将int或long类型窄化转换成整数类型T的时候，转换过程仅仅是简单丢弃除最低位N字节以外的内容，N是类型T的数据类型长度。这将可能导致转换结果与输入值的正负号不同。&lt;/p&gt;&#xA;&lt;br&gt;&#xA;&lt;h3 id=&#34;对象创建与访问指令&#34;&gt;对象创建与访问指令&lt;/h3&gt;&#xA;&lt;p&gt;虽然类实例和数组都是对象，但是JVM对类实例和数组的创建使用不同的字节码指令，对象创建后，可以通过对象访问指令获取对象实例或者数组实例中的字段或者数组元素，包括：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;创建类实例指令：new&lt;/li&gt;&#xA;&lt;li&gt;创建数组的指令：newarray，anewarray，multianewarray&lt;/li&gt;&#xA;&lt;li&gt;访问类字段（static字段）和实例字段（非static字段）的指令：getfield、putfield、getstatic、putstatic&lt;/li&gt;&#xA;&lt;li&gt;把一个数组元素加载到操作数栈的指令：baload、caload、saload、iaload、laload、faload、daload、aaload&lt;/li&gt;&#xA;&lt;li&gt;将一个操作数栈的值存储到数组元素中的指令：bastore、castore、sastore、iastore、fastore、dastore、aastore&lt;/li&gt;&#xA;&lt;li&gt;取数组长度的指令：arraylength&lt;/li&gt;&#xA;&lt;li&gt;检查类实例类型的指令：instanceof、checkcast&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;br&gt;&#xA;&lt;h3 id=&#34;操作数栈管理指令&#34;&gt;操作数栈管理指令&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;将操作数栈的栈顶一个或者两个元素出栈：pop、pop2&lt;/li&gt;&#xA;&lt;li&gt;复制栈顶一个或两个数值并将复制值或双份的复制值重新压入栈顶：dup、dup2、dup_x1、dup2_x1、dup_x2、dup2_x2&lt;/li&gt;&#xA;&lt;li&gt;将栈最顶端的两个数值交换：swap&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;br&gt;&#xA;&lt;h3 id=&#34;控制转移指令&#34;&gt;控制转移指令&lt;/h3&gt;&#xA;&lt;p&gt;可以认为控制指令就是在有条件或者无条件地修改PC寄存器地值，控制指令包括：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;条件分支：ifeq、iflt、ifle、ifne、ifgt、ifge、ifnull、ifnonnull、if_icmpeq、if_icmpne、if_icmplt、if_icmpgt、if_icmple、if_icmpge、if_acmpeq、if_acmpne&lt;/li&gt;&#xA;&lt;li&gt;复合条件分支：tableswitch、lookupswitch&lt;/li&gt;&#xA;&lt;li&gt;无条件分支：goto、goto_w、jsr、jsr_w，ret&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;br&gt;&#xA;&lt;h3 id=&#34;方法调用和返回指令&#34;&gt;方法调用和返回指令&lt;/h3&gt;&#xA;&lt;p&gt;方法调用指令包括：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;invokevirtual：用于调用对象地实例方法，根据对象地实际类型进行分派&lt;/li&gt;&#xA;&lt;li&gt;invokeinterface：用于调用接口方法，他会在运行时搜索一个实现了这个接口地方法地对象，找出合适地方法进行调用&lt;/li&gt;&#xA;&lt;li&gt;invokespecial：用于调用一些需要特殊处理的实例方法，包括实例初始化方法，私有方法和父类方法&lt;/li&gt;&#xA;&lt;li&gt;invokestatic：用于调用类静态方法&lt;/li&gt;&#xA;&lt;li&gt;invokedynamic：用于在运行时动态解析出调用点限定符所引用的方法，并执行该方法。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;方法返回指令包括&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;ireturn（返回值为Boolean，char，short，int时使用）&lt;/li&gt;&#xA;&lt;li&gt;lreturn&lt;/li&gt;&#xA;&lt;li&gt;freturn&lt;/li&gt;&#xA;&lt;li&gt;dreturn&lt;/li&gt;&#xA;&lt;li&gt;areturn&lt;/li&gt;&#xA;&lt;li&gt;return（void）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;br&gt;&#xA;&lt;h3 id=&#34;异常处理指令&#34;&gt;异常处理指令&lt;/h3&gt;&#xA;&lt;p&gt;Java程序中显式抛出异常的操作（throw）都由athrow指令来实现。JVM规范规定许多运行时异常会在其他Java虚拟机指令检测到异常状态时自动抛出。&#xA;处理异常不是由字节码实现的，而是采用异常表实现的。&lt;/p&gt;&#xA;&lt;h3 id=&#34;同步指令&#34;&gt;同步指令&lt;/h3&gt;&#xA;&lt;p&gt;Java虚拟机可以支持方法级的同步和方法内部一段指令序列的同步，这两种同步结构都是使用管程（Monitor，也被称为锁）来实现的。&lt;/p&gt;</description>
    </item>
    <item>
      <title>JVM之类文件结构（六）</title>
      <link>http://localhost:1313/posts/jvm/jvm06-class-file/</link>
      <pubDate>Thu, 26 Mar 2020 17:30:40 +0000</pubDate>
      <guid>http://localhost:1313/posts/jvm/jvm06-class-file/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;实现语言无关性的基础是虚拟机和字节码存储格式。Java虚拟机不与任何程序语言绑定，它只与Class文件这种特定的二进制文件格式所关联。Class文件中包含了Java虚拟机指令集，符号表以及若干其他辅助信息。&lt;/p&gt;&#xA;&lt;h2 id=&#34;class文件结构&#34;&gt;Class文件结构&lt;/h2&gt;&#xA;&lt;p&gt;任何一个Class文件对应着唯一的一个类或者接口的定义信息，Class文件是一组以八个字节为基础单位的&lt;strong&gt;二进制流&lt;/strong&gt;，各个数据项目严格按照顺序紧凑的排列，中间没有任何分隔符，Class文件只有两种类型：&lt;strong&gt;无符号数&lt;/strong&gt;、&lt;strong&gt;表&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;无符号数属于基本数据类型，以u1,u2,u4,u8分别代表1/2/4/8个字节的无符号数，无符号数用来描述数字，索引引用，数量值。&lt;/li&gt;&#xA;&lt;li&gt;表：由多个无符号数或者其他表作为数据项构成的复合数据类型。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;魔数&#34;&gt;魔数&lt;/h3&gt;&#xA;&lt;p&gt;Class文件的头4个字节被称为魔数，它的唯一作用就是确定这个文件是否为一个能被JVM接受的Class文件，魔数的十六进制表示为&lt;code&gt;0xCAFEBABE&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;h3 id=&#34;版本信息&#34;&gt;版本信息&lt;/h3&gt;&#xA;&lt;p&gt;紧接着魔数的4个字节的是版本信息，第5-6字节是次版本号，7-8字节是主版本号，表示Class文件使用的JDK版本。&#xA;高版本的JDK能向下兼容，但是不能向上兼容。&lt;/p&gt;&#xA;&lt;h3 id=&#34;常量池&#34;&gt;常量池&lt;/h3&gt;&#xA;&lt;p&gt;版本信息之后是常量池入口，常量池主要存放两大类常量：&lt;strong&gt;字面量&lt;/strong&gt;、&lt;strong&gt;符号引用&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;常量池中常量的数量是不固定的，所以在入口需要放置一项u2类型的数据，代表常量池容量计数值。&lt;/p&gt;&#xA;&lt;p&gt;字面量接近于常量概念，如字符串、被声明为final的值。&#xA;符号引用属于编译原理方面的概念：主要包括：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;被模块导出或开放的包&lt;/li&gt;&#xA;&lt;li&gt;类和接口的全限定名&lt;/li&gt;&#xA;&lt;li&gt;字段的名称和描述符&lt;/li&gt;&#xA;&lt;li&gt;方法的名称和描述符&lt;/li&gt;&#xA;&lt;li&gt;方法句柄和方法类型&lt;/li&gt;&#xA;&lt;li&gt;动态调用点和动态产量&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;常量池的每个常量都是一个表，共有17钟不同类型的常量。表开始的第一位是个u1类型的标志位，代表当前常量属于哪种常量类型。&lt;/p&gt;&#xA;&lt;p&gt;17种常量类型：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;类型&lt;/th&gt;&#xA;          &lt;th&gt;tag&lt;/th&gt;&#xA;          &lt;th&gt;描述&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;CONSTANT_utf8_info&lt;/td&gt;&#xA;          &lt;td&gt;1&lt;/td&gt;&#xA;          &lt;td&gt;UTF-8编码的字符串&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;CONSTANT_Integer_info&lt;/td&gt;&#xA;          &lt;td&gt;3&lt;/td&gt;&#xA;          &lt;td&gt;整型字面量&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;CONSTANT_Float_info&lt;/td&gt;&#xA;          &lt;td&gt;4&lt;/td&gt;&#xA;          &lt;td&gt;浮点型字面量&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;CONSTANT_Long_info&lt;/td&gt;&#xA;          &lt;td&gt;5&lt;/td&gt;&#xA;          &lt;td&gt;长整型字面量&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;CONSTANT_Double_info&lt;/td&gt;&#xA;          &lt;td&gt;6&lt;/td&gt;&#xA;          &lt;td&gt;双精度浮点型字面量&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;CONSTANT_Class_info&lt;/td&gt;&#xA;          &lt;td&gt;7&lt;/td&gt;&#xA;          &lt;td&gt;类或接口的符号引用&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;CONSTANT_String_info&lt;/td&gt;&#xA;          &lt;td&gt;8&lt;/td&gt;&#xA;          &lt;td&gt;字符串类型字面量&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;CONSTANT_Fieldref_info&lt;/td&gt;&#xA;          &lt;td&gt;9&lt;/td&gt;&#xA;          &lt;td&gt;字段的符号引用&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;CONSTANT_Methodref_info&lt;/td&gt;&#xA;          &lt;td&gt;10&lt;/td&gt;&#xA;          &lt;td&gt;类中方法的符号引用&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;CONSTANT_InterfaceMethodref_info&lt;/td&gt;&#xA;          &lt;td&gt;11&lt;/td&gt;&#xA;          &lt;td&gt;接口中方法的符号引用&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;CONSTANT_NameAndType_info&lt;/td&gt;&#xA;          &lt;td&gt;12&lt;/td&gt;&#xA;          &lt;td&gt;字段或方法的符号引用&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;CONSTANT_MethodHandle_info&lt;/td&gt;&#xA;          &lt;td&gt;15&lt;/td&gt;&#xA;          &lt;td&gt;表示方法句柄&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;CONSTANT_MethodType_info&lt;/td&gt;&#xA;          &lt;td&gt;16&lt;/td&gt;&#xA;          &lt;td&gt;标识方法类型&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;CONSTANT_InvokeDynamic_info&lt;/td&gt;&#xA;          &lt;td&gt;18&lt;/td&gt;&#xA;          &lt;td&gt;表示一个动态方法调用点&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;br&gt;&#xA;对于 CONSTANT_Class_info（此类型的常量代表一个类或者接口的符号引用），它的二维表结构如下：&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;类型&lt;/th&gt;&#xA;          &lt;th&gt;名称&lt;/th&gt;&#xA;          &lt;th&gt;数量&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;u1&lt;/td&gt;&#xA;          &lt;td&gt;tag&lt;/td&gt;&#xA;          &lt;td&gt;1&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;u2&lt;/td&gt;&#xA;          &lt;td&gt;name_index&lt;/td&gt;&#xA;          &lt;td&gt;1&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;tag 是标志位，用于区分常量类型；name_index 是一个索引值，它指向常量池中一个 CONSTANT_Utf8_info 类型常量，此常量代表这个类（或接口）的全限定名，这里 name_index 值若为 0x0002，也即是指向了常量池中的第二项常量。&lt;/p&gt;</description>
    </item>
    <item>
      <title>JVM之内存分配策略（五）</title>
      <link>http://localhost:1313/posts/jvm/jvm05-memory-allocate/</link>
      <pubDate>Wed, 25 Mar 2020 19:53:08 +0000</pubDate>
      <guid>http://localhost:1313/posts/jvm/jvm05-memory-allocate/</guid>
      <description>&lt;h2 id=&#34;内存分配与回收策略&#34;&gt;内存分配与回收策略&lt;/h2&gt;&#xA;&lt;p&gt;Java技术体系的自动内存管理，最根本性的目标是自动化解决两个问题：自动给对象分配内存，以及自动回收分配给对象的内存。&lt;/p&gt;&#xA;&lt;p&gt;对象的内存分配，就是在堆上分配（也有可能经过JIT编译后被拆散为标量空间类型间接地在栈上分配），新生对象主要分配在新生代中，少数情况（大小超过阈值）会被分配在老年代，分配规则不固定，取决于当前使用的垃圾收集器与JVM参数设置。&lt;/p&gt;&#xA;&lt;h3 id=&#34;对象优先在eden分配&#34;&gt;对象优先在Eden分配&lt;/h3&gt;&#xA;&lt;p&gt;大多数情况下，对象在新生代Eden去中分配，当Eden区没有足够的空间进行分配时，虚拟机将发起一次Minor GC。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Minor GC：回收新生代（包括 Eden 和 Survivor 区域），因为 Java 对象大多都具备朝生夕灭的特性，所以 Minor GC 非常频繁，一般回收速度也比较快。&lt;/li&gt;&#xA;&lt;li&gt;Major GC / Full GC: 回收老年代，出现了 Major GC，经常会伴随至少一次的 Minor GC，但这并非绝对。Major GC 的速度一般会比 Minor GC 慢 10 倍 以上。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;大对象直接进入老年代&#34;&gt;大对象直接进入老年代&lt;/h3&gt;&#xA;&lt;p&gt;大对象就是需要大量连续内存空间的Java对象，最典型的大对象就是那种很长的字符串，或者元素数量很庞大的数组。&lt;/p&gt;&#xA;&lt;p&gt;JVM提供了一个&lt;code&gt;-XX:PretenureSizeThreshold&lt;/code&gt;，指定大于该设置值的对象直接在老年代分配，这样做的目的是避免在Eden区和两个Survivor区之间来回复制，产生大量内存复制操作。&lt;/p&gt;&#xA;&lt;h3 id=&#34;长期存活的对象进入老年代&#34;&gt;长期存活的对象进入老年代&lt;/h3&gt;&#xA;&lt;p&gt;为了决策哪些存活对象存储在新生代，哪些对象存储在老年代，，JVM给每个对象定义了一个对象年龄计数器，存储在对象头中，对象通常在Eden区诞生，如果经历一次Miror GC后仍然存活，并且能被Survivor容纳，该对象就会被移动到Survivor，并将该对象年龄设为1岁，对象每经历一次Miror GC，年龄就增加1岁，当年龄达到一定程度（默认15），就会被移动到老年代，对象年龄阈值可以通过&lt;code&gt;-XX:MaxTenuringThreshold&lt;/code&gt;设置。&lt;/p&gt;&#xA;&lt;h3 id=&#34;动态对象年龄判定&#34;&gt;动态对象年龄判定&lt;/h3&gt;&#xA;&lt;p&gt;如果当前新生代的Survivor中，相同年龄的所有对象大小的综合大于Survivor空间的一半，年龄大于或等于该年龄的对象可以进入老年代，无需等到MaxTenuringThreshold 中要求的年龄。&lt;/p&gt;&#xA;&lt;h3 id=&#34;空间分配担保&#34;&gt;空间分配担保&lt;/h3&gt;&#xA;&lt;p&gt;JDK 6 Update 24 之前，在发生Miror GC之前，虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间，如果这个条件成立，那这一次的Miror GC可以确保是安全的，如果不成立，则虚拟机会查看 HandlePromotionFailure 值是否设置为允许担保失败， 如果允许，那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小， 如果大于，将尝试进行一次 Minor GC,尽管这次 Minor GC 是有风险的； 如果小于，或者 HandlePromotionFailure 设置不允许冒险，那此时也要改为进行一次 Full GC。&lt;/p&gt;&#xA;&lt;p&gt;JDK 6 Update 24 之后的规则变为：&lt;br&gt;&#xA;只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小，就会进行 Minor GC，否则将进行 Full GC。&lt;/p&gt;</description>
    </item>
    <item>
      <title>JVM之垃圾收集算法与垃圾收集器（四）</title>
      <link>http://localhost:1313/posts/jvm/jvm04-gc-algorithrms/</link>
      <pubDate>Tue, 24 Mar 2020 21:05:57 +0000</pubDate>
      <guid>http://localhost:1313/posts/jvm/jvm04-gc-algorithrms/</guid>
      <description>&lt;h2 id=&#34;垃圾收集算法&#34;&gt;垃圾收集算法&lt;/h2&gt;&#xA;&lt;p&gt;从如何判定对象消亡的角度出发，垃圾收集算法可以划分为&lt;strong&gt;引用计数式垃圾收集&lt;/strong&gt;和&lt;strong&gt;追踪式垃圾收集&lt;/strong&gt;，由于引用计数式垃圾收集在主流JVM并未涉及，所以追踪式垃圾收集为主。&lt;/p&gt;&#xA;&lt;p&gt;当前的JVM大多数遵循了&lt;strong&gt;分代收集&lt;/strong&gt;理论进行设计，它主要建立在两个分代假说上面：&lt;strong&gt;弱分代假说&lt;/strong&gt;和&lt;strong&gt;强分代假说&lt;/strong&gt;。分代假说奠定了收集器的设计原则：收集器应该将Java堆划分出不同的区域，然后将回收对象依据其年龄分配到不同的区域之中存储。&lt;/p&gt;&#xA;&lt;h3 id=&#34;标记-清除算法&#34;&gt;标记-清除算法&lt;/h3&gt;&#xA;&lt;p&gt;&lt;strong&gt;标记&lt;/strong&gt;过程：遍历所有的&lt;code&gt;GC Roots&lt;/code&gt;，然后将&lt;code&gt;GC Roots&lt;/code&gt;可达对象标记为存活的对象。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;清除&lt;/strong&gt;过程：将没有标记的对象全部清除。&lt;/p&gt;&#xA;&lt;p&gt;主要缺点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;执行效率不稳定&lt;/li&gt;&#xA;&lt;li&gt;内存空间碎片化问题&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;标记-复制算法&#34;&gt;标记-复制算法&lt;/h3&gt;&#xA;&lt;p&gt;也被简称为复制算法，它将可用内存划分成大小相等的两块，每次只使用其中的一块，当这一块的内存用完，就把还存活的对象复制到另外一块上面，然后再把这一块内存全部清除。这种算法有优有劣。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;优点：不会出现内存碎片的问题&lt;/li&gt;&#xA;&lt;li&gt;缺点：可用内存缩为原来的一半，浪费空间&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;为了提高空间利用率的问题，可以将新生代分为一块较大的&lt;code&gt;Eden&lt;/code&gt;区，和两块较小的&lt;code&gt;Survivor&lt;/code&gt;区，比例为&lt;code&gt;8:1:1&lt;/code&gt;,每次 分配内存只使用Eden和其中一块Survivor，发生垃圾收集时，将Eden和Survivor中仍然存活的对象一次性复制到另外一块Survivor区，然后清理掉Eden和已用过的Survivor区，这样只有10%的内存被浪费掉。&#xA;但是不能保证每次回收都只有不多于10%的对象存活，当Survivor空间不够时，需要依赖其他内存区域（老年代）进行分配担保。&lt;/p&gt;&#xA;&lt;h3 id=&#34;标记-整理算法&#34;&gt;标记-整理算法&lt;/h3&gt;&#xA;&lt;p&gt;&lt;strong&gt;标记&lt;/strong&gt;过程：与&lt;strong&gt;标记-清除算法&lt;/strong&gt;一样，将存活的对象标记。&#xA;&lt;strong&gt;整理&lt;/strong&gt;过程：让所有存活的对象都向内存空间一端移动，然后直接清理掉边界之外的内存。&lt;/p&gt;&#xA;&lt;p&gt;这是一种老年代的垃圾收集算法，老年代对象的生命周期较长，因此每次垃圾回收会有大量对象存活，如果采用复制算法，每次效率很低。&lt;/p&gt;&#xA;&lt;h2 id=&#34;经典垃圾收集器&#34;&gt;经典垃圾收集器&lt;/h2&gt;&#xA;&lt;h3 id=&#34;新生代垃圾收集器&#34;&gt;新生代垃圾收集器&lt;/h3&gt;&#xA;&lt;h4 id=&#34;serial收集器单线程&#34;&gt;Serial收集器（单线程）&lt;/h4&gt;&#xA;&lt;p&gt;Serial收集器是一个新生代垃圾收集器，它在垃圾收集时，必须暂停其它所有工作线程,知道它收集结束（Stop the World）。&#xA;对于内存资源受限的环境，它时所有收集器里面额外内存消耗最小的，对于单核处理器或者处理器核心数较少的环境来说，Serial收集器由于没有线程交互的开销，壮美做垃圾收集自然可以获得最高的单线程手机效率。&lt;/p&gt;&#xA;&lt;h4 id=&#34;parnew收集器多线程&#34;&gt;ParNew收集器（多线程）&lt;/h4&gt;&#xA;&lt;p&gt;ParNew收集器实质上时Serial收集器的多线程并行版本，由多条GC线程并行的进行垃圾清理，清理过程仍需Stop The World。在多 CPU 环境下性能比 Serial 会有一定程度的提升；但&lt;strong&gt;线程切换需要额外的开销&lt;/strong&gt;，因此在单 CPU 环境中表现不如 Serial。&lt;/p&gt;&#xA;&lt;h4 id=&#34;parallel-scavenge收集器多线程&#34;&gt;Parallel Scavenge收集器（多线程）&lt;/h4&gt;&#xA;&lt;p&gt;Parallel Scavenge 和 ParNew 一样，都是多线程、新生代垃圾收集器。但是两者有巨大的不同点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Parallel Scavenge：追求 CPU 吞吐量，能够在较短时间内完成指定任务，因此适合没有交互的后台计算。&lt;/li&gt;&#xA;&lt;li&gt;ParNew：追求降低用户停顿时间，适合交互式应用。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间)&lt;/p&gt;&#xA;&lt;h3 id=&#34;老年代垃圾收集器&#34;&gt;老年代垃圾收集器&lt;/h3&gt;&#xA;&lt;h4 id=&#34;serial-old收集器单线程&#34;&gt;Serial Old收集器（单线程）&lt;/h4&gt;&#xA;&lt;p&gt;Serial Old 收集器是 Serial 的老年代版本，都是单线程收集器，只启用一条 GC 线程，都适合客户端应用。它们唯一的区别就是：Serial Old 工作在老年代，使用&lt;strong&gt;标记-整理&lt;/strong&gt;算法；Serial 工作在新生代，使用&lt;strong&gt;标记-复制&lt;/strong&gt;算法。&lt;/p&gt;</description>
    </item>
    <item>
      <title>JVM之垃圾收集策略（三）</title>
      <link>http://localhost:1313/posts/jvm/jvm03-gc-strategy/</link>
      <pubDate>Mon, 23 Mar 2020 22:00:18 +0000</pubDate>
      <guid>http://localhost:1313/posts/jvm/jvm03-gc-strategy/</guid>
      <description>&lt;h2 id=&#34;垃圾收集策略&#34;&gt;垃圾收集策略&lt;/h2&gt;&#xA;&lt;p&gt;程序计数器，虚拟机栈，本地方法栈随线程而生，随线程而灭，栈中的栈帧随着方法的进入和退出而执行入栈和出栈操作，每个栈帧分配多少内存基本上是在类结构确定下来时就已知的，因此这几个区域的分配和回收具备确定性。在这几个区域不需要过多考虑如何回收的问题，当方法执行结束或者线程结束，内存自然就跟随着回收。&#xA;而Java堆和方法区，只有程序运行期间才知道会创建多少对象，这部分内存的分配和回收都是动态的，GC关注的正是这部分内存。&lt;/p&gt;&#xA;&lt;h3 id=&#34;判断对象是否存活&#34;&gt;判断对象是否存活&lt;/h3&gt;&#xA;&lt;p&gt;如果一个对象不被任何对象或变量引用，那么他就是无效对象，需要被回收。判断是存活主要有以下几种算法。&lt;/p&gt;&#xA;&lt;h4 id=&#34;引用计数算法&#34;&gt;引用计数算法&lt;/h4&gt;&#xA;&lt;p&gt;在对象中添加一个引用计数器，每当有一个对地方引用它时，计数器值就加一，当引用失效时，计数器值就减一，任何时刻计数器为零的对象就是不可能再被使用的。&#xA;引用计数原理简单，判定效率也高，但是主流的JVM并没有选用引用计数来管理内存，主要原因是这个算法有很多例外情况需要考虑，比如对象之间相互循环引用。&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;对象 objA 和 objB 都有字段 instance，令 objA.instance = objB 并且 objB.instance = objA，由于它们互相引用着对方，导致它们的引用计数都不为 0，于是引用计数算法无法通知 GC 收集器回收它们。&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;h4 id=&#34;可达性分析算法&#34;&gt;可达性分析算法&lt;/h4&gt;&#xA;&lt;p&gt;所有和 &lt;code&gt;GC Roots&lt;/code&gt; 直接或间接关联的对象都是有效对象，和 &lt;code&gt;GC Roots&lt;/code&gt; 没有关联的对象就是无效对象。&lt;/p&gt;&#xA;&lt;p&gt;从&lt;code&gt;GC Roots&lt;/code&gt;作为起始节点，根据引用关系向下搜索，搜索过程所走过的路径称为&lt;strong&gt;引用链&lt;/strong&gt;，如果某个对象到&lt;code&gt;GC Roots&lt;/code&gt;之间没有任何引用链相连，就证明此对象不可能在被使用的。&lt;/p&gt;&#xA;&lt;p&gt;在Java技术体系里面，固定可作为&lt;code&gt;GC Roots&lt;/code&gt;的对象包括：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;在虚拟机栈（栈帧的本地变量表）中引用的对象，比如各个线程被调用的方法堆栈中使用到的参数，局部变量，临时变量等&lt;/li&gt;&#xA;&lt;li&gt;在方法区中常量引用的对象，比如字符串常量池里面的引用&lt;/li&gt;&#xA;&lt;li&gt;在本地方法栈中&lt;code&gt;JNI&lt;/code&gt;（Native）引用的对象&lt;/li&gt;&#xA;&lt;li&gt;Java虚拟机内部的引用，如基本数据类型对应的Class对象，一些常驻的异常对象，比如&lt;code&gt;NullPointerException&lt;/code&gt;，&lt;code&gt;OutofMemoryError&lt;/code&gt;等，还有系统类加载器&lt;/li&gt;&#xA;&lt;li&gt;所有被同步锁（synchronized）持有的对象&lt;/li&gt;&#xA;&lt;li&gt;反映Java虚拟机内部情况的&lt;code&gt;JMXBean&lt;/code&gt;，&lt;code&gt;JVMTI&lt;/code&gt;中注册的回调，本地代码缓存等&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;引用&#34;&gt;引用&lt;/h3&gt;&#xA;&lt;p&gt;判定对象是否存活与“引用”有关。在 JDK 1.2 以前，Java 中的引用定义很传统，一个对象只有被引用或者没有被引用两种状态，我们希望能描述这一类对象：当内存空间还足够时，则保留在内存中；如果内存空间在进行垃圾手收集后还是非常紧张，则可以抛弃这些对象。很多系统的缓存功能都符合这样的应用场景。&lt;/p&gt;&#xA;&lt;p&gt;在 JDK 1.2 之后，Java 对引用的概念进行了扩充，将引用分为了以下四种。不同的引用类型，主要体现的是对象不同的可达性状态&lt;code&gt;reachable&lt;/code&gt;和垃圾收集的影响。&lt;/p&gt;&#xA;&lt;h4 id=&#34;强引用&#34;&gt;强引用&lt;/h4&gt;&#xA;&lt;p&gt;类似&lt;code&gt;Object object = new Object()&lt;/code&gt;这类的引用，只要强引用还存在，垃圾收集器就永远不会回收掉被引用的对象。&lt;/p&gt;&#xA;&lt;h4 id=&#34;软引用&#34;&gt;软引用&lt;/h4&gt;&#xA;&lt;p&gt;软引用是用来描述一些还有用，但非必须的对象，只被软引用关联着的对象，在系统将要发生内存溢出异常前，会把这些对象列进回收范围之中进行第二次回收。即如果还有空闲内存，即暂时保存，当内存不足时清理掉。JDK1.2之后提供了&lt;code&gt;SoftReference&lt;/code&gt;来实现软引用。&lt;/p&gt;&#xA;&lt;h4 id=&#34;弱引用&#34;&gt;弱引用&lt;/h4&gt;&#xA;&lt;p&gt;弱引用用来描述那些非必须对象，它的强度比软引用更弱一些，被弱引用关联的对象只能生存到下一次垃圾收集发生为止。JDK 1.2之后提供&lt;code&gt;WeakReference&lt;/code&gt;类来实现弱引用&lt;/p&gt;&#xA;&lt;h4 id=&#34;虚引用&#34;&gt;虚引用&lt;/h4&gt;&#xA;&lt;p&gt;虚引用也成为幽灵引用或者幻影引用，他是最弱的一种引用关系。一个对象是否有虚引用的存在，完全不会对其生存空间构成影响。也无法通过虚引用来获取一个对象实例，为一个对象设置虚引用关联的唯一目的只是为了能在这个对象被收集器回收时收到一个系统通知，在JDK1.2之后提供&lt;code&gt;PhantomReference&lt;/code&gt;类来实现虚引用。&lt;/p&gt;&#xA;&lt;h3 id=&#34;回收过程&#34;&gt;回收过程&lt;/h3&gt;&#xA;&lt;p&gt;对于可达性分析中不可达的对象，那么它将会被第一次标记，随后进行一次筛选，筛选的条件是此对象是否有必要执行&lt;code&gt;finalize()&lt;/code&gt;方法，假如对象没有覆盖&lt;code&gt;finalize()&lt;/code&gt;方法，或者&lt;code&gt;finalize()&lt;/code&gt;方法已被虚拟机调用过，那么虚拟机将这两种情况都视为“没有必要执行”，那么对象基本上就真的被回收了。&lt;/p&gt;</description>
    </item>
    <item>
      <title>JVM之HotSpot VM对象（二）</title>
      <link>http://localhost:1313/posts/jvm/jvm02-java-object/</link>
      <pubDate>Sun, 22 Mar 2020 18:14:15 +0000</pubDate>
      <guid>http://localhost:1313/posts/jvm/jvm02-java-object/</guid>
      <description>&lt;h2 id=&#34;对象的创建过程&#34;&gt;对象的创建过程&lt;/h2&gt;&#xA;&lt;h3 id=&#34;类加载检查&#34;&gt;类加载检查&lt;/h3&gt;&#xA;&lt;p&gt;当JVM遇到一条字节码new指令时，首先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用，并检查这个符号引用代表的类是否已被加载，解析和初始化过。如果没有，那么先执行相应的类加载过程。&lt;/p&gt;&#xA;&lt;h3 id=&#34;为新生对象分配内存&#34;&gt;为新生对象分配内存&lt;/h3&gt;&#xA;&lt;p&gt;对象所需内存的大小再类加载完成后便可完全确定（对象的字段存储的时基本类型值，对象和数组的引用），接下来从Java堆中划分出对应大小的内存块给新的对象，分配方式有两种：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;指针碰撞&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;假设Java堆中内存时绝对规整的，所有被使用的内存都被放在一边，空闲的内存放在另一边，中间放着一个指针作为分界点的指示器，那么所分配内存就仅仅是把那个指针向空闲空间方向挪动一段所需大小的距离。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;空闲列表&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;如果Java堆中内存并不是规整的，使用的内存和未使用的内存交错在一起，此时无法使用指针碰撞方法，JVM需要维护一个列表，记录哪些内存块空闲可用，再分配的时候，从列表中找出一块足够大的空间划分给对象实例，并更新列表上的记录。&lt;/p&gt;&#xA;&lt;p&gt;Java堆是否规整，取决于采用的垃圾收集器是否具有空间压缩整理（Compact）的能力决定。使用&lt;code&gt;Serial&lt;/code&gt;、&lt;code&gt;ParNew&lt;/code&gt;等收集器时，采取指针碰撞方法，当使用CMS这种基于清除（Sweep）算法的收集器时，采用较为复杂的空闲列表来分配内存。&lt;/p&gt;&#xA;&lt;p&gt;如何保证并发情况下的线程安全问题？&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;对分配内存空间的动作进行同步处理，实际上JVM是采用CAS配上失败重试的方式保证更新操作的原子性&lt;/li&gt;&#xA;&lt;li&gt;把内存分配的动作按照线程划分再不同的空间之中进行，即每个线程在Java堆预先分配一小块内存，称为本地线程分配缓冲（TLAB）。哪个线程要分配内存，在哪个本地缓冲区进行分配。本地缓冲区用完了，分配新的缓存区才需要同步锁定。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;初始化&#34;&gt;初始化&lt;/h3&gt;&#xA;&lt;p&gt;分配完内存之后，JVM将内存空间都初始化为零值，这步操作保证了对象的实例字段在Java代码中可以不赋初始值就直接使用。&lt;/p&gt;&#xA;&lt;h3 id=&#34;设置信息&#34;&gt;设置信息&lt;/h3&gt;&#xA;&lt;p&gt;设置对象头信息：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;对象是哪个类的实例&lt;/li&gt;&#xA;&lt;li&gt;如何才能找到类的元数据信息&lt;/li&gt;&#xA;&lt;li&gt;对象的哈希码（真正调用&lt;code&gt;Object::hashCode()&lt;/code&gt;时才计算）&lt;/li&gt;&#xA;&lt;li&gt;对象的GC分代年龄&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;执行构造函数&#34;&gt;执行构造函数&lt;/h3&gt;&#xA;&lt;p&gt;执行之前，对象的所有字段都为默认的零值，通过Class文件中的&lt;code&gt;&amp;lt;init&amp;gt;()&lt;/code&gt;完成对象的创建过程。&lt;/p&gt;&#xA;&lt;p&gt;虚拟机层面完成对象创建工作时，Java程序刚开始执行构造函数，此时别的线程读取该对象不为Null（引用存了地址），但是内部无值。如果在并发环境下，由于指令重排序的存在，可能还未读到初始化变量。可以使用&lt;code&gt;volitale&lt;/code&gt;配合&lt;code&gt;Double Check&lt;/code&gt;完成工作。&lt;/p&gt;&#xA;&lt;h2 id=&#34;对象的内存布局&#34;&gt;对象的内存布局&lt;/h2&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/jvm/jvm-object.png&#34; alt=&#34;对象的内存布局&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;对象头&#34;&gt;对象头&lt;/h3&gt;&#xA;&lt;p&gt;对象头存储两类信息，第一类用于存储对象自身的运行时数据，称为&lt;code&gt;Mark Word&lt;/code&gt;，包括以下信息：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;哈希码&lt;/li&gt;&#xA;&lt;li&gt;GC分代年龄&lt;/li&gt;&#xA;&lt;li&gt;锁状态标志&lt;/li&gt;&#xA;&lt;li&gt;线程持有的锁&lt;/li&gt;&#xA;&lt;li&gt;偏向线程ID&lt;/li&gt;&#xA;&lt;li&gt;偏向时间戳&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;code&gt;Mark Word&lt;/code&gt;在32位，64位下分别为&lt;code&gt;32bit&lt;/code&gt;和&lt;code&gt;64bit&lt;/code&gt;，32位HotSpot虚拟机中，对象未被同步锁锁定的状态下，&lt;code&gt;Mark Word&lt;/code&gt;的&lt;code&gt;32bit&lt;/code&gt;中&lt;code&gt;25bit&lt;/code&gt;用于存储对象哈希码，&lt;code&gt;4bit&lt;/code&gt;用于存储对象分代年龄，&lt;code&gt;2bit&lt;/code&gt;用于存储锁标志位,&lt;code&gt;1bit&lt;/code&gt;固定为0。&lt;/p&gt;&#xA;&lt;p&gt;类型指针即对象指向它的类型元数据的指针，JVM通过这个指针来确定对象是哪个类的实例。但类型指针并不是一定存在的。&lt;/p&gt;&#xA;&lt;h3 id=&#34;实例数据&#34;&gt;实例数据&lt;/h3&gt;&#xA;&lt;p&gt;实例数据部分是对象成员变量的值，包括父类继承下来的成员变量和本类的成员变量。&lt;/p&gt;&#xA;&lt;h3 id=&#34;对齐填充&#34;&gt;对齐填充&lt;/h3&gt;&#xA;&lt;p&gt;不是必然存在的，起到占位符的作用，因为HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍，对象头部分正好是整数倍，当实例数据部分没有对齐时，通过对齐填充来补全。&lt;/p&gt;&#xA;&lt;h2 id=&#34;对象的访问定位&#34;&gt;对象的访问定位&lt;/h2&gt;&#xA;&lt;p&gt;对象的存储空间在堆上分配，对象的引用在栈上分配，通过这个引用找到具体的对象，主流的访问方式有使用句柄和直接指针两种。&lt;/p&gt;&#xA;&lt;h3 id=&#34;句柄访问方式&#34;&gt;句柄访问方式&lt;/h3&gt;&#xA;&lt;p&gt;堆中需要划分一块内存来作为句柄池，reference中存储的就是对象的句柄地址，而句柄中包含了对象实例数据与类型数据各自具体的地址信息。句柄访问的最大好处就是引用中存放的是稳定句柄地址，在对象被移动时只会改变句柄中的实例数据指针。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/jvm/IMG_0038.PNG&#34; alt=&#34;通过句柄访问对象&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;直接指针访问方式&#34;&gt;直接指针访问方式&lt;/h3&gt;&#xA;&lt;p&gt;直接指针访问的最大好处就是速度更快，节省了一次指针定位的时间开销。&#xA;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/jvm/IMG_0037.PNG&#34; alt=&#34;直接指针访问对象&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>JVM之Java内存结构（一）</title>
      <link>http://localhost:1313/posts/jvm/jvm01-java-memory-structure/</link>
      <pubDate>Sat, 21 Mar 2020 17:33:06 +0000</pubDate>
      <guid>http://localhost:1313/posts/jvm/jvm01-java-memory-structure/</guid>
      <description>&lt;h1 id=&#34;java运行时数据区域&#34;&gt;Java运行时数据区域&lt;/h1&gt;&#xA;&lt;p&gt;数据区域主要分为五个部分：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;程序计数器&lt;/li&gt;&#xA;&lt;li&gt;虚拟机栈&lt;/li&gt;&#xA;&lt;li&gt;本地方法栈&lt;/li&gt;&#xA;&lt;li&gt;堆&lt;/li&gt;&#xA;&lt;li&gt;方法区&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;其中所有线程共享区域有：方法区和堆。&lt;/p&gt;&#xA;&lt;p&gt;每个线程独享区域有：虚拟机栈，本地方法栈，程序计数器&#xA;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/jvm/java-memory.png&#34; alt=&#34;Java运行时数据区域&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;线程独享的区域&#34;&gt;线程独享的区域&lt;/h2&gt;&#xA;&lt;h3 id=&#34;程序计数器&#34;&gt;程序计数器&lt;/h3&gt;&#xA;&lt;p&gt;程序计数器是一块较小的内存空间，它可以看作是当前线程所执行的字节码的行号指示器，如果当前线程执行的是一个本地方法，那么此时计数器的值为&lt;code&gt;undefined&lt;/code&gt;，是唯一一个不会出现&lt;code&gt;OutOfMemoryError&lt;/code&gt;的内存区域。&lt;/p&gt;&#xA;&lt;h3 id=&#34;java虚拟机栈&#34;&gt;Java虚拟机栈&lt;/h3&gt;&#xA;&lt;p&gt;虚拟机栈描述的是Java方法执行的线程内存模型，每个方法被执行的时候，Java虚拟机都会同步创建一个栈帧，用于存放以下内容：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;局部变量表&lt;/li&gt;&#xA;&lt;li&gt;操作数栈&lt;/li&gt;&#xA;&lt;li&gt;动态链接&lt;/li&gt;&#xA;&lt;li&gt;方法出口&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;其中局部变量表包括以下内容：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;八大基本数据类型&lt;/li&gt;&#xA;&lt;li&gt;对象引用&lt;/li&gt;&#xA;&lt;li&gt;returnAddress类型（保存的是return后要执行的字节码的指令地址）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这些数据类型在局部变量表中的存储空间以局部变量槽来表示，64位长度的&lt;code&gt;long&lt;/code&gt;和&lt;code&gt;double&lt;/code&gt;类型占用两个变量槽，其余的占用一个。局部变量表所需的内存空间在编译期间完成分配，方法运行期间不会改变局部变量表的大小。&lt;/p&gt;&#xA;&lt;p&gt;Java 虚拟机栈会出现两种异常：&lt;code&gt;StackOverFlowError&lt;/code&gt; 和 &lt;code&gt;OutOfMemoryError&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;如果线程请求的栈深度大于虚拟机所允许的深度，将抛出&lt;code&gt;StackOverFlowError&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;如果Java虚拟机栈容量可以动态扩展，当栈扩展时无法申请到足够内存会抛出&lt;code&gt;OutOfMemoryError&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;本地方法栈&#34;&gt;本地方法栈&lt;/h3&gt;&#xA;&lt;p&gt;本地方法栈是为JVM使用到的&lt;code&gt;Native&lt;/code&gt;方法准备的空间。&lt;/p&gt;&#xA;&lt;h2 id=&#34;线程共享的区域&#34;&gt;线程共享的区域&lt;/h2&gt;&#xA;&lt;h3 id=&#34;堆&#34;&gt;堆&lt;/h3&gt;&#xA;&lt;p&gt;主要特点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;堆是被所有线程共享的一块内存区域&lt;/li&gt;&#xA;&lt;li&gt;在虚拟机启动时创建&lt;/li&gt;&#xA;&lt;li&gt;堆的唯一目的就是存放对象实例&lt;/li&gt;&#xA;&lt;li&gt;堆是垃圾回收管理的内存区域&lt;/li&gt;&#xA;&lt;li&gt;可分为新生代，老年代，永久代等（一部分垃圾收集器的共同特性或者设计风格，不是具体实现的固有内存布局）&lt;/li&gt;&#xA;&lt;li&gt;从分配内存的角度看，所有线程共享的Java堆可以划分出多个线程私有的分配缓冲区（TLAB）以提升对象分配的效率，这样做可以更好地回收内存或者更快的分配内存。&lt;/li&gt;&#xA;&lt;li&gt;堆的大小可以通过&lt;code&gt;-Xmx&lt;/code&gt;和&lt;code&gt;-Xms&lt;/code&gt;设定。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;方法区&#34;&gt;方法区&lt;/h3&gt;&#xA;&lt;p&gt;Java 虚拟机规范中定义方法区是堆的一个逻辑部分。&#xA;用于存储以下内容：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;已被虚拟机加载的类信息&lt;/li&gt;&#xA;&lt;li&gt;常量&lt;/li&gt;&#xA;&lt;li&gt;静态变量&lt;/li&gt;&#xA;&lt;li&gt;即时编译器编译后的代码&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;方法区内的主要回收目标是对常量池的回收和对类型的卸载。&lt;/p&gt;&#xA;&lt;h4 id=&#34;运行时常量池&#34;&gt;运行时常量池&lt;/h4&gt;&#xA;&lt;p&gt;运行时常量池是方法区的一部分。主要存放以下内容：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;类信息（版本，字段，方法，接口等描述信息）&lt;/li&gt;&#xA;&lt;li&gt;常量池表（用于存放编译期生成的各种字面量与符号引用）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Java并不要求常量一定在编译期间产生，并非Class文件中常量池的内容才能进入运行时常量池，运行期间产生的新的常量也能放入池中。比如&lt;code&gt;String&lt;/code&gt;类的&lt;code&gt;intern()&lt;/code&gt;方法。&#xA;当常量池无法再申请到内存会抛出&lt;code&gt;OutOfMemoryError&lt;/code&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;直接内存堆外内存&#34;&gt;直接内存（堆外内存）&lt;/h3&gt;&#xA;&lt;p&gt;直接内存并不是虚拟机运行时数据区的一部分，也不是虚拟机规范中定义的内存区域，但是会被频繁地使用，也可能导致&lt;code&gt;OutOfMemoryError&lt;/code&gt;&#xA;直接内存的分配不受JVM控制，但是会受到本机总内存（物理内存，SWAP分区，分页文件）以及处理器寻址空间的限制。&lt;/p&gt;</description>
    </item>
    <item>
      <title>排序算法总结</title>
      <link>http://localhost:1313/posts/%E7%AE%97%E6%B3%95/sort-algorithm/</link>
      <pubDate>Tue, 10 Mar 2020 20:19:19 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E7%AE%97%E6%B3%95/sort-algorithm/</guid>
      <description>&lt;h2 id=&#34;性质&#34;&gt;性质&lt;/h2&gt;&#xA;&lt;h3 id=&#34;稳定性&#34;&gt;稳定性&lt;/h3&gt;&#xA;&lt;p&gt;稳定性指相等的元素经过排序之后相对顺序是否发生了改变。&lt;/p&gt;&#xA;&lt;h3 id=&#34;时间复杂度&#34;&gt;时间复杂度&lt;/h3&gt;&#xA;&lt;p&gt;对于基于比较的排序算法的时间复杂度，较好的性能是$O(nlogn)$，坏的性能是$O(n^2)$。一个排序算法的理想性能是$O(n)$，但是平均而言不可能达到。&lt;/p&gt;&#xA;&lt;h2 id=&#34;选择排序&#34;&gt;选择排序&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;Selection sort&lt;/strong&gt;是较为简单的一种排序算法，每次找到第$i$小的元素，然后将这个元素与数组的第$i$个位置上的元素交换。换句话说：每次找到未完成排序的数组中最小的值，然后将其与边界（已排序和未排序元素的边界）进行交换。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;由于swap操作的存在，因此该算法是一种不稳定的排序算法&lt;/li&gt;&#xA;&lt;li&gt;选择排序的最优、平均、最坏时间复杂度都是$O(n^2)$。两层for&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Java：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;selection&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; arr){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; n &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; arr.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 1; i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; n; i&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; minIndex &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; i;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; j &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; 1; j &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; n; j&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (arr&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;j&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; arr&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;minIndex&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    minIndex &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; j;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            swap(arr, i, minIndex);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;冒泡排序&#34;&gt;冒泡排序&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;Bubble Sort&lt;/strong&gt;由于在算法的执行过程中，较小的元素像气泡一样慢慢浮到数组的顶端，故称为冒泡排序。&lt;/p&gt;&#xA;&lt;p&gt;工作原理：每次检查相邻的两个元素，如果满足排序条件，则交换。经过$i$次扫描，数组末尾的$i$项必然是第$i$大的元素，因此冒泡排序最多需要扫描$n - 1$遍数组就能完成排序。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;稳定的排序算法&lt;/li&gt;&#xA;&lt;li&gt;序列完全有序时，冒泡排序只需遍历一次数组，不用执行任何交换操作，时间复杂度位$O (n) $&lt;/li&gt;&#xA;&lt;li&gt;最坏情况下，需要进行$\frac{(n - 1)n}{2} $次交换操作。&lt;/li&gt;&#xA;&lt;li&gt;平均时间复杂度为$O(n)$&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;bubbleSort&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;[]&lt;/span&gt; arr) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; flag &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; (flag) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            flag &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; 1; i &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; arr.&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;1; i&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (arr&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;i&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; arr&lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;i &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; 1&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    flag &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    swap(arr, i, i &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; 1);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;插入排序&#34;&gt;插入排序&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;Insertion Sort&lt;/strong&gt;：将待排序元素划分为已排序和未排序两部分，每次从未排序元素中选择一个插入到已排序的的元素中的正确位置。&lt;/p&gt;</description>
    </item>
    <item>
      <title>编译OpenJDK</title>
      <link>http://localhost:1313/posts/%E5%B7%A5%E5%85%B7/build-jdk/</link>
      <pubDate>Sat, 22 Feb 2020 18:18:19 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E5%B7%A5%E5%85%B7/build-jdk/</guid>
      <description>&lt;h1 id=&#34;前言&#34;&gt;前言&lt;/h1&gt;&#xA;&lt;p&gt;最近在看《深入理解Java虚拟机》这本书，1.6节是编译openjdk，自己也想尝试一下。&lt;/p&gt;&#xA;&lt;p&gt;使用操作系统为：Ubuntu 18.04 LTS&lt;/p&gt;&#xA;&lt;h1 id=&#34;正文&#34;&gt;正文&lt;/h1&gt;&#xA;&lt;h2 id=&#34;下载源码&#34;&gt;下载源码&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;a href=&#34;http://hg.openjdk.java.net/jdk/jdk12&#34;&gt;http://hg.openjdk.java.net/jdk/jdk12&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;书中提供的下载地址由于网络问题下载较慢，所以在Github的仓库下载，地址为：&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/openjdk/jdk&#34;&gt;https://github.com/openjdk/jdk&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;作者建议阅读&lt;strong&gt;doc/building.md&lt;/strong&gt;，里面有详细的需要安装的编译环境与编译说明。&lt;/p&gt;&#xA;&lt;h2 id=&#34;构建编译&#34;&gt;构建编译&lt;/h2&gt;&#xA;&lt;p&gt;使用&lt;strong&gt;bash configure&lt;/strong&gt;进行设置编译参数。具体的编译配置参数可见&lt;strong&gt;doc/building.md&lt;/strong&gt;。&#xA;成功后命令行回显如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/buildjdk/bashconfigure.png&#34; alt=&#34;编译成功回显&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;编译&#34;&gt;编译&lt;/h2&gt;&#xA;&lt;p&gt;输入&lt;strong&gt;make images&lt;/strong&gt;进行编译。等大概二十分钟编译完成。&lt;/p&gt;&#xA;&lt;p&gt;编译好的jdk位于&lt;strong&gt;build/配置名称/jdk&lt;/strong&gt;，该目录可以直接当成完整的JDK进行使用。&lt;/p&gt;&#xA;&lt;p&gt;至此，编译JDK工作完成。&lt;/p&gt;</description>
    </item>
    <item>
      <title>分布式锁的实现方案</title>
      <link>http://localhost:1313/posts/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E7%9A%84%E5%AE%9E%E7%8E%B0%E6%96%B9%E6%A1%88/</link>
      <pubDate>Thu, 02 Jan 2020 20:24:24 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E7%9A%84%E5%AE%9E%E7%8E%B0%E6%96%B9%E6%A1%88/</guid>
      <description>&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;分布式锁是控制分布式系统或不同系统之间共同访问共享资源的一种锁实现，如果不同的系统或同一个系统的不同主机之间共享了某个资源时，往往需要互斥来防止彼此干扰来保证一致性。&lt;/p&gt;&lt;/blockquote&gt;&#xA;&lt;p&gt;分布式锁需要具备的条件：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;互斥性：在任意一个时刻，只有一个客户端持有锁。&lt;/li&gt;&#xA;&lt;li&gt;无死锁：即使持有锁的客户端崩溃或者其他意外事件，锁仍然可以被获取。&lt;/li&gt;&#xA;&lt;li&gt;容错：只要大部分Redis节点都活着，客户端可以获取和释放锁。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;分布式锁的主要实现方式：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;数据库&lt;/li&gt;&#xA;&lt;li&gt;Redis等缓存数据库，&lt;code&gt;redis&lt;/code&gt;的&lt;code&gt;setnx&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Zookeeper 临时节点&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;redis-实现分布式锁&#34;&gt;Redis 实现分布式锁&lt;/h3&gt;&#xA;&lt;h3 id=&#34;第一阶段&#34;&gt;第一阶段&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;public void hello() {&#xA;    Integer lock = get(&amp;#34;lock&amp;#34;);&#xA;    if(lock == null){&#xA;        set(&amp;#34;lock&amp;#34;,1);&#xA;        //todo&#xA;        del(&amp;#34;lock&amp;#34;);&#xA;        return;&#xA;    }else {&#xA;        //自旋&#xA;        hello();&#xA;    }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;存在的问题：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;请求同时打进来，所有请求都获取不到锁&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;第二阶段&#34;&gt;第二阶段&lt;/h3&gt;&#xA;&lt;p&gt;使用&lt;code&gt;setnx&lt;/code&gt;设置锁&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;setnx&lt;/code&gt;在key不存在时可以设置，存在当前key则不操作&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;public void hello(){&#xA;   String lock = setnx(&amp;#34;lock&amp;#34;); //0代表没有保存数据，说明有人占坑了，1代表占坑成功&#xA;    if(lock != 0){&#xA;        //todo&#xA;        del(&amp;#34;lock&amp;#34;);&#xA;    }else {&#xA;        //自旋&#xA;        hello();&#xA;    } &#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;存在的问题：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;由于各种问题（未捕获的异常，断电）等导致锁未释放，其他人永远获取不到锁&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;第三阶段&#34;&gt;第三阶段&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;public void hello(){&#xA;    String lock = setnx(&amp;#34;lock&amp;#34;);&#xA;    if(lock != 0){&#xA;        expire(&amp;#34;lock&amp;#34;,10s);&#xA;        //todo&#xA;        del(&amp;#34;lock&amp;#34;);&#xA;    }else {&#xA;        hello();&#xA;    }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;存在的问题：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Linux学习笔记</title>
      <link>http://localhost:1313/posts/linux/linux%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</link>
      <pubDate>Tue, 09 Jul 2019 18:38:46 +0000</pubDate>
      <guid>http://localhost:1313/posts/linux/linux%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/</guid>
      <description></description>
    </item>
    <item>
      <title>Git命令记录</title>
      <link>http://localhost:1313/posts/%E5%B7%A5%E5%85%B7/git-note/</link>
      <pubDate>Thu, 30 May 2019 12:14:39 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E5%B7%A5%E5%85%B7/git-note/</guid>
      <description>&lt;h3 id=&#34;1-基本操作&#34;&gt;1. 基本操作&lt;/h3&gt;&#xA;&lt;h4 id=&#34;基本命令&#34;&gt;基本命令&lt;/h4&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;mkdir notes&#xA;cd notes&#xA;&#xA;# 初始化一个git仓库 &#xA;git init&#xA;&#xA;echo &amp;#34;my notes&amp;#34; &amp;gt; readme.md&#xA;&#xA;# 查看状态&#xA;git status&#xA;&#xA;# 查看修改内容&#xA;git diff readme.md&#xA;&#xA;# 添加文件到仓库&#xA;git add readme.md&#xA;&#xA;# 提交更改&#xA;git commit -m &amp;#34;add readme&amp;#34;&#xA;&#xA;# 查看提交日志&#xA;git log&#xA;&#xA;# 回退到上一个版本&#xA;git reset --hard HEAD^&#xA;&#xA;# HEAD: 当前版本&#xA;# HEAD^: 上一个版本&#xA;# HEAD~100: 前一百个版本&#xA;# 58a65b: 指定版本&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;工作区与暂存区&#34;&gt;工作区与暂存区&lt;/h4&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;|-------|            |-------|               |-------|&#xA;| 工作区 | -- add --&amp;gt; | 暂存区 | -- commit --&amp;gt; | 主分支 |&#xA;|-------|            |-------|               |-------|&#xA;&#xA;&#xA;# 查看工作区与暂存区文件的差异&#xA;git diff readme.md&#xA;&#xA;# 查看工作区和版本库最新版本的差异&#xA;git diff HEAD -- readme.md&#xA;&#xA;# 放弃工作区的修改(未执行 git add 命令)&#xA;git checkout -- readme.md&#xA;&#xA;# 撤销暂存区（已经执行了 git add 命令）&#xA;git reset HEAD readme.md&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;删除文件&#34;&gt;删除文件&lt;/h4&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# 删除文件&#xA;rm test.txt&#xA;git add test.txt&#xA;git commit -m &amp;#34;rm test.txt&amp;#34;&#xA;&#xA;# 直接从版本库中删除文件&#xA;git rm test.txt&#xA;git commit -m &amp;#34;git rm test.txt&amp;#34;&#xA;&#xA;# 还原文件&#xA;git reset --hard CommitID&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;2-远程仓库&#34;&gt;2. 远程仓库&lt;/h3&gt;&#xA;&lt;h4 id=&#34;github仓库&#34;&gt;Github仓库&lt;/h4&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# 在本地创建一个 gitlearn 目录，并进入&#xA;mkdir gitlearn&#xA;cd gitlearn&#xA;&#xA;# 使用命令 git init 初始化一个库&#xA;git init&#xA;&#xA;# 添加远程库 origin&#xA;git remote add origin git@github.com:l1nker4/gitlearn.git&#xA;&#xA;# 添加 readme.md 文件&#xA;echo &amp;#34;git learn is very easy!&amp;#34; &amp;gt; readme.md&#xA;&#xA;# 添加文件并提交到仓库&#xA;git add readme.md&#xA;git commit -m &amp;#34;add readme&amp;#34;&#xA;&#xA;# 执行向远程仓库 origin master 分支推送更新（-u 参数用于关联远程仓库）&#xA;git push -u origin master&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;更新远程仓库&#34;&gt;更新远程仓库&lt;/h4&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# 查看当前分支的关联远程仓库&#xA;git branch -vv&#xA;&#xA;# 查看远程仓库的 URL&#xA;git remote -v&#xA;&#xA;# 重新设置远程仓库的 URL&#xA;git remote set-url origin git@github.com:l1nker4/gitlearn.git&#xA;&#xA;# 将当前修改更新到远程 master 分支&#xA;git push origin master&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;3分支管理&#34;&gt;3.分支管理&lt;/h3&gt;&#xA;&lt;h4 id=&#34;创建与合并分支&#34;&gt;创建与合并分支&lt;/h4&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# 查看当前分支&#xA;git branch &#xA;&#xA;# 基于当前分支创建新分支&#xA;git branch dev&#xA;&#xA;# 切换分支&#xA;git checkout dev&#xA;&#xA;# 创建并切换分支&#xA;git checkout -b dev&#xA;&#xA;# 切换到 master 分支&#xA;git checkout master&#xA;&#xA;# 合并指定分支到当前分支(合并 dev 分支到 master 分支)&#xA;git merge dev &#xA;&#xA;# 删除分支&#xA;git branch -d dev&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;冲突管理&#34;&gt;冲突管理&lt;/h4&gt;&#xA;&lt;p&gt;在 master 分支上修改 readme.md，新增一行内容。提交修改。 在 dev 分支上修改 readme.md，也新增一行内容。提交修改。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Docker学习笔记</title>
      <link>http://localhost:1313/posts/%E5%B7%A5%E5%85%B7/docker/</link>
      <pubDate>Mon, 27 May 2019 20:18:39 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E5%B7%A5%E5%85%B7/docker/</guid>
      <description>&lt;h2 id=&#34;1docker概念&#34;&gt;1.Docker概念&lt;/h2&gt;&#xA;&lt;h3 id=&#34;模型&#34;&gt;模型&lt;/h3&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/docker/docker.png&#34; alt=&#34;docker.png&#34;&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;虚拟机运行在虚拟的硬件上，应用运行在虚拟机内核上，而Docker是机器上的一个进程，Docker应用是Docker的一个子进程。&lt;/li&gt;&#xA;&lt;li&gt;Docker是对Linux容器（LXC）的一种封装，提供简单易用的接口，Docker是目前最流行的Linux容器解决方案。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;docker用途&#34;&gt;Docker用途&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;提供一次性的环境。主要用于测试。&lt;/li&gt;&#xA;&lt;li&gt;提供云服务&lt;/li&gt;&#xA;&lt;li&gt;组建微服务架构。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;docker引擎&#34;&gt;Docker引擎&lt;/h3&gt;&#xA;&lt;p&gt;Docker 引擎是一个包含以下主要组件的客户端服务器应用程序。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;一种服务器，它是一种称为守护进程并且长时间运行的程序。&lt;/li&gt;&#xA;&lt;li&gt;REST API用于指定程序可以用来与守护进程通信的接口，并指示它做什么。&lt;/li&gt;&#xA;&lt;li&gt;一个有命令行界面工具的客户端。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/docker/620140640_31678.png&#34; alt=&#34;620140640_31678.png&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;docker系统架构&#34;&gt;Docker系统架构&lt;/h3&gt;&#xA;&lt;p&gt;Docker 使用客户端-服务器 (C/S) 架构模式，使用远程 API 来管理和创建 Docker 容器。&lt;/p&gt;&#xA;&lt;p&gt;Docker 容器通过 Docker 镜像来创建。&lt;/p&gt;&#xA;&lt;p&gt;容器和对象的关系可以类似于对象和类。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/docker/262150629_86976.png&#34; alt=&#34;262150629_86976.png&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;docker镜像&#34;&gt;Docker镜像&lt;/h3&gt;&#xA;&lt;p&gt;在Linux下，内核启动会挂载&lt;code&gt;root&lt;/code&gt;文件系统，Docker镜像就相当于一个&lt;code&gt;root&lt;/code&gt;文件系统，它除了提供容器运行时所需的程序，资源，配置之外，还有一些配置参数（匿名卷，环境变量，用户）。&lt;/p&gt;&#xA;&lt;p&gt;Docker镜像使用分层存储技术，它并非像ISO镜像那样的文件，镜像是一个虚拟的概念，它是由一组文件系统构成。&lt;/p&gt;&#xA;&lt;h3 id=&#34;docker容器&#34;&gt;Docker容器&lt;/h3&gt;&#xA;&lt;p&gt;容器的本质是进程，容器进程运行于属于自己的命名空间，它可以拥有自己的&lt;code&gt;root&lt;/code&gt;文件系统，自己的网络配置等宿主机可以有的东西。&lt;/p&gt;&#xA;&lt;p&gt;每一个容器运行时，都是以镜像为基础层，在其上创建一个当前容器的存储层，可以称这个为容器运行时读写而准备的存储层为&lt;strong&gt;容器存储层&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;h3 id=&#34;docker仓库&#34;&gt;Docker仓库&lt;/h3&gt;&#xA;&lt;p&gt;存放镜像的地方&lt;/p&gt;&#xA;&lt;h2 id=&#34;2安装docker&#34;&gt;2.安装Docker&lt;/h2&gt;&#xA;&lt;h4 id=&#34;1获取脚本并下载&#34;&gt;1.获取脚本并下载&lt;/h4&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;//从官网获取安装脚本&#xA;$ curl -fsSL get.docker.com -o get-docker.sh&#xA;//使用AzureChinaCloud镜像脚本&#xA;$ sudo sh get-docker.sh --mirror AzureChinaCloud&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;2启动docker&#34;&gt;2.启动Docker&lt;/h4&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ sudo systemctl enable docker&#xA;$ sudo systemctl start docker&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;3建立docker用户组&#34;&gt;3.建立Docker用户组&lt;/h4&gt;&#xA;&lt;p&gt;docker命令只有root用户和docker组的用户才能访问docker引擎&lt;/p&gt;&#xA;&lt;h5 id=&#34;建立docker组&#34;&gt;建立Docker组&lt;/h5&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ sudo groupadd docker&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&#34;将当前用户加入docker组&#34;&gt;将当前用户加入Docker组&lt;/h5&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ sudo usermod -aG docker $USER&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&#34;校验是否安装成功&#34;&gt;校验是否安装成功&lt;/h5&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;l1nker4@zero:~$ docker version &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Client:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Version:           18.09.6&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; API version:       1.39&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Go version:        go1.10.8&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Git commit:        481bc77&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Built:             Sat May  &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; 02:35:57 &lt;span style=&#34;color:#ae81ff&#34;&gt;2019&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; OS/Arch:           linux/amd64&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Experimental:      false&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Server: Docker Engine - Community&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Engine:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Version:          18.09.6&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  API version:      1.39 &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;minimum version 1.12&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Go version:       go1.10.8&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Git commit:       481bc77&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Built:            Sat May  &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt; 01:59:36 &lt;span style=&#34;color:#ae81ff&#34;&gt;2019&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  OS/Arch:          linux/amd64&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Experimental:     false&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;4-添加镜像加速器&#34;&gt;4. 添加镜像加速器&lt;/h4&gt;&#xA;&lt;h5 id=&#34;新建daemonjson文件&#34;&gt;新建daemon.json文件&lt;/h5&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo touch /etc/docker/daemon.json&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id=&#34;添加内容&#34;&gt;添加内容&lt;/h5&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;registry-mirrors&amp;#34;&lt;/span&gt;: [&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://registry.docker-cn.com&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;3常用命令&#34;&gt;3.常用命令&lt;/h2&gt;&#xA;&lt;h4 id=&#34;1镜像操作&#34;&gt;1.镜像操作&lt;/h4&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th style=&#34;text-align: center&#34;&gt;名称&lt;/th&gt;&#xA;          &lt;th style=&#34;text-align: center&#34;&gt;命令&lt;/th&gt;&#xA;          &lt;th style=&#34;text-align: center&#34;&gt;作用&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;搜索&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;docker search xxx&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;搜索镜像&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;拉取&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;docker pull xxx&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;从仓库拉取镜像&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;列表&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;docker images&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;列出所有镜像&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;删除&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;docker rmi imageID&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;删除镜像&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h4 id=&#34;2容器操作&#34;&gt;2.容器操作&lt;/h4&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th style=&#34;text-align: center&#34;&gt;名称&lt;/th&gt;&#xA;          &lt;th style=&#34;text-align: center&#34;&gt;命令&lt;/th&gt;&#xA;          &lt;th style=&#34;text-align: center&#34;&gt;说明&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;运行&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;docker run &amp;ndash;name container-name -d image-name&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;&amp;ndash;name：自定义容器名，-d：后台运行，image-name：指定镜像模板&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;列表&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;docker ps&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;查看运行中的容器，-a：查看所有容器&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;停止&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;docker stop container-name/container-id&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;停止当前你运行的容器&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;启动&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;docker start container-name/container-id&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;启动容器&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;删除&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;docker rm container-id&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;s删除指定容器&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;端口映射&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;-p 6379:6379&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: center&#34;&gt;-p：主机端口映射到容器内部端口&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;docker run -d -p 8888:8080 tomcat&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;-d：后台运行，-p：端口映射&lt;/p&gt;</description>
    </item>
    <item>
      <title>FastDFS使用入门</title>
      <link>http://localhost:1313/posts/linux/fastdfs-01/</link>
      <pubDate>Sat, 25 May 2019 10:03:52 +0000</pubDate>
      <guid>http://localhost:1313/posts/linux/fastdfs-01/</guid>
      <description>&lt;!-- more --&gt;&#xA;&lt;h2 id=&#34;介绍&#34;&gt;介绍&lt;/h2&gt;&#xA;&lt;p&gt;FastDFS是一个开源的分布式文件系统，主要有以下功能。&lt;/p&gt;&#xA;&lt;p&gt;分布式文件系统（Distributed File System）是指文件系统管理的物理存储资源不一定直接连接在本地节点上，而是通过计算机网络与节点相连。&lt;/p&gt;&#xA;&lt;p&gt;FastDFS主要有以下特点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;文件存储&lt;/li&gt;&#xA;&lt;li&gt;文件同步&lt;/li&gt;&#xA;&lt;li&gt;文件访问（上传、下载）&lt;/li&gt;&#xA;&lt;li&gt;存取负载均衡&lt;/li&gt;&#xA;&lt;li&gt;在线扩容&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;fastdfs的架构&#34;&gt;FastDFS的架构&lt;/h2&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog-1251613845.cos.ap-shanghai.myqcloud.com/1526205318630.png&#34; alt=&#34;1526205318630.png&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;由三个部分组成：Client，Tracker Server，Storage Server。&lt;/p&gt;&#xA;&lt;p&gt;Client是上传下载数据的服务器，Tracker Server是跟踪服务器，主要做调度工作，起到负载均衡，管理所有的Storage Server。Storage Server：存储服务器，主要提供容量和备份服务。&lt;/p&gt;&#xA;&lt;h2 id=&#34;fastdfs安装&#34;&gt;FastDFS安装&lt;/h2&gt;&#xA;&lt;h3 id=&#34;安装环境&#34;&gt;安装环境&lt;/h3&gt;&#xA;&lt;p&gt;操作系统：Ubuntu 18.04&lt;/p&gt;&#xA;&lt;h4 id=&#34;下载libfastcommon&#34;&gt;下载libfastcommon&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://github.com/happyfish100/libfastcommon/archive/V1.0.7.tar.gz&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;解压&#34;&gt;解压&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tar -zxvf V1.0.7.tar.gz&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd libfastcommon-1.0.7&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;编译-安装&#34;&gt;编译 安装&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./make.sh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./make.sh install&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;设置软链接&#34;&gt;设置软链接&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ln -s /usr/lib64/libfastcommon.so /usr/local/lib/libfastcommon.so&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ln -s /usr/lib64/libfastcommon.so /usr/lib/libfastcommon.so&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ln -s /usr/lib64/libfdfsclient.so /usr/local/lib/libfdfsclient.so&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ln -s /usr/lib64/libfdfsclient.so /usr/lib/libfdfsclient.so&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;安装fastdfs&#34;&gt;安装FastDFS&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://github.com/happyfish100/fastdfs/archive/V5.05.tar.gz&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tar -zxvf V5.05.tar.gz&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd fastdfs-5.05&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./make.sh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./make.sh install&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;配置tracker服务器&#34;&gt;&lt;strong&gt;配置Tracker服务器&lt;/strong&gt;&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /etc/fdfs&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp tracker.conf.sample tracker.conf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vim tracker.conf&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;修改&lt;code&gt;base_path&lt;/code&gt;为指定目录&lt;/p&gt;</description>
    </item>
    <item>
      <title>Mybatis学习笔记</title>
      <link>http://localhost:1313/posts/java%E5%9F%BA%E7%A1%80/mybatis-note/</link>
      <pubDate>Mon, 08 Apr 2019 13:44:13 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%9F%BA%E7%A1%80/mybatis-note/</guid>
      <description>&lt;h3 id=&#34;mybatis简介&#34;&gt;Mybatis简介&lt;/h3&gt;&#xA;&lt;p&gt;开源免费框架，原名叫iBatis&lt;/p&gt;&#xA;&lt;p&gt;作用：数据访问层框架，底层是对JDBC的封装&lt;/p&gt;&#xA;&lt;p&gt;优点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;使用mybatis时不需要编写实现类，只需要写执行的sql命令&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;mybatis简单使用&#34;&gt;Mybatis简单使用&lt;/h3&gt;&#xA;&lt;p&gt;mybatis-config.xml：全局配置文件&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34; ?&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;!DOCTYPE configuration&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;        PUBLIC &amp;#34;-//mybatis.org//DTD Config 3.0//EN&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;        &amp;#34;http://mybatis.org/dtd/mybatis-3-config.dtd&amp;#34;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;environments&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;default=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;default&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;environment&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;id=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;default&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;transactionManager&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;type=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JDBC&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;dataSource&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;type=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;POOLED&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;property&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;driver&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;value=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;com.mysql.jdbc.Driver&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;property&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;url&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;value=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;jdbc:mysql://localhost:3308/learnjsp?useSSL=false&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;property&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;value=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;root&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;property&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;value=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;root&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/dataSource&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/environment&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/environments&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;mappers&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;mapper&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;resource=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;UserMapper.xml&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/mappers&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;mapper.xml文件：编写需要执行的SQL命令，把XML文件理解成实现类&lt;/p&gt;&#xA;&lt;p&gt;UserMapper.xml：配置了sql语句，以及sql的封装规则&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34; ?&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;!DOCTYPE mapper&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;        PUBLIC &amp;#34;-//mybatis.org//DTD Mapper 3.0//EN&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;        &amp;#34;http://mybatis.org/dtd/mybatis-3-mapper.dtd&amp;#34;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;!--namespace:命名空间--&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;mapper&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;namespace=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;com.test.UserMapper&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;!--&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;    id:sql语句的唯一标识&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;    parameterType:定义参数类型&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;    resultType:返回值类型&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;    如果方法返回值返回的是list,在resultType中写List的泛型&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#{id}:外部传入的参数&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;    --&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;select&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;id=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;selectUser&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;resultType=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;com.test.model.User&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        select uid,uname,pwd,sex,age from t_user where id = #{id}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/select&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/mapper&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;测试&lt;/p&gt;</description>
    </item>
    <item>
      <title>Spring学习笔记（一）</title>
      <link>http://localhost:1313/posts/java%E5%9F%BA%E7%A1%80/spring01/</link>
      <pubDate>Thu, 14 Mar 2019 20:15:42 +0000</pubDate>
      <guid>http://localhost:1313/posts/java%E5%9F%BA%E7%A1%80/spring01/</guid>
      <description>&lt;h1 id=&#34;基础&#34;&gt;基础&lt;/h1&gt;&#xA;&lt;h2 id=&#34;spring介绍&#34;&gt;Spring介绍&lt;/h2&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Spring是一个开源框架。&lt;/li&gt;&#xA;&lt;li&gt;Spring为简化企业级应用开发而生，使用Spring可以使简单的JavaBean实现以前只有EJB才能实现的功能。&lt;/li&gt;&#xA;&lt;li&gt;Spring是一个IOC(DI)和AOP容器框架。&lt;/li&gt;&#xA;&lt;li&gt;轻量级：Spring是非侵入式的-基于Spring开发的应用中的对象可以不依赖于Spring的API&lt;/li&gt;&#xA;&lt;li&gt;依赖注入(DI)：Dependency Injection，IOC&lt;/li&gt;&#xA;&lt;li&gt;面向切面编程（AOP-aspect oriented programming）&lt;/li&gt;&#xA;&lt;li&gt;容器：Spring是一个容器，因为它包含并且管理应用对象的生命周期&lt;/li&gt;&#xA;&lt;li&gt;框架：Spring实现了使用简单的组件配置组合成一个复杂的应用，在Spring中可以使用XML和Java注解组合这些对象。&lt;/li&gt;&#xA;&lt;li&gt;一站式：在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方类库&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;核心特性&#34;&gt;核心特性&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;IoC容器&lt;/li&gt;&#xA;&lt;li&gt;Spring事件&lt;/li&gt;&#xA;&lt;li&gt;资源管理&lt;/li&gt;&#xA;&lt;li&gt;国际化&lt;/li&gt;&#xA;&lt;li&gt;校验&lt;/li&gt;&#xA;&lt;li&gt;数据绑定&lt;/li&gt;&#xA;&lt;li&gt;类型转换&lt;/li&gt;&#xA;&lt;li&gt;Spring表达式&lt;/li&gt;&#xA;&lt;li&gt;面向切面编程&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;ioc和di&#34;&gt;IOC和DI&lt;/h3&gt;&#xA;&lt;p&gt;IOC（Inversion of Control）：其思想是反转资源获取的方向。&lt;/p&gt;&#xA;&lt;p&gt;传统的资源查找方式要求组件向容器发起请求查找资源，作为回应，容器适时的返回资源，而应用了IOC之后，则是容器主动地将资源推送给它所管理的组件，组件所要做的仅是选择一种合适的方式来接受资源，这种行为 也被称为查找的被动形式。&lt;/p&gt;&#xA;&lt;p&gt;IoC容器的职责：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;依赖处理&#xA;&lt;ul&gt;&#xA;&lt;li&gt;依赖查找&lt;/li&gt;&#xA;&lt;li&gt;依赖注入&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;生命周期管理&#xA;&lt;ul&gt;&#xA;&lt;li&gt;容器&lt;/li&gt;&#xA;&lt;li&gt;托管的资源&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;配置&#xA;&lt;ul&gt;&#xA;&lt;li&gt;容器&lt;/li&gt;&#xA;&lt;li&gt;外部化配置&lt;/li&gt;&#xA;&lt;li&gt;托管资源&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;DI：IOC的另一种表述方式，即组件以一些预先定义好的方式（例如：setter方法）接受来自如容器的资源注入，相对于IOC而言，这种表述更直接。&lt;/p&gt;&#xA;&lt;h3 id=&#34;配置bean&#34;&gt;配置Bean&lt;/h3&gt;&#xA;&lt;p&gt;配置形式：基于XML文件的方式，基于注解的方式&lt;/p&gt;&#xA;&lt;p&gt;Bean的配置方式：通过全类名（反射），通过工厂方法（静态工厂方法&amp;amp;实例工厂方法），FactoryBean&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;beans&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;xmlns=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://www.springframework.org/schema/beans&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;xmlns:xsi=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://www.w3.org/2001/XMLSchema-instance&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;!--配置Bean--&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;bean&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;id=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;helloWorld&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;class=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HelloWorld&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;property&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;value=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Spring&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/bean&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;/beans&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;class：bean的全类名，通过反射的方式在IOC容器中创建bean，所以要求bean要有无参构造器&lt;/p&gt;&#xA;&lt;p&gt;id：标识容易中的bean，id唯一&lt;/p&gt;&#xA;&lt;p&gt;Spring提供了两种类型的IOC容器实现：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;BeanFactory：IOC容器的基本实现&lt;/li&gt;&#xA;&lt;li&gt;ApplicationContext 提供了更多的高级特大型，是BeanFactory的子接口&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;BeanFactory是Spring框架的基础设施，面向Spring本身&lt;/p&gt;&#xA;&lt;p&gt;ApplicationContext 面向使用Spring框架的开发者，几乎所有的应用场合都直接使用ApplicationContext&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ApplicationContext ctx &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; ClassPathXmlApplicationContext(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;applicationContext.xml&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HelloWorld helloWorld &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (HelloWorld) ctx.&lt;span style=&#34;color:#a6e22e&#34;&gt;getBean&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;helloWorld&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;利用id定位到IOC容器中的Bean&lt;/p&gt;</description>
    </item>
    <item>
      <title>PHP-Challenge-1</title>
      <link>http://localhost:1313/posts/web%E5%AE%89%E5%85%A8/php-challenge-1/</link>
      <pubDate>Sat, 01 Dec 2018 19:48:06 +0000</pubDate>
      <guid>http://localhost:1313/posts/web%E5%AE%89%E5%85%A8/php-challenge-1/</guid>
      <description></description>
    </item>
    <item>
      <title>PHP数组整数键名截断问题</title>
      <link>http://localhost:1313/posts/web%E5%AE%89%E5%85%A8/phpbug-69892/</link>
      <pubDate>Fri, 23 Nov 2018 17:02:35 +0000</pubDate>
      <guid>http://localhost:1313/posts/web%E5%AE%89%E5%85%A8/phpbug-69892/</guid>
      <description></description>
    </item>
    <item>
      <title>PHP弱类型产生的安全问题</title>
      <link>http://localhost:1313/posts/web%E5%AE%89%E5%85%A8/php-weak-type/</link>
      <pubDate>Fri, 09 Nov 2018 11:00:15 +0000</pubDate>
      <guid>http://localhost:1313/posts/web%E5%AE%89%E5%85%A8/php-weak-type/</guid>
      <description></description>
    </item>
    <item>
      <title>理解PHP变量覆盖漏洞</title>
      <link>http://localhost:1313/posts/web%E5%AE%89%E5%85%A8/php-audit-cover/</link>
      <pubDate>Thu, 01 Nov 2018 11:32:14 +0000</pubDate>
      <guid>http://localhost:1313/posts/web%E5%AE%89%E5%85%A8/php-audit-cover/</guid>
      <description></description>
    </item>
    <item>
      <title>浅析文件上传漏洞</title>
      <link>http://localhost:1313/posts/web%E5%AE%89%E5%85%A8/uploadvul/</link>
      <pubDate>Mon, 01 Oct 2018 21:05:56 +0000</pubDate>
      <guid>http://localhost:1313/posts/web%E5%AE%89%E5%85%A8/uploadvul/</guid>
      <description></description>
    </item>
    <item>
      <title>南京邮电大学CTF平台Web系列WriteUp</title>
      <link>http://localhost:1313/posts/web%E5%AE%89%E5%85%A8/nctf/</link>
      <pubDate>Mon, 25 Jun 2018 14:10:49 +0000</pubDate>
      <guid>http://localhost:1313/posts/web%E5%AE%89%E5%85%A8/nctf/</guid>
      <description></description>
    </item>
    <item>
      <title>你好世界</title>
      <link>http://localhost:1313/posts/%E9%9A%8F%E7%AC%94/hello-world/</link>
      <pubDate>Thu, 14 Jun 2018 19:34:14 +0000</pubDate>
      <guid>http://localhost:1313/posts/%E9%9A%8F%E7%AC%94/hello-world/</guid>
      <description></description>
    </item>
    <item>
      <title>About</title>
      <link>http://localhost:1313/about/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://localhost:1313/about/</guid>
      <description>&lt;p&gt;Email：&lt;a href=&#34;mailto:evl1nker4@gmail.com&#34;&gt;evl1nker4@gmail.com&lt;/a&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Talk is cheap, show me the code.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Too young too simple, sometimes naive.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;知其然知其所以然。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;博客于2018年夏季搭建，用来记录在CS领域的学习成长之路。&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;对于时代而言，个人只是区区沙砾，对于个人而言，时代就是他的全部，生活中的点点滴滴、喜怒哀乐、成长经验等数据，构成了独一无二的人，这些都值得记录下来。&lt;/p&gt;&lt;/blockquote&gt;</description>
    </item>
    <item>
      <title>Links</title>
      <link>http://localhost:1313/links/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>http://localhost:1313/links/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://zgq.me/&#34;&gt;ZGQ&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.mssail.com/&#34;&gt;Orange&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://d-veda.top/&#34;&gt;D-Veda&lt;/a&gt;&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
