<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on 边个濑椰的博客</title><link>https://ottercoconut.github.io/post/</link><description>Recent content in Posts on 边个濑椰的博客</description><generator>Hugo -- gohugo.io</generator><language>zh-CN</language><lastBuildDate>Wed, 24 Jun 2026 11:02:00 +0800</lastBuildDate><atom:link href="https://ottercoconut.github.io/post/index.xml" rel="self" type="application/rss+xml"/><item><title>TOEFL Writing</title><link>https://ottercoconut.github.io/p/toefl-writing/</link><pubDate>Wed, 24 Jun 2026 11:02:00 +0800</pubDate><guid>https://ottercoconut.github.io/p/toefl-writing/</guid><description>&lt;h1 id="托福写作"&gt;托福写作
&lt;/h1&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;题型&lt;/th&gt;
					&lt;th style="text-align: left"&gt;分值&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;Build a Sentence&lt;/td&gt;
					&lt;td style="text-align: left"&gt;10&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;Write an Email&lt;/td&gt;
					&lt;td style="text-align: left"&gt;5&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;Academic Discussion&lt;/td&gt;
					&lt;td style="text-align: left"&gt;5&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;

 &lt;blockquote&gt;
 &lt;p&gt;自2026.1.21托福改革后，“综合写作”取消，“学术写作”保留，新增了“造句”和“邮件”两种新题型。下面的内容，均总结自B站Vince9120的视频&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;a class="link" href="https://www.bilibili.com/video/BV1zrEr6cELz" target="_blank" rel="noopener"
 &gt;2026新托福写作：Build a Sentence 句子排序 句子重组 造句 组句&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="build-a-sentence"&gt;Build A Sentence
&lt;/h2&gt;&lt;p&gt;共10道题，需在6分50秒之内完成答题。&lt;/p&gt;
&lt;h3 id="分析情景"&gt;分析情景
&lt;/h3&gt;&lt;p&gt;题目首先有一句情景句来模拟对话的场景。比如：The printer in the library keeps jamming. What should I do?&lt;br&gt;
下面是需要填写的单词和空格，需要把单词按正确的顺序拖拽到空格中完成情景中的回答。我们作答的部分可能会有已有的提示词，也可能没有，即全是空格。此外，可选词的数量也可能比空格的数量更多。比如：
___ ___ ___ ___ ___ ___ ___ right now.&lt;br&gt;
需要填的词有：could, ask, for, help, you, IT service desk, the&lt;/p&gt;
&lt;p&gt;那么这题干的情景句，有以下三种类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特殊疑问句&lt;/strong&gt; (Wh- Questions): Why didn&amp;rsquo;t you attend your morning class?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;一般疑问句&lt;/strong&gt; (Yes/No Questions): Are you planning to attend the conference next month?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;陈述句 / 信息分享&lt;/strong&gt; (Statements):The university&amp;rsquo;s conference on climate change was very informative.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;那么我们可以按照下面的顺序作答：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;确定语序&lt;/strong&gt;：根据题干情景句的类型，可以确认回答句应该是陈述句或者疑问句，从而确定语序。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;确定主语&lt;/strong&gt;：根据可选词的词性，结合题干，从而确定主语&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;确定时态 / 确定意思&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="锚定主句"&gt;锚定主句
&lt;/h3&gt;&lt;p&gt;基本上，主句分为：主谓 / 主谓宾 / 主系表 这三种句式。
那么我们可以按照下面的顺序作答：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;确定主语&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;确定谓语&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;确定宾语 / 表语&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;主语&lt;/strong&gt;：&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;类别&lt;/th&gt;
					&lt;th style="text-align: left"&gt;示例内容&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;名词 (Nouns)&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;The manager&lt;br&gt;The budget reports&lt;br&gt;Students&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;代词 (Pronouns)&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;I, you, he/she/it, they, we, this/that.&lt;br&gt;me, you, him/her/it, them, us, this/that / myself&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;Doing / To do&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;[ Reading books ] is fun.&lt;br&gt;[ To learn English ] takes time.&lt;br&gt;I like [ to learn English ]&lt;br&gt;I like [ learning English ]&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;名词性从句 Noun Clauses&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;[ What he said ] made me angry.&lt;br&gt;I don&amp;rsquo;t understand [ What he said ]&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;谓语&lt;/strong&gt;：&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;类别&lt;/th&gt;
					&lt;th style="text-align: left"&gt;结构/形式&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;时态&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;do/does&lt;br&gt;be doing&lt;br&gt;did&lt;br&gt;will do / be going to do&lt;br&gt;have done / had done&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;情态&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;can / could / may / might / shall / should + do&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;语态&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;be done&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;be动词单独出现&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;is/am/are/was/were&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;例题：&lt;/p&gt;
&lt;p&gt;Did you enjoy the student film festival?
___ ___ ___ ___ ___ ___ me.
movies, to, the, none of, were, of interest&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;按照词性判断，主语只能是 movies, 谓语只能是 were, 表语只能是 of interest。&lt;/li&gt;
&lt;li&gt;那么答案应该是：None of movies were of interest to me.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="定位从句"&gt;定位从句
&lt;/h3&gt;&lt;p&gt;从句类型有名词性从句、定语从句、状语从句（不常考），那么我们可以按照下面的顺序作答：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;确定从句类型&lt;/li&gt;
&lt;li&gt;确定从句连词&lt;/li&gt;
&lt;li&gt;确定从句语序&lt;/li&gt;
&lt;li&gt;确定从句时态&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;从句类型&lt;/th&gt;
					&lt;th style="text-align: left"&gt;引导词/连接词&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;名词性从句&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;if / whether&lt;br&gt;that&lt;br&gt;what, where, when, why, who, how&lt;br&gt;whatever, wherever, whenever, however, whoever&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;定语从句&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;that/which/who/whom/where/when/why&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;状语从句&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;because/since/when/while/if &amp;hellip;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;大致可以这么判断：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;know, tell, ask, see, wonder + 宾语从句&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;介词 (in/on/at&amp;hellip;) + 宾语从句&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;名词 + 定语从句&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;句尾/句首 - 状语从句&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;名词性从句&lt;/strong&gt;：&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;句子结构情况&lt;/th&gt;
					&lt;th style="text-align: left"&gt;引导词&lt;/th&gt;
					&lt;th style="text-align: left"&gt;功能/含义&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;主谓宾完整&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;that&lt;/td&gt;
					&lt;td style="text-align: left"&gt;肯定事实&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;If / whether&lt;/td&gt;
					&lt;td style="text-align: left"&gt;不确定/是否&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;when, where, why, how&lt;/td&gt;
					&lt;td style="text-align: left"&gt;补充背景信息&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;缺少主语/宾语/表语&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;what, who, which+名词, whose+名词&lt;/td&gt;
					&lt;td style="text-align: left"&gt;指代某人某事&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定语从句&lt;/strong&gt;：&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;名词（先行词）&lt;/th&gt;
					&lt;th style="text-align: left"&gt;连词&lt;/th&gt;
					&lt;th style="text-align: left"&gt;从句内部结构&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;人 (Person)&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;who / that (宾语可用 whom)&lt;/td&gt;
					&lt;td style="text-align: left"&gt;缺主语 / 宾语/表语&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;物 (Thing)&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;which / that&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;地点 (Place)&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;where = in/at which&lt;/td&gt;
					&lt;td style="text-align: left"&gt;主谓宾完美无缺&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;时间 (Time)&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;when = on/in which&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;原因 (reason)&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;why = for which&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;如何区分 if 引导的从句类型&lt;/strong&gt;：&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;类型&lt;/th&gt;
					&lt;th style="text-align: left"&gt;特征与规则&lt;/th&gt;
					&lt;th style="text-align: left"&gt;示例&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;名词性从句&lt;/strong&gt;&lt;br&gt;(当宾语)&lt;/td&gt;
					&lt;td style="text-align: left"&gt;- 前面有 &lt;strong&gt;know, ask, wonder&lt;/strong&gt; 等&lt;br&gt;- &lt;strong&gt;if&lt;/strong&gt; 后跟陈述语序&lt;br&gt;- 可用 &lt;strong&gt;whether&lt;/strong&gt; 替换&lt;/td&gt;
					&lt;td style="text-align: left"&gt;I wonder if she will come.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;状语从句&lt;/strong&gt;&lt;br&gt;(表条件)&lt;/td&gt;
					&lt;td style="text-align: left"&gt;- 前面是主句，表条件&lt;br&gt;- &lt;strong&gt;if&lt;/strong&gt; 后跟完整主谓宾&lt;br&gt;- &lt;strong&gt;不能&lt;/strong&gt;用 whether 替换&lt;/td&gt;
					&lt;td style="text-align: left"&gt;If she comes, I will tell you.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;前面的动词是 &lt;strong&gt;know / ask / wonder / tell&amp;hellip;&lt;/strong&gt; → &lt;strong&gt;if&lt;/strong&gt; 就是引导宾语从句&lt;/p&gt;
&lt;p&gt;例题：&lt;/p&gt;
&lt;p&gt;My sister ___ ___ ___ ___ ___ ___
can, suggest, one, that, you, might interest, be&lt;/p&gt;
&lt;p&gt;先确定主句：My sister can suggest one &amp;hellip;
one这里是代词，代指一本书，后面可以加定语从句。剩下的词当中，you的位置比较重要，应该是放在 interest 之后作宾语。若放在从句主语的位置则语义不通。
答案应该是：My sister can suggest one that might interest you.&lt;/p&gt;
&lt;h3 id="检查修饰语"&gt;检查修饰语
&lt;/h3&gt;&lt;p&gt;那么我们可以按照下面的顺序作答：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;检查定语&lt;/li&gt;
&lt;li&gt;检查状语&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定语&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;分类&lt;/th&gt;
					&lt;th style="text-align: left"&gt;内容 / 示例&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;限定词&lt;/td&gt;
					&lt;td style="text-align: left"&gt;a/an/the&lt;br&gt;this/my&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;数量词&lt;/td&gt;
					&lt;td style="text-align: left"&gt;one/two&lt;br&gt;first/second&lt;br&gt;numerous&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;介词短语&lt;/td&gt;
					&lt;td style="text-align: left"&gt;the impact of &amp;hellip;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;doing / done / to do 短语&lt;/td&gt;
					&lt;td style="text-align: left"&gt;Information stored on computers&lt;br&gt;man sitting under the tree&lt;br&gt;the best way to prevent this&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;形容词短语&lt;/td&gt;
					&lt;td style="text-align: left"&gt;Materials suitable for construction&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;名词/形容词&lt;/td&gt;
					&lt;td style="text-align: left"&gt;climate change&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;doing/done单独&lt;/td&gt;
					&lt;td style="text-align: left"&gt;increasing pressure&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;定语从句&lt;/td&gt;
					&lt;td style="text-align: left"&gt;The technology that was developed&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;句中状语&lt;/strong&gt; 频度 / 程度 / 否定副词的位置&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;永远在实义动词前 或 be动词后。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;副词类型&lt;/th&gt;
					&lt;th style="text-align: left"&gt;常用词&lt;/th&gt;
					&lt;th style="text-align: left"&gt;位置规律&lt;/th&gt;
					&lt;th style="text-align: left"&gt;示例&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;频度副词&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;always / usually / often / sometimes / never&lt;/td&gt;
					&lt;td style="text-align: left"&gt;实义动词前，系动词后&lt;/td&gt;
					&lt;td style="text-align: left"&gt;He &lt;strong&gt;always&lt;/strong&gt; arrives on time.&lt;br&gt;She is &lt;strong&gt;usually&lt;/strong&gt; busy.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;程度副词&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;totally / almost / nearly / quite&lt;/td&gt;
					&lt;td style="text-align: left"&gt;助动词/be 后 + 实义动词前&lt;/td&gt;
					&lt;td style="text-align: left"&gt;I &lt;strong&gt;totally&lt;/strong&gt; agree.&lt;br&gt;They have &lt;strong&gt;almost&lt;/strong&gt; finished.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;否定副词&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;hardly / barely / rarely / seldom&lt;/td&gt;
					&lt;td style="text-align: left"&gt;助动词/be 后 + 实义动词前&lt;/td&gt;
					&lt;td style="text-align: left"&gt;I can &lt;strong&gt;hardly&lt;/strong&gt; hear you.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;句末状语&lt;/strong&gt; 副词 / 介词短语 / to do / 状语从句&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;多个句末状语共存时，一般顺序为：方式、地点、时间。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;状语类型&lt;/th&gt;
					&lt;th style="text-align: left"&gt;功能&lt;/th&gt;
					&lt;th style="text-align: left"&gt;示例&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;副词 (方式)&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;说明动作方式&lt;/td&gt;
					&lt;td style="text-align: left"&gt;He solved the problem easily.&lt;br&gt;She goes to school by bus.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;介词短语&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;地点 / 时间 / 方式&lt;/td&gt;
					&lt;td style="text-align: left"&gt;They are playing in the park.&lt;br&gt;The meeting starts at 3 PM.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;to do 短语&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;目的 / 结果&lt;/td&gt;
					&lt;td style="text-align: left"&gt;I went to the store to buy milk.&lt;br&gt;She studied hard to pass the exam.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;状语从句&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;时间 / 条件 / 原因等&lt;/td&gt;
					&lt;td style="text-align: left"&gt;I will call you when I arrive.&lt;br&gt;He speaks so fast that I can&amp;rsquo;t catch him.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;例题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Why didn&amp;rsquo;t you attend the campus fair last night?
We went to the restaurant that (opened downtown recently) / (recently opened downtown).
可见副词 &amp;ldquo;recently&amp;rdquo; 前置或者后置，语法都是正确的，前置修饰 &amp;ldquo;opened&amp;rdquo; 后置修饰 &amp;ldquo;went&amp;rdquo; 或者 &amp;ldquo;opened&amp;rdquo;。
但是关注语境可以发现，问题问 &amp;ldquo;last night&amp;rdquo; 那么回答中，&amp;ldquo;recently&amp;rdquo; 后置就会在语义上奇怪。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Why did the university administration email us about our upcoming conference?
They wanted ___ ___ ___ ___ ___.
confirmed so, far, to know, which speakers, have been
&amp;ldquo;so far&amp;rdquo; 连起来作为时间可以放到句末，&amp;ldquo;wanted&amp;rdquo; 后跟 &amp;ldquo;to know&amp;rdquo;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="academic-discussion"&gt;Academic Discussion
&lt;/h2&gt;&lt;h3 id="intro"&gt;Intro
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Questions Types&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Evaluation&lt;/li&gt;
&lt;li&gt;Comparison&lt;/li&gt;
&lt;li&gt;Solution&lt;/li&gt;
&lt;li&gt;Argument&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Topics&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Education&lt;/li&gt;
&lt;li&gt;Work&lt;/li&gt;
&lt;li&gt;Environment&lt;/li&gt;
&lt;li&gt;Tech&lt;/li&gt;
&lt;li&gt;Urban Development&lt;/li&gt;
&lt;li&gt;Economy&lt;/li&gt;
&lt;li&gt;Social Issues&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="steps"&gt;Steps
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Topic&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;120-180 words of relevant discussion with reasoning, example, and preferably concession.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Coherence&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Clear topic, flow of idea, and connection between sentences&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Language&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Various, accurate, and natural&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Grammar&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;A mix of simple and complex sentences, preferably with attributive clauses and participles&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="prompt"&gt;Prompt
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;例文：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From my perspective, social media companies should regulate their platforms themselves rather than governments since it is the most effective way to build up tailored regulation systems.&lt;/p&gt;
&lt;p&gt;To be more specific, social media companies are familiar with the environment of the platforms and have a better understanding of which areas may present potential issues. Therefore, when it comes to bad content from the users, these companies could react on it quickly, minimizing the negative impact.&lt;/p&gt;
&lt;p&gt;For example, social media companies like Reddit have dedicated departments to monitor different parts of platforms real-time, which enables the rules to be obeyed meticulously. Moreover, these companies can analyze such negative user behaviors and then refine their regulation systems, creating tailored approaches.&lt;/p&gt;
&lt;p&gt;Still, some might claim that allowing the companies to manage themselves lacks fairness, as different companies may set varying standards. However, governments can provide broad guidelines to ensure that these platforms align with public interests, while also allow businesses some flexibility to implement specific measures based on their unique platforms and users.&lt;/p&gt;
&lt;h4 id="structure"&gt;Structure
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;Structure 1: Point &amp;amp; Elaboration + Further Elaboration + Example + Concession&lt;/li&gt;
&lt;li&gt;Structure 2 : Point &amp;amp; Elaboration + Further Elaboration +Second Point &amp;amp; Elaboration + Further Elaboration&lt;/li&gt;
&lt;li&gt;Structure 3 : Point &amp;amp; Elaboration + Further Elaboration + Full Concession&lt;/li&gt;
&lt;li&gt;Structure 4 : Point &amp;amp; Elaboration + Further Elaboration + Sublimation&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="comparison"&gt;Comparison
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Which&lt;/strong&gt; approach do you think is &lt;strong&gt;better&lt;/strong&gt;: assessing students based only on their performance, &lt;strong&gt;OR&lt;/strong&gt; also based on their effort?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;One&lt;/strong&gt; proposal is to…
&lt;strong&gt;The other&lt;/strong&gt; is to…
&lt;strong&gt;Which&lt;/strong&gt; proposal do you think is &lt;strong&gt;better&lt;/strong&gt;? Why?&lt;/li&gt;
&lt;li&gt;What is the best way to evaluate teachers: Students’ test scores? Students’ feedback? Other teachers’ evaluation?
&lt;strong&gt;Which&lt;/strong&gt; is the &lt;strong&gt;best&lt;/strong&gt; and why?&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="evaluation"&gt;Evaluation
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;What is your opinion on gap year? Does it bring &lt;strong&gt;more advantages or disadvantages&lt;/strong&gt; to students?&lt;/li&gt;
&lt;li&gt;Do you think it&amp;rsquo;s a &lt;strong&gt;good idea&lt;/strong&gt; for very young children to play educational computer games? Why or why not?&lt;/li&gt;
&lt;li&gt;Is journal writing a &lt;strong&gt;worthwhile&lt;/strong&gt; activity to support learning? Why or why not?&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="argument"&gt;Argument
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;Do you think ongoing job training is the most important investment a business can make?&lt;/li&gt;
&lt;li&gt;Will people have more free time and be able to enjoy more leisure activities in the future?&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="solution"&gt;Solution
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;What is the biggest mistake that people make when it comes to the purchase of tech products?&lt;/li&gt;
&lt;li&gt;In what area should the government reduce its spending for a budget cut?&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="point--elaboration"&gt;Point &amp;amp; Elaboration
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Example&lt;/strong&gt;：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Prof. : Which approach do you think is better:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;assessing students based only on their performance;&lt;/li&gt;
&lt;li&gt;or also based on their effort?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Student1 : Effort - learn something, will benefit them in their future life.&lt;/p&gt;
&lt;p&gt;Student2 : Performance - fair&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Common Points in Education&lt;/strong&gt; :
&lt;ul&gt;
&lt;li&gt;Academic development / Effectiveness of study&lt;/li&gt;
&lt;li&gt;Personal development / Career development&lt;/li&gt;
&lt;li&gt;Teamworking and communication skills&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="point-template"&gt;Point Template
&lt;/h4&gt;&lt;p&gt;I believe that … / I firmly hold the idea that … / In my opinion, … / As far as I am concerned, … / It is obvious that …&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Practical experience will greatly promote / hinder students’ academic development &lt;strong&gt;as&lt;/strong&gt; they can deepen their understanding in their field of study. (25)&lt;/li&gt;
&lt;li&gt;The overuse of technology will have a positive / negative impact on our personal development &lt;strong&gt;since&lt;/strong&gt; it will hinder our independent thinking. (29)&lt;/li&gt;
&lt;li&gt;We shall definitely prioritize economic development over environmental protection &lt;strong&gt;due to the fact that&lt;/strong&gt; a stable economy is the very foundation of social, scientific, and industrial development. (31)&lt;/li&gt;
&lt;li&gt;The fact that discussion involves active exchange of ideas between participants &lt;strong&gt;indicates that&lt;/strong&gt; such style of learning drives us to strengthen our communication skills. (24)&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="how-to-point"&gt;How to Point
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;I think score is good for students because they learn knowledge.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I believe grading shall focus on students’ performance on assignments and tests, &lt;strong&gt;since&lt;/strong&gt; it is the most effective way to measure the progress in their study. (27)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I believe effort is important because experience is good.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In my opinion, effort is an important element to be considered in study and grading &lt;strong&gt;due to the fact that&lt;/strong&gt; students learn from both what they have done right and what they have done wrong. (31)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="elaboration-template"&gt;Elaboration Template
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;To be more specific&lt;/strong&gt;, during a discussion, students not only have to come up with their own thoughts but also consider those from others, which stimulates an active way of thinking.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;To elaborate&lt;/strong&gt;, practical experience will help students witness the true nature of a job instead of developing some random imagination based on their limited experience, developing a real passion in their field of study.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;In other words&lt;/strong&gt;, it is only in a prosperous, stable, and developed society that we can allocate extra resources to implement the protection of the environment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;More specifically&lt;/strong&gt;, instead of thinking and analyzing a problem, people might rely on technology to search for quick answers to every question they have in life and study.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="how-to-elaborate"&gt;How to Elaborate
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;I believe effort is important because experience is good. As far as I am concerned, the fact that students learn from both good and bad results in study indicates that effort is an important element to be considered in study and grading. (33)
&lt;ul&gt;
&lt;li&gt;To elaborate, students not only gain academic knowledge from a correct understanding of class materials, but also obtain a stronger resilience and judgment power through their mistakes, developing both technical and life skills. (35)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="more-examples"&gt;More Examples
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Do you think ongoing job training is the most important investment a business can make?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It is certain that&lt;/strong&gt; ongoing job training is an essential part of business &lt;strong&gt;because&lt;/strong&gt; it helps employees to stay competitive in today’s rapidly changing world. (27)
&lt;strong&gt;To be more specific&lt;/strong&gt;, instead of relying on outdated skillsets, ongoing job training not only provides employees an insight into advanced strategies but also equip them with competitive technical skills, &lt;strong&gt;which&lt;/strong&gt; in turn helps the company to keep vibrant. (39)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;What is the biggest mistake that people make when it comes to purchase of tech products?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The biggest mistake in the purchase of tech products is that consumers almost always pay for what they do not need &lt;strong&gt;since&lt;/strong&gt; people are easily misled by advertisements. (28)
To elaborate, TV and internet commercials usually illustrate the most sophisticated and powerful functions of high-tech products in an exaggerated manner, &lt;strong&gt;which&lt;/strong&gt; are unfortunately rarely needed. (26)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="example"&gt;Example
&lt;/h3&gt;&lt;h4 id="substantiation"&gt;Substantiation
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;Focused on topic&lt;/li&gt;
&lt;li&gt;Factual illustration&lt;/li&gt;
&lt;li&gt;Good language&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="how-to-make-a-substantiation"&gt;How to make a Substantiation
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;To be more specific, performance on assignments and tests best reflect students’ understanding of academic concepts and their problem-solving skills, which are also the objective of most courses. (29)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;For example&lt;/strong&gt;, the score on a mathematics test indicates if the student has completely understood formulas and theories, and if they can apply them in various conditions. (27)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Electronic devices help students on their study.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;For example&lt;/strong&gt;, students can find different ways of thinking for whatever questions they have with their mobile phones wherever they are, greatly broadening their mind. (25)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="story-telling"&gt;Story Telling
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;Focused on topic&lt;/li&gt;
&lt;li&gt;Vivid with relevant details&lt;/li&gt;
&lt;li&gt;Good language&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="how-to-tell-a-story"&gt;How to Tell a Story
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Electronic devices help students on their study.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;For instance&lt;/strong&gt;, last week, my little niece had a homework. She used her mobile phone to search for information on the internet. Finally, she got a good grade.&lt;/li&gt;
&lt;li&gt;For instance, last week, my little niece had a homework &lt;strong&gt;from her biology class&lt;/strong&gt;. She used her mobile phone to search for &lt;strong&gt;diverse&lt;/strong&gt; information on the internet. Finally, she got a good grade &lt;strong&gt;for the excellent work&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;For instance, last week, my little niece had a homework &lt;strong&gt;from her biology class about animal behaviors&lt;/strong&gt;. &lt;strong&gt;Instead of relying on limited knowledge on books&lt;/strong&gt;, she used her mobile phone to search for diverse information on the internet, &lt;strong&gt;including why and how animals play, which earned her a good grade for the excellent work&lt;/strong&gt;. (54)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;What is the biggest mistake that people make when it comes to the purchase of tech products?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The biggest mistake in the purchase of tech products is that&lt;/strong&gt; consumers almost always pay for what they do not need &lt;strong&gt;since&lt;/strong&gt; people are easily misled by advertisements. (28) &lt;strong&gt;To elaborate&lt;/strong&gt;, TV and internet commercials usually illustrate the most sophisticated and powerful functions of high-tech products in an exaggerated manner, &lt;strong&gt;which&lt;/strong&gt; are unfortunately rarely needed. (26)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;For example&lt;/strong&gt;, commercials may demonstrate how a powerful laptop may solve all problems in our work and life, while we end up just using the expensive laptop with basic jobs such as editing texts and PowerPoint slides. (37)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="concession"&gt;Concession
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;Concede with students&amp;rsquo; point or a potential advantage.&lt;/li&gt;
&lt;li&gt;Refute with an obvious weakness.&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Admitting that another person is right about something.&lt;/li&gt;
&lt;li&gt;Proving that someone else is wrong about something.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="how-to-make-a-concession"&gt;How to make a Concession
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;Do you think ongoing job training is the most important investment a business can make?&lt;/li&gt;
&lt;li&gt;I don&amp;rsquo;t think so. Training takes a lot of money, and companies can hire new skilled employees.
&lt;ul&gt;
&lt;li&gt;Still, a voice arises that businesses can save money from training by recruiting new employees.
Ironically, even the most talented and skilled new employees will need time and training to best adapt themselves to a new environment, which is a lot of times more expensive than ongoing job training. (15+34)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;What is the biggest mistake that people make when it comes to the purchase of tech products?&lt;/li&gt;
&lt;li&gt;They often don&amp;rsquo;t consider the compatibility of software. The software we are used to might not work on the new device. It can be troublesome to learn new software.
&lt;ul&gt;
&lt;li&gt;Nevertheless, some state that the biggest mistake is that the software we are familiar with might not be compatible with the new tech products. However, with the development of computer science, software today can usually be used on multiple platforms. For example, PowerPoint can be used on both PC and Mac, and even on mobile devices. (24+32)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="ai-prompt"&gt;AI Prompt
&lt;/h3&gt;&lt;p&gt;（转自CSDN &lt;a class="link" href="https://blog.csdn.net/milk0618/article/details/141405341" target="_blank" rel="noopener"
 &gt;【TOEFL Prompt】1 学术讨论评分Prompt_prompt professor-CSDN博客&lt;/a&gt;）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;角色&lt;/strong&gt;
你是一位经验丰富的托福写作评分员，能够根据题目和回答，给出和ETS官方一致的分数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;任务&lt;/strong&gt;
下面请你对学术讨论写作任务进行评分，我将会给出题目材料以及回答，请你根据评分标准，以及过往的评分示例对我的回答进行评分，并给出指导意见。
其中，我给出的格式是：
[题目要求]：
[Professor]：
[Student A]：
[Student B]：
[回答]：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;回答格式&lt;/strong&gt;
[评分]：xx分（满分30分）
[指导意见]：1.xxx； 2.xxx； …
[回答思路]：
[示例范文]：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;评分标准&lt;/strong&gt;
&lt;strong&gt;Score 5&lt;/strong&gt;
A fully successful response
The response is a relevant and very clearly expressed contribution to the online discussion, and it demonstrates consistent facility in the use of language.
A typical response displays the following:
•	Relevant and well-elaborated explanations, exemplifications, and/or details
•	Effective use of a variety syntactic structures and precise, idiomatic word choice
•	Almost no lexical or grammatical errors other than those expected from a competent writer writing under timed conditions (e.g., common typos or common misspellings or substitutions like there/their)
&lt;strong&gt;Score 4&lt;/strong&gt;
A generally successful response
The response is a relevant contribution to the online discussion, and facility in the use of language allows the writer’s ideas to be easily understood.
A typical response displays the following:
•	Relevant and adequately elaborated explanations, exemplifications, and/or details
•	A variety of syntactic structures and appropriate word choice
•	Few lexical or grammatical errors
&lt;strong&gt;Score 3&lt;/strong&gt;
A partially successful response
The response is a mostly relevant and mostly understandable contribution to the online discussion, and there is some facility in the use of language.
A typical response displays the following:
•	Elaboration in which part of an explanation, example, or detail may be missing, unclear, or irrelevant
•	Some variety in syntactic structures and a range of vocabulary
•	Some noticeable lexical and grammatical errors in sentence structure, word form, or use of idiomatic language
&lt;strong&gt;Score 2&lt;/strong&gt;
A mostly unsuccessful response
The response reflects an attempt to contribute to the online discussion, but limitations in the use of language may make ideas hard to follow.
A typical response displays the following:
•	Ideas that may be poorly elaborated or only partially relevant
•	A limited range of syntactic structures and vocabulary
•	An accumulation of errors in sentence structure, word forms, or use
&lt;strong&gt;Score 1&lt;/strong&gt;
An unsuccessful response
The response reflects an ineffective attempt to contribute to the online discussion, and limitations in the use of language may prevent the expression of ideas.
A typical response may display the following:
•	Words and phrases that indicate an attempt to address the task but with few or no coherent ideas
•	Severely limited range of syntactic structures and vocabulary
•	Serious and frequent errors in the use of language
•	Minimal original language; any coherent language is mostly borrowed from the stimulus
&lt;strong&gt;Score 0&lt;/strong&gt;
The response is blank, rejects the topic, is not in English, is entirely copied from the prompt, is entirely unconnected to the prompt, or consists of arbitrary keystrokes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;要求&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;你必须遵照评分标准以及评分示例，对我的回答进行评分&lt;/li&gt;
&lt;li&gt;请一步一步进行思考，给出最接近ETS官方的评分结果&lt;/li&gt;
&lt;li&gt;在生成范文阶段，请务必遵照5分的评分标准进行写作&lt;/li&gt;
&lt;li&gt;我将支付$1000以获得更好的评分体验&lt;/li&gt;
&lt;li&gt;在提出修改意见的阶段，请你按照5分的评分标准进行提出。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;分数转换标准&lt;/strong&gt;
5分换算为30分， 4.75换算为29分， 4.5分换算为28分， 4.25分换算为27分， 4分换算为25分， 3.75分换算为24分， 3.50换算为22分， 3.25分换算为21分， 3分换算为20分， 2.75分换算为18分， 2.50分换算为17分， 2.25分换算为15分， 2分换算为14分， 1.75分换算为12分， 1.5分换算为11分， 1.25分换算为10分， 1分换算为8分。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;生成回答流程&lt;/strong&gt;
&lt;strong&gt;生成评分阶段&lt;/strong&gt;
每次评分时，你都必须扮演两个评分人，按照评分规则从0-5进行评分，注意你可以根据回答的质量给出包含小数点的分数。之后求取两个评分者的平均数，以获得更加公平的评分，最后根据分数转换标准将5分制的评分转换为30分制。
&lt;strong&gt;生成范文阶段&lt;/strong&gt;
每次你都必须生成三篇范文，每篇范文都必须依照5分A fully successful response的标准，以及具体的[题目要求]进行，最后，请你挑出最好的一篇进行呈现。 之后并呈现你的回答思路&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;现在请你根据下面材料进行评分&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;[题目要求]：（填充）
[Professor]：（填充）
[Student A]：（填充）
[Student B]：（填充）
[回答]：（填充）&lt;/p&gt;
&lt;hr&gt;</description></item><item><title>稀疏向量与 SPLADE 模型</title><link>https://ottercoconut.github.io/p/%E7%A8%80%E7%96%8F%E5%90%91%E9%87%8F%E4%B8%8E-splade-%E6%A8%A1%E5%9E%8B/</link><pubDate>Tue, 12 May 2026 16:17:17 +0800</pubDate><guid>https://ottercoconut.github.io/p/%E7%A8%80%E7%96%8F%E5%90%91%E9%87%8F%E4%B8%8E-splade-%E6%A8%A1%E5%9E%8B/</guid><description>&lt;h2 id="参考网站"&gt;参考网站
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/naver/splade" target="_blank" rel="noopener"
 &gt;Naver SPLADE 官方仓库&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://huggingface.co/naver/splade_v2_max" target="_blank" rel="noopener"
 &gt;naver/splade_v2_max 模型页&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.sbert.net/docs/package_reference/sparse_encoder/index.html" target="_blank" rel="noopener"
 &gt;Sentence Transformers Sparse Encoder 文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.sbert.net/docs/sparse_encoder/training_overview.html" target="_blank" rel="noopener"
 &gt;Sentence Transformers Sparse Encoder 训练概览&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://sbert.net/docs/sparse_encoder/usage/efficiency.html" target="_blank" rel="noopener"
 &gt;Sentence Transformers Sparse Encoder 推理加速&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="稀疏向量与-splade-模型"&gt;稀疏向量与 SPLADE 模型
&lt;/h1&gt;&lt;p&gt;在 RAG 系统里，dense vector 已经是最常见的召回方式。它把文本映射到连续向量空间中，适合捕捉语义相近的表达，例如“员工离职流程”和“人员退出手续”。但 dense vector 也有明显短板：它不一定擅长精确匹配实体、编号、术语、错误码、产品型号、表格字段名和代码片段。&lt;/p&gt;
&lt;p&gt;这时 sparse vector 就有价值了。它更像一个“神经网络增强版倒排索引”：文本仍然被表示为词项维度上的稀疏权重，但这些权重不是 BM25 这类纯统计方法算出来的，而是由模型预测出来的。&lt;/p&gt;
&lt;p&gt;简单说：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;dense vector 负责语义相似。&lt;/li&gt;
&lt;li&gt;BM25 负责原词匹配。&lt;/li&gt;
&lt;li&gt;SPLADE sparse vector 负责神经词项扩展后的加权匹配。&lt;/li&gt;
&lt;li&gt;Hybrid Search 则把 dense 和 sparse 两种召回结果融合起来。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="论文模型"&gt;论文模型
&lt;/h2&gt;&lt;p&gt;SPLADE 基于 Masked Language Model 的 logits，把一段文本映射到词表空间中。假设词表里有 30522 个 WordPiece token，那么每个文本最终可以表示为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;token_id -&amp;gt; weight
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;也就是一个稀疏向量。大部分 token 的权重为 0，只有少量被模型认为重要的 token 会有非零权重。&lt;/p&gt;
&lt;p&gt;这和普通 embedding 最大的区别是：dense embedding 的每一维通常不可解释，而 sparse vector 的维度就是词表 token。一个被模型激活的 token 可以理解为“这段文本与这个词项相关”。&lt;/p&gt;
&lt;p&gt;例如一段文档没有显式出现“报销”，但出现了“差旅费”“发票”“审批单”，SPLADE 可能会激活与“报销”相关的 token。这样在查询“报销流程”时，即便文档没有完全命中原词，也可能被召回。&lt;/p&gt;
&lt;p&gt;更具体地说，SPLADE 会利用 Masked Language Model 层的 logits，在 BERT WordPiece 词表中预测每个词项的重要性。假设输入文本在分词后是：&lt;/p&gt;
$$
t=(t_{1},t_{2},...,t_{N})
$$&lt;p&gt;对应的上下文表示是：&lt;/p&gt;
$$
(h_{1},h_{2},...,h_{N})
$$&lt;p&gt;那么对输入中第 $i$ 个 token，模型会计算它对词表中第 $j$ 个 token 的重要性：&lt;/p&gt;
$$
w_{ij}=transform(h_{i})^{T}E_{j}+b_{j}, \quad j\in\{1,...,|V|\}
$$&lt;p&gt;这里 $E_j$ 词表 ${token}_j$ 的 BERT 输入嵌入，$b_j$ 是 token 级偏置，&lt;code&gt;transform(.)&lt;/code&gt; 通常是带 GeLU 和 LayerNorm 的线性变换。直觉上，这一步是在问：输入里的这个位置，和词表里的每个词项分别有多相关。&lt;/p&gt;
&lt;p&gt;但检索时需要的不是“某个位置对某个词的分数”，而是“整段文本对某个词的分数”。因此 SPLADE 会把不同位置的激活聚合成整段文本的稀疏表示：&lt;/p&gt;
$$
w_{j}=\sum_{i\in t}\log(1+ReLU(w_{ij}))
$$&lt;p&gt;这个公式里有三层含义：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ReLU&lt;/code&gt; 把负分清零，只保留正向相关的词项。&lt;/li&gt;
&lt;li&gt;$log(1+x)$ 做对数饱和，避免高频词或重复词的分数被无限放大。&lt;/li&gt;
&lt;li&gt;$\sum$ 把不同位置对同一个词表 token 的激活累加起来，得到整段文本的词项权重。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最后，文本就变成了一个很高维但很稀疏的向量：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;token_id -&amp;gt; weight
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;查询和文档都映射到同一个词表空间后，检索分数就是稀疏向量点积：&lt;/p&gt;
$$
s(q,d)=\sum_j w_j^q w_j^d
$$&lt;p&gt;这也是 SPLADE 能接入倒排索引或稀疏向量索引的原因。&lt;/p&gt;
&lt;h3 id="排序损失"&gt;排序损失
&lt;/h3&gt;&lt;p&gt;训练时，SPLADE 要让相关文档得分更高，不相关文档得分更低。给定一个查询 $q_i$ 、一个正样本文档 $d_i^+$ 、一个困难负样本 $d_i^-$ ，以及一组批内负样本 ${d_{i,j}^{-}}$ ，可以使用类似下面的对比排序损失：&lt;/p&gt;
$$
\mathcal{L}_{rank-IBN} =
-\log
\frac{e^{s(q_i,d_i^+)}}
{e^{s(q_i,d_i^+)} + e^{s(q_i,d_i^-)} + \sum e^{s(q_i,d_{i,j}^{-})}}
$$&lt;p&gt;它的目标很直接：让正样本在候选集合里的概率尽可能大。工程上可以理解为，模型会不断学习哪些词项扩展能帮助它把正确文档排到前面。&lt;/p&gt;
&lt;h3 id="flops-稀疏正则"&gt;FLOPS 稀疏正则
&lt;/h3&gt;&lt;p&gt;如果只优化排序效果，模型可能会激活太多 token。这样虽然召回可能变强，但倒排索引会膨胀，查询时需要访问的 posting list 也会变多。&lt;/p&gt;
&lt;p&gt;因此 SPLADE 引入 FLOPS 正则来控制稀疏性。对一批文档来说，可以先估计词表 token (j) 在这批文档中的平均激活：&lt;/p&gt;
$$
\overline{a}_{j}=\frac{1}{N}\sum_{i=1}^{N}w_{j}^{(d_i)}
$$&lt;p&gt;然后对平均激活做平方求和：&lt;/p&gt;
$$
l_{FLOPS}=\sum_{j\in V}\overline{a}_{j}^{2}
=\sum_{j\in V}(\frac{1}{N}\sum_{i=1}^{N}w_{j}^{(d_i)})^{2}
$$&lt;p&gt;这个正则项不是简单控制“向量维度”，而是在控制非零 token 的数量和分布。它希望模型不要把大量文档都绑定到少数高频词上，也不要让每个文档都激活过多词项。&lt;/p&gt;
&lt;p&gt;因此，稀疏性权重可以理解为一个召回质量和检索成本之间的旋钮：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;权重更大：稀疏向量更短，索引更小，检索更快，但可能损失召回。&lt;/li&gt;
&lt;li&gt;权重更小：稀疏向量更长，扩展更丰富，但索引和检索成本更高。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="总体损失"&gt;总体损失
&lt;/h3&gt;&lt;p&gt;最终，SPLADE 会把排序损失和稀疏正则放在一起训练：&lt;/p&gt;
$$
\mathcal{L}=\mathcal{L}_{rank-IBN}
+\lambda_q\mathcal{L}_{reg}^{q}
+\lambda_d\mathcal{L}_{reg}^{d}
$$&lt;p&gt;其中 (\lambda_q) 控制查询侧稀疏性，(\lambda_d) 控制文档侧稀疏性。查询侧通常对延迟更敏感，所以查询侧稀疏性非常重要。文档侧可以离线计算，通常可以接受更高一点的计算成本，但仍然要控制索引体积。&lt;/p&gt;
&lt;h3 id="从求和到最大池化"&gt;从求和到最大池化
&lt;/h3&gt;&lt;p&gt;原始 SPLADE 会对输入文本中每个位置的词项预测进行聚合：&lt;/p&gt;
$$
w_{j}=\sum_{i\in t}\log(1+ReLU(w_{ij}))
$$&lt;p&gt;
后续更常见的 SPLADE-max 使用最大池化：&lt;/p&gt;
$$
w_{j}=\max_{i\in t}\log(1+ReLU(w_{ij}))
$$&lt;p&gt;
这并不是整段文本只保留一个 token，而是对词表里的每个维度分别取最大激活值。这样可以减少长文本或重复词带来的累加放大，让表示更关注“是否强烈激活某个语义词项”，而不是简单依赖出现次数。&lt;/p&gt;
&lt;h3 id="splade-doc-与蒸馏训练"&gt;SPLADE-doc 与蒸馏训练
&lt;/h3&gt;&lt;p&gt;标准 SPLADE 会同时编码 query 和 document。也就是说，查询侧和文档侧都可能产生神经扩展词项，检索时计算的是：&lt;/p&gt;
$$
s(q,d)=\sum_j w_j^q w_j^d
$$&lt;p&gt;SPLADE-doc 则更偏工程效率。它只在文档侧做 SPLADE 编码，查询侧通常只使用原始 query token，文档得分可以写成：&lt;/p&gt;
$$
s(q,d)=\sum_{j\in q}w_j^d
$$&lt;p&gt;这样文档侧扩展可以离线预计算，查询侧不需要跑 SPLADE encoder，延迟会更低。代价是 query 侧没有神经扩展能力，只能利用“文档侧扩展”。&lt;/p&gt;
&lt;p&gt;另外，很多效果较强的 SPLADE 模型会使用知识蒸馏和困难负样本。常见做法是先训练一个第一阶段检索器和 cross-encoder 重排器，再用更难的负样本和重排器分数继续训练。工程上不用自己复现这套训练流程，也能使用公开模型；但理解这一点有助于判断模型名称里 &lt;code&gt;distil&lt;/code&gt;、&lt;code&gt;ensemble&lt;/code&gt;、&lt;code&gt;cocondenser&lt;/code&gt; 这类词为什么会出现。&lt;/p&gt;
&lt;h3 id="稀疏性为什么重要"&gt;稀疏性为什么重要
&lt;/h3&gt;&lt;p&gt;如果模型把大量 token 都激活，召回效果也许会上升，但索引会变大，检索会变慢。SPLADE 使用 FLOPS 正则化来控制非零 token 的数量和分布。&lt;/p&gt;
&lt;p&gt;工程上可以把它理解为：稀疏向量不是越长越好。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;非零 token 太少：索引小、检索快，但召回可能不够。&lt;/li&gt;
&lt;li&gt;非零 token 太多：召回可能更好，但索引膨胀，检索成本上升。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;落地时通常还会做二次裁剪，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;只保留 top_k 个 token&lt;/li&gt;
&lt;li&gt;过滤 weight 低于阈值的 token&lt;/li&gt;
&lt;li&gt;限制单个 chunk 的最大稀疏维度数量&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些参数往往比模型本身更影响线上成本。&lt;/p&gt;
&lt;h2 id="模型选择"&gt;模型选择
&lt;/h2&gt;&lt;p&gt;SPLADE 更像一类稀疏神经检索方法，而不是单一模型。Naver 官方仓库也特别提醒：不同正则化强度会得到从“非常稀疏”到“强 query/doc 扩展”的不同模型，效果、索引大小和延迟都会变。&lt;/p&gt;
&lt;p&gt;如果只是想快速做工程验证，可以从 &lt;code&gt;naver/splade-cocondenser-ensembledistil&lt;/code&gt; 开始。它是官方 SPLADE++ 系列里常见的强效果模型，在 Naver 官方仓库列出的 MS MARCO dev MRR@10 为 38.3，高于 &lt;code&gt;splade_v2_max&lt;/code&gt; 的 34.0 和 &lt;code&gt;splade_v2_distil&lt;/code&gt; 的 36.8。它适合先验证 sparse 召回是否能补足 dense 的关键词、实体、术语召回缺口。&lt;/p&gt;
&lt;p&gt;如果更看重推理成本，可以看 &lt;code&gt;naver/splade_v2_max&lt;/code&gt; 或 efficient SPLADE 系列。&lt;code&gt;splade_v2_max&lt;/code&gt; 结构简单，Hugging Face 模型页标注为 DistilBERT base、512 token 最大长度、30522 维输出、点积相似度。efficient SPLADE 系列则进一步区分 document encoder 与 query encoder，目标是降低查询侧延迟。&lt;/p&gt;
&lt;p&gt;一个实用的选型顺序是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;先选一个效果强的公开模型做离线评测，例如 &lt;code&gt;naver/splade-cocondenser-ensembledistil&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;如果离线评测有效，再统计平均非零 token 数、索引大小、文档侧编码吞吐和查询侧 P95 延迟。&lt;/li&gt;
&lt;li&gt;如果查询侧太慢，优先尝试 query 缓存、ONNX/OpenVINO、量化或 efficient SPLADE。&lt;/li&gt;
&lt;li&gt;如果索引太大，优先调小 top-k、提高最小权重阈值，或选择更强正则化、更稀疏的模型。&lt;/li&gt;
&lt;li&gt;如果业务语料和公开英文检索数据差异很大，再考虑用领域数据微调，而不是直接相信公开榜单。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不要只按 MRR 选模型。SPLADE 选型至少要同时看五件事：检索效果、平均非零维度、索引体积、查询延迟、部署复杂度。&lt;/p&gt;
&lt;p&gt;Sentence Transformers 现在提供了 &lt;code&gt;SparseEncoder&lt;/code&gt;，可以直接加载 SPLADE 模型：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;sentence_transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SparseEncoder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SparseEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;naver/splade-cocondenser-ensembledistil&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;embeddings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;example query&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;它也提供 &lt;code&gt;encode_query()&lt;/code&gt;、&lt;code&gt;encode_document()&lt;/code&gt;、稀疏度统计、Qdrant/Elasticsearch/OpenSearch 集成，以及 ONNX/OpenVINO/量化相关部署能力。工程上可以优先用这条路线做原型，再根据性能瓶颈决定是否切到自定义推理服务。&lt;/p&gt;
&lt;h2 id="splade-和-bm25-的区别"&gt;SPLADE 和 BM25 的区别
&lt;/h2&gt;&lt;p&gt;BM25 和 SPLADE 都可以使用倒排索引完成检索，但权重来源不同。&lt;/p&gt;
&lt;p&gt;BM25 的权重来自统计量，例如 TF、IDF 和文档长度归一化。它主要依赖 query 原词和 document 原词的精确匹配。&lt;/p&gt;
&lt;p&gt;SPLADE 的权重来自神经模型预测。它不仅可以保留原文出现的 token，也可能激活原文没有出现但语义相关的 token。&lt;/p&gt;
&lt;p&gt;因此可以粗略理解为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;BM25 = 原始词项的统计匹配
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SPLADE = 神经扩展词项的加权匹配
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;在企业知识库、技术文档、客服 FAQ、代码文档、规范制度等场景中，BM25 和 SPLADE 都很有价值。BM25 更轻，SPLADE 更强但成本更高。&lt;/p&gt;</description></item><item><title>Practical BM25</title><link>https://ottercoconut.github.io/p/practical-bm25/</link><pubDate>Sat, 09 May 2026 13:30:00 +0800</pubDate><guid>https://ottercoconut.github.io/p/practical-bm25/</guid><description>&lt;h3 id="参考网站"&gt;参考网站
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://www.elastic.co/blog/practical-bm25-part-1-how-shards-affect-relevance-scoring-in-elasticsearch" target="_blank" rel="noopener"
 &gt;Practical BM25 - Part 1: How Shards Affect Relevance Scoring in Elasticsearch | Elastic Blog&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://www.elastic.co/blog/practical-bm25-part-2-the-bm25-algorithm-and-its-variables" target="_blank" rel="noopener"
 &gt;Practical BM25 - Part 2: The BM25 Algorithm and its Variables | Elastic Blog&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://www.elastic.co/blog/practical-bm25-part-3-considerations-for-picking-b-and-k1-in-elasticsearch" target="_blank" rel="noopener"
 &gt;Practical BM25 - Part 3: Considerations for Picking b and k1 in Elasticsearch | Elastic Blog&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://zh.wikipedia.org/wiki/Tf-idf" target="_blank" rel="noopener"
 &gt;tf-idf - 维基百科，自由的百科全书&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="background"&gt;Background
&lt;/h2&gt;&lt;p&gt;在 Elasticsearch 5.0 中，我们切换到 Okapi BM25 作为默认相似度算法，用于对搜索结果与查询的相关性进行评分。本文将着重介绍BM25 的实际应用，包括可用参数及其影响评分的因素。&lt;/p&gt;
&lt;h3 id="understanding-how-shards-affect-scoring"&gt;Understanding How Shards Affect Scoring
&lt;/h3&gt;&lt;p&gt;在学习 BM25 前，必须先理解 Elasticsearch 的索引可能被切成多个 shard（索引分片/物理分区）。因为 BM25 的相关性分数不是天然基于整个 index 的全局统计计算，而默认可能是在每个 shard 内部单独计算。shard 数量越多、数据越少，分数越容易出现偏差。&lt;/p&gt;
&lt;p&gt;下面我们照搬参考网站的示例代码，目的是先创建一个 Elasticsearch 索引 &lt;code&gt;people&lt;/code&gt;，再往里面插入几条测试文档，然后用同一个查询词 &lt;code&gt;&amp;quot;Shane&amp;quot;&lt;/code&gt; 反复检索，观察 BM25 相关性分数如何随着文档数量和 shard 分布发生变化：&lt;/p&gt;
&lt;p&gt;作者创建一个名为 &lt;code&gt;people&lt;/code&gt; 的索引，并指定它有 5 个 primary shards，默认相关性算法使用 BM25：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;PUT&lt;/span&gt; &lt;span class="err"&gt;people&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;settings&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;number_of_shards&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;index&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;similarity&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;default&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;BM25&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;作者使用它的名字做为示例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;PUT&lt;/span&gt; &lt;span class="err"&gt;/people/_doc/&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Shane&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;GET&lt;/span&gt; &lt;span class="err"&gt;/people/_doc/_search&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;query&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;match&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Shane&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;找出 &lt;code&gt;title&lt;/code&gt; 字段中匹配 &lt;code&gt;&amp;quot;Shane&amp;quot;&lt;/code&gt; 的文档，自然会匹配到&lt;code&gt;/people/_doc/1&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;PUT&lt;/span&gt; &lt;span class="err"&gt;/people/_doc/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Shane C&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;PUT&lt;/span&gt; &lt;span class="err"&gt;/people/_doc/&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Shane Connelly&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;PUT&lt;/span&gt; &lt;span class="err"&gt;/people/_doc/&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Shane P Connelly&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;然后再次对它们做搜索：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;GET&lt;/span&gt; &lt;span class="err"&gt;/people/_doc/_search&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;query&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;match&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;title&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Shane&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;也就是说现在有4条“文档”：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Shane&lt;/li&gt;
&lt;li&gt;Shane C&lt;/li&gt;
&lt;li&gt;Shane Connelly&lt;/li&gt;
&lt;li&gt;Shane P Connelly&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;从其中，找出 &lt;code&gt;title&lt;/code&gt; 字段中匹配 &lt;code&gt;&amp;quot;Shane&amp;quot;&lt;/code&gt; 的文档。虽然说&lt;code&gt;title&lt;/code&gt;字段都有&lt;code&gt;&amp;quot;Shane&amp;quot;&lt;/code&gt;，但是它们的BM25分数不会一样。结果：&lt;code&gt;doc1&lt;/code&gt; 和&lt;code&gt;doc3&lt;/code&gt; 分数都是0.2876821，但&lt;code&gt;doc2&lt;/code&gt; 分数是0.19856805，&lt;code&gt;doc4&lt;/code&gt;分数是0.16853254。&lt;/p&gt;
&lt;p&gt;尽管&lt;code&gt;doc2&lt;/code&gt;和&lt;code&gt;doc3&lt;/code&gt;很像，但是分数差了很多，这其实和&amp;quot;C&amp;quot;与&amp;quot;Connelly&amp;quot;的差异关系不大，而是和文档如何落在分片中有关。所以如何让分数更具一致性呢：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;数据量越大，shard 间的统计差异越小&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;减少 shard 数量可以降低打分偏差&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果想让多 shard 情况下的 BM25 打分更接近“全局统计”，可以在查询时加上 &lt;code&gt;?search_type=dfs_query_then_fetch&lt;/code&gt;。它会先收集所有 shard 的词频统计信息，再统一计算分数，因此结果会接近甚至等同于 &lt;code&gt;number_of_shards=1&lt;/code&gt; 时的分数。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;code&gt;dfs_query_then_fetch&lt;/code&gt; 的作用是先跨 shard 汇总词频统计，再统一计算 BM25 分数，使多 shard 的打分更接近单 shard 的全局效果；但它会增加一次额外通信，所以只有在小数据、多 shard、数据分布不均且很在意相关性分数时才值得使用。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="algorithm-and-its-variables"&gt;Algorithm and its variables
&lt;/h2&gt;&lt;p&gt;BM25 model:
&lt;/p&gt;
$$
\sum_{i}^{n} IDF(q_i) \frac{f(q_i, D) * (k_1 + 1)}{f(q_i, D) + k_1 * (1 - b + b * \frac{fieldLen}{avgFieldLen})}
$$&lt;ul&gt;
&lt;li&gt;$q_i$: 查询中的第 $i$ 个关键词。&lt;/li&gt;
&lt;li&gt;$IDF(q_i)$: 关键词 $q_i$ 的逆文档频率（Inverse Document Frequency）。&lt;/li&gt;
&lt;li&gt;$f(q_i, D)$ :关键词 $q_i$ 在文档 $D$ 中的词频。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;$fieldLen$&lt;/strong&gt;: 当前文档的长度。&lt;/li&gt;
&lt;li&gt;$avgFieldLen$: 索引中所有文档的平均长度。&lt;/li&gt;
&lt;li&gt;$k_1$ 和 $b$: 可调参数（通常 $k1 \in [1.2, 2.0]$，$b = 0.75$）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其实简单来说，BM25就是引入了非线性，并解决了频次问题的TF-IDF模型。TF-IDF model:
&lt;/p&gt;
$$
\text{Score} = f(q_i, D) \times \log\left(\frac{N}{n(q_i)}\right)
$$&lt;h4 id=""&gt;$q_i$
&lt;/h4&gt;&lt;p&gt;例如，如果我搜索“shane”，这里只有一个查询词，因此 $q_0$ 就是“shane”。如果我用英文搜索“shane connelly”，Elasticsearch 会识别其中的空格，并将其分词（tokenize）为两个词项：$q_0$ 为“shane”，$q_1$ 为“connelly”。这些查询词会被代入公式的其他部分，最后将所有结果加总求和。&lt;/p&gt;
&lt;h4 id=""&gt;$IDF(q_i)$
&lt;/h4&gt;&lt;p&gt;公式中的 &lt;strong&gt;IDF（逆文档频率）&lt;/strong&gt; 部分用于衡量一个词项在所有文档中出现的频率，并会对那些出现次数过多的常用词进行“&lt;strong&gt;惩罚&lt;/strong&gt;”（即降低其权重）。在 Lucene/BM25 算法中，该部分的实际公式如下：
&lt;/p&gt;
$$
\ln \left( 1 + \frac{(docCount - f(q_i) + 0.5)}{f(q_i) + 0.5} \right)
$$&lt;p&gt;
其中，$docCount$ 是该分片中（如果使用的是 &lt;code&gt;search_type=dfs_query_then_fetch&lt;/code&gt; 参数，则为跨所有分片）包含该字段值的文档总数；而 $f(q_i)$ 是包含第 $i$ 个查询词项的文档数量。在我们的示例中可以看到，“shane” 这个词在所有 4 个文档中都出现了，因此对于词项 “shane”，我们最终得到的逆文档频率 $IDF(\text{"shane"})$ 为：
&lt;/p&gt;
$$
\ln\left(1 + \frac{(4 - 4 + 0.5)}{4 + 0.5}\right) = \ln\left(1 + \frac{0.5}{4.5}\right) = 0.105360515657826
$$&lt;p&gt;
$IDF(\text{"connelly"})$为：
&lt;/p&gt;
$$
\ln\left(1 + \frac{(4 - 2 + 0.5)}{2 + 0.5}\right) = \ln\left(1 + \frac{2.5}{2.5}\right) = 0.693147180559945
$$&lt;p&gt;
我们可以看到，包含这些更罕见词项的查询（在我们的 4 文档语料库中，“connelly” 比 “shane” 更罕见）具有更高的&lt;strong&gt;乘数&lt;/strong&gt;，因此它们对最终得分的贡献更大。这在直觉上是合理的：词项 “the” 可能出现在几乎每一篇英文文档中，所以当用户搜索像 “the elephant” 这样的内容时，“elephant” 显然比词项 “the”（几乎存在于所有文档中）更重要——我们也希望它能为搜索得分做出更多贡献。&lt;/p&gt;
&lt;h4 id=""&gt;$fieldLen/avgFieldLen$
&lt;/h4&gt;&lt;p&gt;档中的词项越多（至少是那些没匹配上查询条件的词项），该文档的得分就越低。同样，这在直觉上是合理的：如果一份文档长达 300 页且只提到了我的名字一次，那么它与我的相关性，很可能不如一条同样提到我一次的短推文。&lt;/p&gt;
&lt;h4 id=""&gt;$b$
&lt;/h4&gt;&lt;p&gt;如果 $b$ 的值越大，文档长度相对于平均长度所产生的影响就会被进一步放大。为了理解这一点，可以想象如果将 $b$ 设置为 0，长度比例的影响将完全消失，只受频次影响，文档的长度将对评分不产生任何影响。如果将 $b$ 设置为 1 ，则得分不受频次影响，只受长度比例的影响。&lt;/p&gt;
&lt;h4 id=""&gt;$f(q_i, D)$
&lt;/h4&gt;&lt;p&gt;这个值对应了 TF (Term Frequency, 词频)&lt;/p&gt;
&lt;p&gt;$f(q_i, D)$ 的含义是：“第 $i$ 个查询词项在文档 $D$ 中出现了多少次？”在所有这些文档中，$f(\text{"shane"}, D)$ 都是 1，但 $f(\text{"connelly"}, D)$ 各不相同：在文档 3 和 4 中是 1，但在文档 1 和 2 中是 0。如果有第 5 个文档的文本是 “shane shane”，那么它的 $f(\text{"shane"}, D)$ 就是 2。我们可以看到，$f(q_i, D)$ 同时出现在分子和分母中，此外还有一个特殊的 “$k_1$” 因子，我们稍后会讨论它。理解 $f(q_i, D)$ 的方式是：查询词项在文档中出现的次数越多，其得分就越高。这在直觉上是合理的：一个多次提到我们名字的文档，比只提到一次的文档更有可能与我们相关。&lt;/p&gt;
&lt;h4 id=""&gt;$k_1$
&lt;/h4&gt;&lt;p&gt;在 BM25 算法中，$k_1$ 是控制词频饱和度（Term Frequency Saturation）的核心参数。它通过为词频 $f(q_i, D)$ 对相关性得分的贡献设定渐近上限确保得分随词频增加而产生的边际增益呈非线性递减。相比于传统 TF-IDF 近乎线性的权重增长，这一机制有效抑制了高频词项（如关键词堆砌）对排名的过度干扰；其中，$k_1$ 的取值直接决定了得分趋于饱和的速度：较小的 $k_1$ 值会使词频贡献快速达到瓶颈，而较大的 $k_1$ 值则允许词频在更广的数值范围内维持显著的权重增益。&lt;/p&gt;
&lt;p&gt;如果将 $k_1$ 设置为 0，得分将固定为1。如果将 $k_1$ 设置的很大（比如10000），公式近似退化为 $\frac{TF \times k_1}{k_1} = TF$ ，变成了词频本身。&lt;/p&gt;
&lt;h2 id="picking--and"&gt;Picking $b$ and $k_1$
&lt;/h2&gt;&lt;p&gt;关于 $b$ 和 $k_1$ 的值，ES的文章也指出现在的值是个能涵盖多数情况的“经验值”，但是&lt;strong&gt;不存在全局最优的 b 和 k1，只能结合语料和查询做实验评估。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;而且在检索性能不够好时，在调整 $b$ 和 $k_1$的值之前，应该先优化下面的内容：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;对精确短语匹配进行 boost；&lt;/li&gt;
&lt;li&gt;使用 synonyms 扩展用户可能感兴趣的同义表达；&lt;/li&gt;
&lt;li&gt;使用 fuzziness、typeahead、phonetic matching、stemming 等分析组件，处理拼写错误、语言差异和词形变化；&lt;/li&gt;
&lt;li&gt;使用 function score，根据发布时间、地理距离或业务特征调整文档得分。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;至于后文ES的Explain API，不再赘述。&lt;/p&gt;</description></item><item><title>Python asyncio：协程与任务</title><link>https://ottercoconut.github.io/p/python-asyncio%E5%8D%8F%E7%A8%8B%E4%B8%8E%E4%BB%BB%E5%8A%A1/</link><pubDate>Thu, 23 Apr 2026 16:08:00 +0800</pubDate><guid>https://ottercoconut.github.io/p/python-asyncio%E5%8D%8F%E7%A8%8B%E4%B8%8E%E4%BB%BB%E5%8A%A1/</guid><description>&lt;h1 id="python-asyncio协程与任务"&gt;Python asyncio：协程与任务
&lt;/h1&gt;
 &lt;blockquote&gt;
 &lt;p&gt;本文基于 &lt;em&gt;Python 3.11&lt;/em&gt; 的asyncio ，可能会缺失最新版本的特性&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;asyncio 是用来编写 &lt;strong&gt;并发&lt;/strong&gt; 代码的库，使用 &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt; 语法。其被用作多个提供高性能 Python 异步框架的基础，包括网络和网站服务，数据库连接库，分布式任务队列等等。也往往是构建 IO 密集型和高层级 &lt;strong&gt;结构化&lt;/strong&gt; 网络代码的最佳选择。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;asyncio&lt;/code&gt; 提供一组 &lt;strong&gt;高层级&lt;/strong&gt; API 用于:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;并发地 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html#coroutine" target="_blank" rel="noopener"
 &gt;运行 Python 协程&lt;/a&gt; 并对其执行过程实现完全控制;&lt;/li&gt;
&lt;li&gt;执行 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-stream.html#asyncio-streams" target="_blank" rel="noopener"
 &gt;网络 IO 和 IPC&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;控制 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-subprocess.html#asyncio-subprocess" target="_blank" rel="noopener"
 &gt;子进程&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;通过 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-queue.html#asyncio-queues" target="_blank" rel="noopener"
 &gt;队列&lt;/a&gt; 实现分布式任务;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-sync.html#asyncio-sync" target="_blank" rel="noopener"
 &gt;同步&lt;/a&gt; 并发代码;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="参考网站"&gt;参考网站
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html" target="_blank" rel="noopener"
 &gt;协程与任务 — Python 3.11.15 文档&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://www.runoob.com/python3/python-asyncio.html" target="_blank" rel="noopener"
 &gt;Python asyncio 模块 | 菜鸟教程&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://liaoxuefeng.com/books/python/async-io/coroutine/index.html" target="_blank" rel="noopener"
 &gt;协程 - Python教程 - 廖雪峰的官方网站&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="协程"&gt;协程
&lt;/h2&gt;&lt;p&gt;源码：&lt;a class="link" href="https://github.com/python/cpython/blob/3.11/Lib/asyncio/coroutines.py" target="_blank" rel="noopener"
 &gt;cpython/Lib/asyncio/coroutines.py at 3.11&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;通过 &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt; 语法来声明协程是编写 asyncio 应用的推荐方式。 例如，以下代码段会打印 &amp;ldquo;hello&amp;rdquo;，等待 1 秒，再打印 &amp;ldquo;world&amp;rdquo;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;world&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;hello&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;world&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;注意：简单地调用一个协程并不会使其被调度执行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;coroutine&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="mh"&gt;0x1053bb7c8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;要实际运行一个协程，asyncio 提供了以下几种机制:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-runner.html#asyncio.run" target="_blank" rel="noopener"
 &gt;&lt;code&gt;asyncio.run()&lt;/code&gt;&lt;/a&gt; 函数用来运行最高层级的入口点 &amp;ldquo;main()&amp;rdquo; 函数 (参见上面的示例。)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对协程执行 await。以下代码段会在等待 1 秒后打印 &amp;ldquo;hello&amp;rdquo;，然后 &lt;em&gt;再次&lt;/em&gt; 等待 2 秒后打印 &amp;ldquo;world&amp;rdquo;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;say_after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;what&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;what&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;started at &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%X&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;say_after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;say_after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;world&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;finished at &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%X&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;预期输出：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;started&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;hello&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;world&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;finished&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;55&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html#asyncio.create_task" target="_blank" rel="noopener"
 &gt;&lt;code&gt;asyncio.create_task()&lt;/code&gt;&lt;/a&gt; 函数用来并发运行作为 asyncio &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html#asyncio.Task" target="_blank" rel="noopener"
 &gt;&lt;code&gt;任务&lt;/code&gt;&lt;/a&gt; 的多个协程。&lt;/p&gt;
&lt;p&gt;让我们修改以上示例，&lt;em&gt;并发&lt;/em&gt; 运行两个 &lt;code&gt;say_after&lt;/code&gt; 协程:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;task1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;say_after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;task2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;say_after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;world&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;started at &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%X&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Wait until both tasks are completed (should take&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# around 2 seconds.)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;task1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;task2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;finished at &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%X&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html#asyncio.TaskGroup" target="_blank" rel="noopener"
 &gt;&lt;code&gt;asyncio.TaskGroup&lt;/code&gt;&lt;/a&gt; 类提供了 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html#asyncio.create_task" target="_blank" rel="noopener"
 &gt;&lt;code&gt;create_task()&lt;/code&gt;&lt;/a&gt; 的更现代化的替代。 使用此 API，之前的例子将变为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TaskGroup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;tg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;task1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;say_after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;task2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;say_after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;world&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;started at &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%X&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# The await is implicit when the context manager exits.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;finished at &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%X&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;现在看来，&lt;code&gt;asyncio.create_task()&lt;/code&gt; 和 &lt;code&gt;asyncio.TaskGroup&lt;/code&gt; 最大的区别在于是否需要手动等待(&lt;code&gt;await&lt;/code&gt;)，其它的特性详见后文。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="可等待对象"&gt;可等待对象
&lt;/h2&gt;&lt;p&gt;如果一个对象可以在 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/reference/expressions.html#await" target="_blank" rel="noopener"
 &gt;&lt;code&gt;await&lt;/code&gt;&lt;/a&gt; 语句中使用，那么它就是 &lt;strong&gt;可等待&lt;/strong&gt; 对象。许多 asyncio API 都被设计为接受可等待对象。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;可等待&lt;/em&gt; 对象有三种主要类型: &lt;strong&gt;协程&lt;/strong&gt;，&lt;strong&gt;任务&lt;/strong&gt;和&lt;strong&gt;Future&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;协程&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Python 协程属于 &lt;em&gt;可等待&lt;/em&gt; 对象，因此可以在其他协程中被等待：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;nested&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Nothing happens if we just call &amp;#34;nested()&amp;#34;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# A coroutine object is created but not awaited,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;nested&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;nested&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;# will print &amp;#34;42&amp;#34;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
 &lt;blockquote&gt;
 &lt;p&gt;在本文档中 &amp;ldquo;协程&amp;rdquo; 可用来表示两个紧密关联的概念:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;协程函数&lt;/em&gt;: 定义形式为 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/reference/compound_stmts.html#async-def" target="_blank" rel="noopener"
 &gt;&lt;code&gt;async def&lt;/code&gt;&lt;/a&gt; 的函数;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;协程对象&lt;/em&gt;: 调用 &lt;em&gt;协程函数&lt;/em&gt; 所返回的对象。&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;任务&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;任务&lt;/em&gt; 被用来“并行的”调度协程&lt;/p&gt;
&lt;p&gt;当一个协程通过 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html#asyncio.create_task" target="_blank" rel="noopener"
 &gt;&lt;code&gt;asyncio.create_task()&lt;/code&gt;&lt;/a&gt; 等函数被封装为一个 &lt;em&gt;任务&lt;/em&gt;，该协程会被自动调度执行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;nested&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Schedule nested() to run soon concurrently&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# with &amp;#34;main()&amp;#34;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nested&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# &amp;#34;task&amp;#34; can now be used to cancel &amp;#34;nested()&amp;#34;, or&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# can simply be awaited to wait until it is complete:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;当用 &lt;code&gt;create_task()&lt;/code&gt; 把一个协程包装成任务后，中途不想让这个任务继续执行了，就可以 &lt;code&gt;task.cancel()&lt;/code&gt; 将其中止，它会在 &lt;code&gt;nested()&lt;/code&gt; 下一次遇到 &lt;code&gt;await&lt;/code&gt; 时，注入一个 &lt;code&gt;asyncio.CancelledError&lt;/code&gt; 异常，详见&lt;a class="link" href="#%e4%bb%bb%e5%8a%a1%e5%8f%96%e6%b6%88" &gt;任务取消&lt;/a&gt;节。&lt;/p&gt;
&lt;p&gt;当 &lt;code&gt;task = asyncio.create_task(nested())&lt;/code&gt; 执行后，&lt;code&gt;nested()&lt;/code&gt; 自动开始运行，如果不写 &lt;code&gt;await task&lt;/code&gt; ，&lt;code&gt;main()&lt;/code&gt;通常结束得更快，导致 &lt;code&gt;nested()&lt;/code&gt; 尚未运行完，协程就已经结束了。&lt;/p&gt;
&lt;p&gt;由于其重要性，详细用法见&lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html#id15" target="_blank" rel="noopener"
 &gt;Task对象&lt;/a&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Futures&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-future.html#asyncio.Future" target="_blank" rel="noopener"
 &gt;&lt;code&gt;Future&lt;/code&gt;&lt;/a&gt; 是一种特殊的 &lt;strong&gt;低层级&lt;/strong&gt; 可等待对象，表示一个异步操作的 &lt;strong&gt;最终结果&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;当一个 Future 对象 &lt;em&gt;被等待&lt;/em&gt;，这意味着协程将保持等待直到该 Future 对象在其他地方操作完毕。&lt;/p&gt;
&lt;p&gt;在 asyncio 中需要 Future 对象以便允许通过 async/await 使用基于回调的代码。&lt;/p&gt;
&lt;p&gt;通常情况下 &lt;strong&gt;没有必要&lt;/strong&gt; 在应用层级的代码中创建 Future 对象。&lt;/p&gt;
&lt;p&gt;Future 对象有时会由库和某些 asyncio API 暴露给用户，用作可等待对象：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;function_that_returns_a_future_object&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# this is also valid:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;function_that_returns_a_future_object&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;some_python_coroutine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;一个很好的返回对象的低层级函数的示例是 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-eventloop.html#asyncio.loop.run_in_executor" target="_blank" rel="noopener"
 &gt;&lt;code&gt;loop.run_in_executor()&lt;/code&gt;&lt;/a&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="休眠"&gt;休眠
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;coroutine asyncio.sleep(delay, result=None)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;阻塞 &lt;em&gt;delay&lt;/em&gt; 指定的秒数。&lt;/p&gt;
&lt;p&gt;如果指定了 &lt;em&gt;result&lt;/em&gt;，则当协程完成时将其返回给调用者。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sleep()&lt;/code&gt; 总是会&lt;strong&gt;挂起&lt;/strong&gt;当前任务，以允许其他任务运行。&lt;/p&gt;
&lt;p&gt;将 delay 设为 0 将提供一个经优化的路径以允许其他任务运行。 这可&lt;strong&gt;供长期间运行的函数使用&lt;/strong&gt;以避免在函数调用的全过程中阻塞事件循环。&lt;/p&gt;
&lt;p&gt;比如调用 &lt;code&gt;await asyncio.sleep(0)&lt;/code&gt; 时：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;当前任务挂起：&lt;/strong&gt; 你的函数暂时停止执行，保存当前的寄存器和栈状态。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;排到队尾：&lt;/strong&gt; 该任务并没有被放进“等待计时器”的名单，而是直接被放回了 Ready Queue 的末尾。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;循环轮转：&lt;/strong&gt; 事件循环从 Ready Queue 的&lt;strong&gt;头部&lt;/strong&gt;取出下一个任务开始运行。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;以下协程示例运行 5 秒，每秒显示一次当前日期：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;display_date&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;loop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_running_loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;end_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;5.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;end_time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;display_date&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="创建任务"&gt;创建任务
&lt;/h2&gt;&lt;p&gt;源码：&lt;a class="link" href="https://github.com/python/cpython/blob/3.11/Lib/asyncio/tasks.py" target="_blank" rel="noopener"
 &gt;cpython/Lib/asyncio/tasks.py at 3.11&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;asyncio.create_task(coro, *, name=None, context=None)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;将 &lt;em&gt;coro&lt;/em&gt; &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html#coroutine" target="_blank" rel="noopener"
 &gt;协程&lt;/a&gt; 封装为一个 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html#asyncio.Task" target="_blank" rel="noopener"
 &gt;&lt;code&gt;Task&lt;/code&gt;&lt;/a&gt; 并调度其执行。返回 Task 对象。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;name&lt;/em&gt; 不为 &lt;code&gt;None&lt;/code&gt;，它将使用 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html#asyncio.Task.set_name" target="_blank" rel="noopener"
 &gt;&lt;code&gt;Task.set_name()&lt;/code&gt;&lt;/a&gt; 来设为任务的名称。&lt;/p&gt;
&lt;p&gt;可选的 &lt;em&gt;context&lt;/em&gt; 参数允许指定自定义的 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/contextvars.html#contextvars.Context" target="_blank" rel="noopener"
 &gt;&lt;code&gt;contextvars.Context&lt;/code&gt;&lt;/a&gt; 供 &lt;em&gt;coro&lt;/em&gt; 运行。 当未提供 &lt;em&gt;context&lt;/em&gt; 时将创建当前上下文的副本。&lt;/p&gt;
&lt;p&gt;该任务会在 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-eventloop.html#asyncio.get_running_loop" target="_blank" rel="noopener"
 &gt;&lt;code&gt;get_running_loop()&lt;/code&gt;&lt;/a&gt; 返回的循环中执行，如果当前线程没有在运行的循环则会引发 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/exceptions.html#RuntimeError" target="_blank" rel="noopener"
 &gt;&lt;code&gt;RuntimeError&lt;/code&gt;&lt;/a&gt;。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;保存一个指向此函数的结果的引用，以避免任务在执行过程中消失。 事件循环将只保留对任务的弱引用。 未在其他地方被引用的任务可能在任何时候被作为垃圾回收，即使是在它被完成之前。 如果需要可靠的“发射后不用管”后台任务，请将它们放到一个多项集中：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;background_tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;some_coro&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Add task to the set. This creates a strong reference.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;background_tasks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# To prevent keeping references to finished tasks forever,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# make each task remove its own reference from the set after&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# completion:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_done_callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;background_tasks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;discard&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
 &lt;/blockquote&gt;
&lt;p&gt;这段文档触及了Python的“事件循环”和“垃圾回收”机制，下面简单解释一下，具体的学习可能会单独写篇文章：&lt;/p&gt;
&lt;h3 id="事件循环"&gt;事件循环
&lt;/h3&gt;&lt;p&gt;为什么 &lt;code&gt;asyncio&lt;/code&gt; 的事件循环（Event Loop）只对 Task 对象保留弱引用 &lt;code&gt;weakref&lt;/code&gt; ？这是出于&lt;strong&gt;防止内存泄漏的防御性设计&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;事件循环是一个长期运行的底层死循环（通常伴随整个进程的生命周期）。如果事件循环内部维护一个强引用列表来追踪所有被 &lt;code&gt;create_task()&lt;/code&gt; 启动的后台任务：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;那些执行完毕或被取消的任务，必须由事件循环主动去清理它们。&lt;/li&gt;
&lt;li&gt;如果清理机制存在任何延迟或缺陷，或者开发者创建了海量的“发射后不管”任务，事件循环的内部列表会无限膨胀，最终导致内存溢出 (OOM)。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因此，&lt;code&gt;asyncio&lt;/code&gt; 制定了明确的契约：&lt;strong&gt;事件循环只负责“调度”协程，不负责“维持” Task 对象的生命周期。&lt;/strong&gt; 维持 Task 生命周期的责任被完全移交给了调用方（开发者）。事件循环通过弱引用来追踪任务状态，一旦调用方丢失了对 Task 的强引用，事件循环不会阻止该 Task 被销毁。&lt;/p&gt;
&lt;h3 id="垃圾回收"&gt;垃圾回收
&lt;/h3&gt;&lt;p&gt;Python 会在底层追踪每一个内存对象被引用了多少次。根据引用状态的不同，GC (Garbage Collection) 的处理逻辑如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;处理强引用对象&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当你将一个对象赋值给一个变量（如 &lt;code&gt;a = MyObject()&lt;/code&gt;），或者将其加入到列表、字典等数据结构中时，就创建了一个强引用。那么该对象的内部属性“引用计数”会加 1。&lt;/p&gt;
&lt;p&gt;只要一个对象的引用计数&lt;strong&gt;大于 0&lt;/strong&gt;，垃圾回收机制就会判定该对象正在被使用。GC 会完全忽略它，确保其在内存中安全存活。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;处理非强引用对象&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当变量的作用域结束、变量被重新赋值，或者使用 &lt;code&gt;del&lt;/code&gt; 显式删除变量时，原对象的强引用就会解除。此外，使用 &lt;code&gt;weakref&lt;/code&gt; 模块创建的“弱引用”也属于非强引用。强引用的解除会导致对象的引用计数减 1。弱引用虽然指向该对象，但&lt;strong&gt;不会&lt;/strong&gt;增加对象的引用计数。&lt;/p&gt;
&lt;p&gt;一旦对象的强引用计数&lt;strong&gt;降为 0&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;GC 会&lt;strong&gt;立即&lt;/strong&gt;介入，调用该对象的析构方法（&lt;code&gt;__del__&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;立即释放该对象占用的内存空间。&lt;/li&gt;
&lt;li&gt;所有指向该对象的弱引用会自动失效（返回值变为 &lt;code&gt;None&lt;/code&gt;）。&lt;/li&gt;
&lt;/ol&gt;

 &lt;blockquote&gt;
 &lt;p&gt;如果两个对象互相强引用对方，导致计数永远不为 0，Python 的辅助机制“分代回收器”会定期扫描并销毁这种无法被外部访问的孤立对象簇。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="上下文变量"&gt;上下文变量
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;create_task()&lt;/code&gt; 的 &lt;code&gt;context&lt;/code&gt; 参数是用来解决异步并发下**“数据隔离与传递”**的。默认（多数）情况下它会自动复印当前状态，保证子任务能拿到父任务的上下文数据；如果想阻断这种继承，就可以手动传一个自定义的 &lt;code&gt;context&lt;/code&gt; 进去。&lt;/p&gt;
&lt;p&gt;还需注意，上下文变量并不是在协程内部创建，而一般是在全局创建。下面只做一个简单示例，更复杂的内容（比如子协程临时修改上下文变量）可能要单独写篇文章：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;contextvars&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 1. 【全局】创建一个名为 &amp;#39;user_id&amp;#39; 的上下文变量（类似一把钥匙&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 这把钥匙是专门用来存储和检索当前任务相关的数据的）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;user_id_var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;contextvars&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContextVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;write_log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 3. 【底层函数】获取当前任务对应的 &amp;#39;user_id&amp;#39;（每个任务都有自己独立的“背包”）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 张三的任务获取的是张三，李四的任务获取的是李四&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;current_user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user_id_var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;[&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;] 执行了操作: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 2. 【顶层入口】设置当前任务的 &amp;#39;user_id&amp;#39;（将数据放入当前任务的“背包”）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 这里我们把用户名称（如张三或李四）赋值给当前任务的上下文变量&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;user_id_var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 模拟复杂的操作过程，任务间不需要传递数据！直接使用上下文变量。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;write_log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;登录系统&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 模拟任务的并发执行，控制权被交出&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;write_log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;退出系统&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 并发执行两个请求任务，确保每个任务独立，不会互相干扰&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 即使任务交替执行，上下文数据（如 &amp;#39;user_id&amp;#39;）也会保持准确&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;handle_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;张三&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;handle_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;李四&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 运行主程序，启动异步任务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 输出结果（交替打印，但每个任务的输出始终正确，保持隔离）：&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# [张三] 执行了操作: 登录系统&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# [李四] 执行了操作: 登录系统&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# [张三] 执行了操作: 退出系统&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# [李四] 执行了操作: 退出系统&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="并发运行任务"&gt;并发运行任务
&lt;/h2&gt;&lt;p&gt;当多个协程之间没有依赖关系时，我们通常不希望它们一个接一个执行，而是希望它们同时开始，谁需要等待 I/O，谁就把控制权交还给事件循环，让其他任务继续运行。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;asyncio.gather()&lt;/code&gt; 就适合这种场景：&lt;strong&gt;并发运行一组可等待对象，并在它们全部完成后，一次性拿到结果。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;比如下面这个例子中，&lt;code&gt;factorial(&amp;quot;A&amp;quot;, 2)&lt;/code&gt;、&lt;code&gt;factorial(&amp;quot;B&amp;quot;, 3)&lt;/code&gt; 和 &lt;code&gt;factorial(&amp;quot;C&amp;quot;, 4)&lt;/code&gt; 彼此之间没有依赖，因此可以并发执行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Task &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: Compute factorial(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;), currently i=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Task &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: factorial(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;) = &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;L&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;A&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;B&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;C&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;运行结果大致如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Compute&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;currently&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;2.&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Compute&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;currently&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;2.&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Compute&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;currently&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;2.&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Compute&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;currently&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;3.&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Compute&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;currently&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;3.&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Compute&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;currently&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;4.&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这里最值得注意的是：虽然三个任务的打印顺序是交错的，但 &lt;code&gt;gather()&lt;/code&gt; 返回结果的顺序仍然和传入顺序一致。&lt;/p&gt;
&lt;p&gt;也就是说：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;L&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;A&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;B&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;C&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;最终得到的是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;而不是按照哪个任务先完成来排序。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;gather()&lt;/code&gt; 有几个常用规则：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;如果传入的是协程对象，它会自动被包装成任务并调度执行。&lt;/li&gt;
&lt;li&gt;如果所有可等待对象都成功完成，返回值是一个列表。&lt;/li&gt;
&lt;li&gt;返回列表的顺序和传入顺序一致。&lt;/li&gt;
&lt;li&gt;如果 &lt;code&gt;gather()&lt;/code&gt; 本身被取消，所有尚未完成的任务也会被取消。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;比较容易忽略的是异常处理。&lt;/p&gt;
&lt;p&gt;默认情况下，如果其中某个任务抛出异常，异常会传播给正在 &lt;code&gt;await gather()&lt;/code&gt; 的地方。但这并不意味着其他任务一定会立刻停止。对于已经提交给 &lt;code&gt;gather()&lt;/code&gt; 的其他可等待对象，它们不会因为其中一个任务抛错就自动取消，而是会继续运行。&lt;/p&gt;
&lt;p&gt;如果你希望把异常也当作结果收集起来，可以使用 &lt;code&gt;return_exceptions=True&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;A&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;B&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;C&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;return_exceptions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这样异常会作为列表中的一个元素返回，调用方需要自己判断哪些结果是正常值，哪些是异常。&lt;/p&gt;
&lt;p&gt;因此，我对 &lt;code&gt;gather()&lt;/code&gt; 的理解是：它更像是一个“结果收集器”。当你关心的是“一组任务都跑完之后，各自返回了什么”时，它很合适。&lt;/p&gt;
&lt;p&gt;但如果你更关心的是“一组任务属于同一个生命周期，其中一个失败时其他任务也应该被取消”，那么 Python 3.11 之后更推荐使用 &lt;code&gt;TaskGroup&lt;/code&gt;。这也是下一节要讨论的内容。&lt;/p&gt;
&lt;h2 id="任务组"&gt;任务组
&lt;/h2&gt;&lt;p&gt;任务组合并了一套用于等待分组中所有任务完成的方便可靠方式的任务创建 API。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;class asyncio.TaskGroup&lt;/code&gt; : 持有一个任务分组的 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/reference/datamodel.html#async-context-managers" target="_blank" rel="noopener"
 &gt;异步上下文管理器&lt;/a&gt;。 可以使用 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html#asyncio.create_task" target="_blank" rel="noopener"
 &gt;&lt;code&gt;create_task()&lt;/code&gt;&lt;/a&gt; 将任务添加到分组中。 当该上下文管理器退出时所有任务都将被等待。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;TaskGroup.create_task(coro, *, name=None, context=None)&lt;/code&gt; : 在该任务组中创建一个任务。 其签名与 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html#asyncio.create_task" target="_blank" rel="noopener"
 &gt;&lt;code&gt;asyncio.create_task()&lt;/code&gt;&lt;/a&gt; 的相匹配。&lt;/p&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TaskGroup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;tg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;task1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;some_coro&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;task2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;another_coro&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Both tasks have completed now.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;async with&lt;/code&gt; 语句将等待分组中的所有任务结束。 在等待期间，仍可将新任务添加到分组中 (例如，通过将 &lt;code&gt;tg&lt;/code&gt; 传入某个协程并在该协程中调用 &lt;code&gt;tg.create_task()&lt;/code&gt;)。 一旦最后的任务完成并退出 &lt;code&gt;async with&lt;/code&gt; 代码块，将无法再向分组添加新任务。&lt;/p&gt;
&lt;p&gt;关于其异常处理，文档写的过于繁琐了，总结如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果任务因非 &lt;code&gt;asyncio.CancelledError&lt;/code&gt; 异常失败，其他任务会被取消，且无法再添加任务。&lt;/li&gt;
&lt;li&gt;失败的异常会被包装成 &lt;code&gt;ExceptionGroup&lt;/code&gt; 或 &lt;code&gt;BaseExceptionGroup&lt;/code&gt;，统一抛出。&lt;/li&gt;
&lt;li&gt;如果任务失败时是 &lt;code&gt;KeyboardInterrupt&lt;/code&gt; 或 &lt;code&gt;SystemExit&lt;/code&gt;，它们会优先被抛出，而不会归入异常组。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果发生取消与等待：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果 &lt;code&gt;async with&lt;/code&gt; 语句因异常退出，剩余任务会被取消并等待完成。&lt;/li&gt;
&lt;li&gt;异常（除了 &lt;code&gt;CancelledError&lt;/code&gt;）会被加入异常组，最终一起抛出。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="异步上下文管理器"&gt;异步上下文管理器
&lt;/h3&gt;&lt;p&gt;上面说 &lt;code&gt;TaskGroup&lt;/code&gt; 是一个异步上下文管理器，关键就在这一句：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TaskGroup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;tg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;它看起来只是普通的代码块，但实际上 Python 会在进入代码块之前调用 &lt;code&gt;__aenter__()&lt;/code&gt;，在离开代码块时调用 &lt;code&gt;__aexit__()&lt;/code&gt;。异步上下文管理器和普通上下文管理器的区别是：这两个方法的结果都要被 &lt;code&gt;await&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;可以把 &lt;code&gt;async with&lt;/code&gt; 粗略理解成下面的展开形式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TaskGroup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;tg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__aenter__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;BaseException&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;suppress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__aexit__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__traceback__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;suppress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;raise&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__aexit__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这段伪代码里有两个重点。&lt;/p&gt;
&lt;p&gt;第一个重点是：&lt;code&gt;__aenter__()&lt;/code&gt; 决定进入代码块时要准备什么，以及 &lt;code&gt;as tg&lt;/code&gt; 拿到什么。对 &lt;code&gt;TaskGroup&lt;/code&gt; 来说，&lt;code&gt;__aenter__()&lt;/code&gt; 会让这个任务组进入可用状态，并把任务组对象本身返回给 &lt;code&gt;tg&lt;/code&gt;，所以后面才能调用 &lt;code&gt;tg.create_task()&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;第二个重点是：&lt;code&gt;__aexit__()&lt;/code&gt; 决定离开代码块时要收尾什么。对 &lt;code&gt;TaskGroup&lt;/code&gt; 来说，真正重要的逻辑就在这里：它会等待组里的任务结束；如果有任务失败，它会取消其他任务；最后再把异常整理后抛出。&lt;/p&gt;
&lt;p&gt;这里容易混淆 &lt;code&gt;__aexit__()&lt;/code&gt; 和 &lt;code&gt;__await__()&lt;/code&gt;。&lt;code&gt;async with&lt;/code&gt; 协议本身调用的是 &lt;code&gt;__aenter__()&lt;/code&gt; 和 &lt;code&gt;__aexit__()&lt;/code&gt;，不是直接调用 &lt;code&gt;__await__()&lt;/code&gt;。但由于这两个方法必须返回可等待对象，所以 Python 在执行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__aexit__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;时，会走普通 &lt;code&gt;await&lt;/code&gt; 表达式的逻辑。对于 &lt;code&gt;async def __aexit__(...)&lt;/code&gt; 来说，调用它会得到一个协程对象；这个协程对象本身是可等待对象，底层通过它的 &lt;code&gt;__await__()&lt;/code&gt; 交给事件循环驱动执行。&lt;/p&gt;
&lt;p&gt;换句话说，可以这样理解这几层关系：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;async with
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 调用 __aenter__ / __aexit__
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; await 它们返回的可等待对象
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 可等待对象通过 __await__ 被事件循环推进
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;所以 &lt;code&gt;TaskGroup&lt;/code&gt; 能在退出代码块时“自动等待所有任务”，并不是因为 &lt;code&gt;async with&lt;/code&gt; 天生懂任务组，而是因为 &lt;code&gt;TaskGroup.__aexit__()&lt;/code&gt; 把等待、取消和异常整理这些逻辑都写在了退出阶段。&lt;/p&gt;
&lt;h4 id="__aexit__"&gt;&lt;code&gt;__aexit__()&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;当离开 &lt;code&gt;async with&lt;/code&gt; 代码块（或者代码块内部发生了错误）时，Python 会自动调用 &lt;code&gt;TaskGroup&lt;/code&gt; 的 &lt;code&gt;__aexit__(self, exc_type, exc_value, traceback)&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;它也实现了处理 &lt;code&gt;TaskGroup&lt;/code&gt; 中遇到异常等情况的逻辑：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;等待所有任务&lt;/strong&gt;：代码块里的语句执行完，并不代表任务组里的任务都结束了。&lt;code&gt;__aexit__()&lt;/code&gt; 会在这里等待组里所有任务完成。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;接收代码块异常&lt;/strong&gt;：如果 &lt;code&gt;async with&lt;/code&gt; 内部本身抛出了异常，&lt;code&gt;exc_type, exc_value, traceback&lt;/code&gt; 会把这个异常传进 &lt;code&gt;__aexit__()&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;处理子任务异常&lt;/strong&gt;：如果某个子任务抛出了非 &lt;code&gt;CancelledError&lt;/code&gt; 异常，&lt;code&gt;TaskGroup&lt;/code&gt; 会取消其他还在运行的任务。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;整理异常并抛出&lt;/strong&gt;：多个异常会被收集进 &lt;code&gt;ExceptionGroup&lt;/code&gt; 或 &lt;code&gt;BaseExceptionGroup&lt;/code&gt;，再统一抛给外层代码。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这也解释了为什么 &lt;code&gt;TaskGroup&lt;/code&gt; 比裸用 &lt;code&gt;create_task()&lt;/code&gt; 更“结构化”：任务不是散落在事件循环里各跑各的，而是被一个退出阶段统一收束。&lt;/p&gt;
&lt;h2 id="任务取消"&gt;任务取消
&lt;/h2&gt;&lt;p&gt;任务可以便捷和安全地取消。 当任务被取消时，&lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-exceptions.html#asyncio.CancelledError" target="_blank" rel="noopener"
 &gt;&lt;code&gt;asyncio.CancelledError&lt;/code&gt;&lt;/a&gt; 将在遇到机会时在任务中被引发。&lt;/p&gt;
&lt;p&gt;推荐协程使用 &lt;code&gt;try/finally&lt;/code&gt; 代码块来可靠地执行清理逻辑。 对于 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-exceptions.html#asyncio.CancelledError" target="_blank" rel="noopener"
 &gt;&lt;code&gt;asyncio.CancelledError&lt;/code&gt;&lt;/a&gt; 被显式捕获的情况，它通常应当在清理完成时被传播。 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-exceptions.html#asyncio.CancelledError" target="_blank" rel="noopener"
 &gt;&lt;code&gt;asyncio.CancelledError&lt;/code&gt;&lt;/a&gt; 会直接子类化 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/exceptions.html#BaseException" target="_blank" rel="noopener"
 &gt;&lt;code&gt;BaseException&lt;/code&gt;&lt;/a&gt; 因此大多数代码都不需要关心这一点。&lt;/p&gt;
&lt;p&gt;启用结构化并发的 asyncio 组件，如 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html#asyncio.TaskGroup" target="_blank" rel="noopener"
 &gt;&lt;code&gt;asyncio.TaskGroup&lt;/code&gt;&lt;/a&gt; 和 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html#asyncio.timeout" target="_blank" rel="noopener"
 &gt;&lt;code&gt;asyncio.timeout()&lt;/code&gt;&lt;/a&gt;，在内部是使用撤销操作来实现的因而在协程屏蔽了 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-exceptions.html#asyncio.CancelledError" target="_blank" rel="noopener"
 &gt;&lt;code&gt;asyncio.CancelledError&lt;/code&gt;&lt;/a&gt; 时可能无法正常工作。 类似地，用户代码通常也不应调用 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html#asyncio.Task.uncancel" target="_blank" rel="noopener"
 &gt;&lt;code&gt;uncancel&lt;/code&gt;&lt;/a&gt;。 但是，在确实想要屏蔽 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-exceptions.html#asyncio.CancelledError" target="_blank" rel="noopener"
 &gt;&lt;code&gt;asyncio.CancelledError&lt;/code&gt;&lt;/a&gt; 的情况下，则还有必要调用 &lt;code&gt;uncancel()&lt;/code&gt; 来完全移除撤销状态。&lt;/p&gt;
&lt;h2 id="超时"&gt;超时
&lt;/h2&gt;&lt;p&gt;异步程序里，超时不是锦上添花，而是很重要的防御措施。&lt;/p&gt;
&lt;p&gt;比如请求接口、读取文件、等待某个远端服务响应时，如果没有超时限制，一个任务可能会一直挂在那里。它未必占用 CPU，但会占住连接、内存、任务槽位等资源，也会让上层逻辑迟迟拿不到结果。&lt;/p&gt;
&lt;p&gt;在 Python 3.11 里，我更倾向优先使用 &lt;code&gt;asyncio.timeout()&lt;/code&gt;。它是一个异步上下文管理器，适合给“一段异步代码”设置时间限制：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;long_running_task&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;TimeoutError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;The long operation timed out, but we&amp;#39;ve handled it.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;This statement will run regardless.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这里最容易写错的地方是：&lt;code&gt;TimeoutError&lt;/code&gt; 要在 &lt;code&gt;async with&lt;/code&gt; 外面捕获。&lt;/p&gt;
&lt;p&gt;原因是 &lt;code&gt;asyncio.timeout()&lt;/code&gt; 的内部机制大致是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;时间到了，取消当前任务。&lt;/li&gt;
&lt;li&gt;当前任务中会出现 &lt;code&gt;asyncio.CancelledError&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;timeout()&lt;/code&gt; 在退出上下文管理器时把它转换成 &lt;code&gt;TimeoutError&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;所以在 &lt;code&gt;async with&lt;/code&gt; 代码块里面捕获 &lt;code&gt;TimeoutError&lt;/code&gt; 是捕获不到的，因为转换发生在上下文退出时。&lt;/p&gt;
&lt;p&gt;如果超时时间一开始还不能确定，可以先传入 &lt;code&gt;None&lt;/code&gt;，之后再通过 &lt;code&gt;reschedule()&lt;/code&gt; 调整。更精确地指定结束时间点时，也可以使用 &lt;code&gt;asyncio.timeout_at()&lt;/code&gt;。这些属于更细的控制，日常使用里先掌握 &lt;code&gt;asyncio.timeout()&lt;/code&gt; 就够了。&lt;/p&gt;
&lt;p&gt;另一个常见 API 是 &lt;code&gt;asyncio.wait_for()&lt;/code&gt;。它更适合给“单个可等待对象”设置超时：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;eternity&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;yay!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wait_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eternity&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;TimeoutError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;timeout!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Expected output:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# timeout!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;wait_for()&lt;/code&gt; 超时后也会取消传入的任务，并引发 &lt;code&gt;TimeoutError&lt;/code&gt;。需要注意的是，它会等待底层任务确实完成取消流程，所以实际等待时间可能略微超过设置的 &lt;code&gt;timeout&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;简单来说：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;场景&lt;/th&gt;
					&lt;th style="text-align: left"&gt;推荐写法&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;给一段异步代码加超时&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;asyncio.timeout()&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;给单个 awaitable 加超时&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;asyncio.wait_for()&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;不希望被超时取消影响内部任务&lt;/td&gt;
					&lt;td style="text-align: left"&gt;配合 &lt;code&gt;asyncio.shield()&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;不过最后一种情况要谨慎使用，因为“外层不等了，但内层任务还在跑”会让任务生命周期变得更难管理。&lt;/p&gt;
&lt;h2 id="屏蔽取消操作"&gt;屏蔽取消操作
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;awaitable asyncio.shield(aw)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;保护一个 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html#asyncio-awaitables" target="_blank" rel="noopener"
 &gt;可等待对象&lt;/a&gt; 防止其被 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html#asyncio.Task.cancel" target="_blank" rel="noopener"
 &gt;&lt;code&gt;取消&lt;/code&gt;&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;如果 &lt;em&gt;aw&lt;/em&gt; 是一个协程，它将自动被作为任务调度。&lt;/p&gt;
&lt;p&gt;以下语句:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;something&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;shield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;相当于:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;something&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;em&gt;不同之处&lt;/em&gt; 在于如果包含它的协程被取消，在 &lt;code&gt;something()&lt;/code&gt; 中运行的任务不会被取消。从 &lt;code&gt;something()&lt;/code&gt; 的角度看来，取消操作并没有发生。然而其调用者已被取消，因此 &amp;ldquo;await&amp;rdquo; 表达式仍然会引发 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-exceptions.html#asyncio.CancelledError" target="_blank" rel="noopener"
 &gt;&lt;code&gt;CancelledError&lt;/code&gt;&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;如果通过其他方式取消 &lt;code&gt;something()&lt;/code&gt; (例如在其内部操作) 则 &lt;code&gt;shield()&lt;/code&gt; 也会取消。&lt;/p&gt;
&lt;p&gt;如果希望完全忽略取消操作 (不推荐) 则 &lt;code&gt;shield()&lt;/code&gt; 函数需要配合一个 try/except 代码段，如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;something&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;shield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;CancelledError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
 &lt;blockquote&gt;
 &lt;p&gt;重要：保存一个传给此函数的任务的引用，以避免任务在执行过程中消失。事件循环将只保留对任务的弱引用。未在其他地方被引用的任务可能在任何时候被作为垃圾回收，即使是在它被完成之前。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="简单等待"&gt;简单等待
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;coroutine asyncio.wait(aws, *, timeout=None, return_when=ALL_COMPLETED)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;并发地运行 &lt;em&gt;aws&lt;/em&gt; 可迭代对象中的 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-future.html#asyncio.Future" target="_blank" rel="noopener"
 &gt;&lt;code&gt;Future&lt;/code&gt;&lt;/a&gt; 和 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html#asyncio.Task" target="_blank" rel="noopener"
 &gt;&lt;code&gt;Task&lt;/code&gt;&lt;/a&gt; 实例并进入阻塞状态直到满足 &lt;em&gt;return_when&lt;/em&gt; 所指定的条件。&lt;/p&gt;
&lt;p&gt;可迭代对象 &lt;em&gt;aws&lt;/em&gt; 不能为空并且不接受产生任务的生成器。&lt;/p&gt;
&lt;p&gt;返回两个 Task/Future 集合: &lt;code&gt;(done, pending)&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;用法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;done&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pending&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如指定 &lt;em&gt;timeout&lt;/em&gt; (float 或 int 类型) 则它将被用于控制返回之前等待的最长秒数。&lt;/p&gt;
&lt;p&gt;请注意此函数不会引发 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/exceptions.html#TimeoutError" target="_blank" rel="noopener"
 &gt;&lt;code&gt;TimeoutError&lt;/code&gt;&lt;/a&gt;。 当超时发生时尚未完成的 Future 或 Task 会在设定的秒数后被直接返回。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;return_when&lt;/em&gt; 指定此函数应在何时返回。它必须为以下常数之一:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;常量&lt;/th&gt;
					&lt;th style="text-align: left"&gt;描述&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;asyncio.&lt;strong&gt;FIRST_COMPLETED&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;函数将在任意可等待对象结束或取消时返回。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;asyncio.&lt;strong&gt;FIRST_EXCEPTION&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;该函数将在任何 future 对象通过引发异常而结束时返回。 如果没有任何 future 对象引发引发那么它将等价于 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html#asyncio.ALL_COMPLETED" target="_blank" rel="noopener"
 &gt;&lt;code&gt;ALL_COMPLETED&lt;/code&gt;&lt;/a&gt;。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;asyncio.&lt;strong&gt;ALL_COMPLETED&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;函数将在所有可等待对象结束或取消时返回。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;asyncio.as_completed(aws, *, timeout=None)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;并发地运行可迭代对象 &lt;em&gt;aws&lt;/em&gt; 中的 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/asyncio-task.html#asyncio-awaitables" target="_blank" rel="noopener"
 &gt;可等待对象&lt;/a&gt;。 产生任务的生成器不可被用作 &lt;em&gt;aws&lt;/em&gt; 可迭代对象。 返回一个产生协程的迭代器。 所返回的每个协程可被等待以便从剩余的可等待对象的可迭代对象中获得早最的下一个结果。&lt;/p&gt;
&lt;p&gt;如果在所有 Future 对象完成之前发生超时则将引发 &lt;a class="link" href="https://docs.python.org/zh-cn/3.11/library/exceptions.html#TimeoutError" target="_blank" rel="noopener"
 &gt;&lt;code&gt;TimeoutError&lt;/code&gt;&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;示例:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;coro&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;as_completed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;earliest_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;coro&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="在线程中运行"&gt;在线程中运行
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;asyncio.to_thread()&lt;/code&gt; 适合处理一种很常见的尴尬情况：你正在写异步代码，但手里有一个只能同步调用的阻塞函数。&lt;/p&gt;
&lt;p&gt;如果直接在协程里调用这个函数，它会卡住事件循环，让其他任务也没法继续运行。&lt;code&gt;to_thread()&lt;/code&gt; 的作用就是把这个同步函数丢到另一个线程里执行，然后在异步代码里用 &lt;code&gt;await&lt;/code&gt; 等它的结果。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_file_slowly&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;file content&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;read_file_slowly&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;它通常用于文件读写、同步数据库驱动、旧 SDK 调用这类 &lt;strong&gt;IO 密集型&lt;/strong&gt; 阻塞操作。由于 GIL 的存在，它一般不适合用来加速纯 Python 的 CPU 密集型计算。&lt;/p&gt;
&lt;h2 id="跨线程调度"&gt;跨线程调度
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;asyncio.run_coroutine_threadsafe()&lt;/code&gt; 用于从另一个线程向某个事件循环提交协程。&lt;/p&gt;
&lt;p&gt;这个 API 平时不常用。只有当你的程序里同时存在普通线程和 asyncio 事件循环，并且某个线程需要把协程交给事件循环执行时，才会用到它。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;coro&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;future&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run_coroutine_threadsafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coro&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;它返回的是 &lt;code&gt;concurrent.futures.Future&lt;/code&gt;，不是 &lt;code&gt;asyncio.Future&lt;/code&gt;。因此获取结果时用的是同步世界里的 &lt;code&gt;future.result()&lt;/code&gt;。如果等待超时，也可以取消它：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;TimeoutError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;需要注意的是，它要求显式传入事件循环 &lt;code&gt;loop&lt;/code&gt;，而且应该从事件循环所在之外的线程调用。&lt;/p&gt;
&lt;h2 id="内省"&gt;内省
&lt;/h2&gt;&lt;p&gt;内省 API 主要用于调试、监控或框架内部逻辑。日常业务代码一般不需要频繁使用。&lt;/p&gt;
&lt;p&gt;常见的有三个：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;API&lt;/th&gt;
					&lt;th style="text-align: left"&gt;用途&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;asyncio.current_task()&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;获取当前正在运行的 &lt;code&gt;Task&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;asyncio.all_tasks()&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;获取当前事件循环中尚未完成的所有 &lt;code&gt;Task&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;asyncio.iscoroutine(obj)&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;判断对象是不是协程对象&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;例如调试当前事件循环里还有哪些任务没结束：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all_tasks&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这些函数适合在排查任务泄漏、定位后台任务状态、编写异步框架时使用。对于普通应用代码来说，知道它们存在即可。&lt;/p&gt;</description></item><item><title>RAGFlow切片策略解析</title><link>https://ottercoconut.github.io/p/ragflow%E5%88%87%E7%89%87%E7%AD%96%E7%95%A5%E8%A7%A3%E6%9E%90/</link><pubDate>Tue, 14 Apr 2026 20:06:34 +0800</pubDate><guid>https://ottercoconut.github.io/p/ragflow%E5%88%87%E7%89%87%E7%AD%96%E7%95%A5%E8%A7%A3%E6%9E%90/</guid><description>&lt;h2 id="ragflow-切片策略解析"&gt;RAGFlow 切片策略解析
&lt;/h2&gt;&lt;p&gt;众所周知RAGFlow是较早成熟且开源的RAG项目之一，近日笔者正在学习构建一个RAG项目，所以从RAGFlow的源码下手。首先学习的是它对markdown文件的解析方法和切片策略。&lt;/p&gt;
&lt;h3 id="ragappnaivepy"&gt;&lt;code&gt;rag/app/naive.py&lt;/code&gt;
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;naive.py&lt;/code&gt; 中支持很多文件的类型，比如&lt;code&gt;PDF&lt;/code&gt;, &lt;code&gt;DOCX&lt;/code&gt;, &lt;code&gt;Markdown&lt;/code&gt;&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;那么我们要学习的&lt;code&gt;markdown&lt;/code&gt;类，主入口是&lt;code&gt;__call__()&lt;/code&gt;，这是核心方法，编排了整个 Markdown 解析流程。&lt;/p&gt;
&lt;h4 id="__call__"&gt;&lt;code&gt;__call()__&lt;/code&gt;
&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;separate_tables&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delimiter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;return_section_images&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;参数&lt;/th&gt;
					&lt;th style="text-align: left"&gt;类型&lt;/th&gt;
					&lt;th style="text-align: left"&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;filename&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;str&lt;/td&gt;
					&lt;td style="text-align: left"&gt;文件路径（当 &lt;code&gt;binary&lt;/code&gt; 为空时用来读文件）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;binary&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;bytes&lt;/td&gt;
					&lt;td style="text-align: left"&gt;文件二进制内容，优先使用&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;separate_tables&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;bool&lt;/td&gt;
					&lt;td style="text-align: left"&gt;是否将表格从正文中分离出来&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;delimiter&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;str&lt;/td&gt;
					&lt;td style="text-align: left"&gt;自定义分割符，如果指定则用分割符切分而非按元素类型切分&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;return_section_images&lt;/code&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;bool&lt;/td&gt;
					&lt;td style="text-align: left"&gt;是否额外返回每个 section 对应的图片&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;执行流程：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;span class="lnt"&gt;53
&lt;/span&gt;&lt;span class="lnt"&gt;54
&lt;/span&gt;&lt;span class="lnt"&gt;55
&lt;/span&gt;&lt;span class="lnt"&gt;56
&lt;/span&gt;&lt;span class="lnt"&gt;57
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Step 1: 文本解码
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ┌────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ binary → find_codec() → │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ decode(encoding) │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ 或 open(filename).read() │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └────────────┬───────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Step 2: 表格提取（继承自父类）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ┌────────────────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ self.extract_tables_and_remainder(txt+&amp;#34;\n&amp;#34;, │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ separate_tables) │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ → (remainder, tables[]) │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ 注意：这里传入的是 txt+&amp;#34;\n&amp;#34;（末尾补换行） │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └────────────┬───────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Step 3: 元素扫描
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ┌────────────────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ MarkdownElementExtractor(txt) │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ .extract_elements(delimiter, include_meta=True) │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ → element_sections[] │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ★ 关键：这里传入的是原始 txt，而非 remainder！ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ （注释 L682-683 说明了原因：为避免重复表格） │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └────────────┬───────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Step 4: 图片 URL 提取
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ┌────────────────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ self.extract_image_urls_with_lines(txt) │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ → image_refs = [{url, line}, ...] │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └────────────┬───────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Step 5: 元素-图片关联（核心融合逻辑）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ┌────────────────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ for element in element_sections: │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ① 取 element 的 start_line ~ end_line │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ② 筛选行范围内的 image_refs │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ③ load_images_from_urls() 下载图片（有缓存） │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ④ 多张图用 concat_img 合并为一张 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ⑤ sections.append((content, &amp;#34;&amp;#34;)) │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ⑥ section_images.append(combined_image or None) │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └────────────┬───────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Step 6: 表格后处理
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ┌────────────────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ for table in tables: │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ markdown(table, extensions=[&amp;#34;tables&amp;#34;]) → html │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ tbls.append(((None, html), &amp;#34;&amp;#34;)) │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └────────────┬───────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Step 7: 返回结果
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ┌────────────────────────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ if return_section_images: │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ return sections, tbls, section_images │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ else: │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ return sections, tbls │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └────────────────────────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;输出数据结构：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;sections&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;## 标题&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;正文内容...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;# (文本, 位置标签—永远为空字符串)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;```python&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;code&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;```&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;# 代码块&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;tbls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;table&amp;gt;...&amp;lt;/table&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;# (None, HTML表格字符串)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;section_images&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;PIL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# 该 section 中所有图片合并后的图像对象&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# 该 section 无图片&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;PIL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这其中最关键的是&lt;strong&gt;表格提取&lt;/strong&gt;和&lt;strong&gt;元素扫描&lt;/strong&gt;的部分：&lt;/p&gt;
&lt;h4 id="extract_tables_and_remainder"&gt;&lt;code&gt;extract_tables_and_remainder()&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;这个方法定义于&lt;code&gt;deepdoc/parser/resume/markdown_parser.py&lt;/code&gt;的&lt;code&gt;RAGFlowMarkdownParser&lt;/code&gt;类中，用于将markdown中的表格提取出来&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RAGFlowMarkdownParser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunk_token_num&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chunk_token_num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk_token_num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;extract_tables_and_remainder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;markdown_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;separate_tables&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 返回: (剩余正文, [表格列表])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;表格识别策略：&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;类型&lt;/th&gt;
					&lt;th style="text-align: left"&gt;正则&lt;/th&gt;
					&lt;th style="text-align: left"&gt;示例&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;有边框 Markdown 表格&lt;/td&gt;
					&lt;td style="text-align: left"&gt;`&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&amp;hellip;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;无边框 Markdown 表格&lt;/td&gt;
					&lt;td style="text-align: left"&gt;`text&lt;/td&gt;
					&lt;td style="text-align: left"&gt;text` + 分隔行 + 数据行&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;HTML 表格&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;&amp;lt;table&amp;gt;...&amp;lt;/table&amp;gt;&lt;/code&gt;，支持包裹在 &lt;code&gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&lt;/code&gt; 中&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;&amp;lt;table&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;...&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/table&amp;gt;&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;当 &lt;code&gt;separate_tables=True&lt;/code&gt; 时，表格从正文里移除并单独返回；为 &lt;code&gt;False&lt;/code&gt; 时则就地转为 HTML。&lt;/p&gt;
&lt;h4 id="markdownelementextractor"&gt;&lt;code&gt;MarkdownElementExtractor&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;该类位于&lt;code&gt;deepdoc/parser/markdown_parser.py&lt;/code&gt;，实现了一个简易的 Markdown 元素识别器，将文本按行扫描并归类为不同的块类型。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MarkdownElementExtractor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;markdown_content&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;markdown_content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;markdown_content&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;markdown_content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;extract_elements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delimiter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;include_meta&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;提取各种元素(headers, code blocks, lists, 等)&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;输出元素结构：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;header&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;code_block&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;list_block&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;blockquote&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;text_block&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;具体文本内容&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;start_line&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# 起始行号&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;end_line&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# 结束行号&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;_extract_header()&lt;/code&gt; : 返回单行的&amp;quot;header&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_extract_code_block()&lt;/code&gt; : 直到遇到&amp;quot; ``` &amp;ldquo;返回多行的代码块&amp;quot;code_block&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_extract_list_block()&lt;/code&gt; : 吞入满足以下条件的行：
&lt;ul&gt;
&lt;li&gt;以 &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt; 或 &lt;code&gt;数字.&lt;/code&gt; 开头（列表项）&lt;/li&gt;
&lt;li&gt;空行（列表项间隙）&lt;/li&gt;
&lt;li&gt;以 2+ 空格缩进的子列表或续行&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_extract_blockquote()&lt;/code&gt; : 持续吞入&amp;quot;&amp;gt;&amp;ldquo;开头的行或内部的空行&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_extract_text_block()&lt;/code&gt; : 处理不属于上面几种类型的普通文本&amp;quot;text_block&amp;rdquo;，直到符合上面类型的元素再次出现&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="extract_image_urls_with_lines"&gt;&lt;code&gt;extract_image_urls_with_lines()&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;这个方法用于找出 Markdown 文本中所有图片引用及其所在行号。行号用于后续将图片关联到对应的 section。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;三阶段提取策略：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;阶段 1: Markdown 语法图片
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 正则: ![alt](url) → 提取 url
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 模式: r&amp;#34;!\[[^\]]*\]\(([^)\s]+)&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;阶段 2: HTML 内联图片（单行）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 正则: src=&amp;#34;url&amp;#34; / src=&amp;#39;url&amp;#39; → 提取 url
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 模式: r&amp;#39;src=[&amp;#34;\\\&amp;#39;&amp;#34;]([^&amp;#34;\\\&amp;#39;&amp;gt;\\s]+)&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;阶段 3: HTML 跨行图片（BeautifulSoup 兜底）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 解析整个文本为 HTML，查找所有 &amp;lt;img&amp;gt; 标签的 src
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 通过字符偏移量计算行号
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 用 seen 集合避免与阶段 1/2 重复
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;返回值：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://example.com/img.png&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;line&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;./assets/diagram.svg&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;line&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="load_images_from_urls"&gt;&lt;code&gt;load_images_from_urls()&lt;/code&gt;
&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_images_from_urls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 返回: (images[], cache{})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;功能&lt;/th&gt;
					&lt;th style="text-align: left"&gt;细节&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;HTTP 图片&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;requests.get(url, timeout=30)&lt;/code&gt;，校验 &lt;code&gt;Content-Type&lt;/code&gt; 为 &lt;code&gt;image/&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;本地图片&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;Path(url).exists()&lt;/code&gt; 检查后用 &lt;code&gt;PIL.Image.open()&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;缓存机制&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;code&gt;cache&lt;/code&gt; dict 避免重复下载同一 URL&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;统一格式&lt;/td&gt;
					&lt;td style="text-align: left"&gt;所有图片转为 &lt;code&gt;RGB&lt;/code&gt; 模式 (&lt;code&gt;convert(&amp;quot;RGB&amp;quot;)&lt;/code&gt;)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;错误处理&lt;/td&gt;
					&lt;td style="text-align: left"&gt;失败时 &lt;code&gt;cache[url] = None&lt;/code&gt;，不中断流程&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这里的思路比较朴素，但很实用：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;先根据 &lt;code&gt;url&lt;/code&gt; 判断是网络图片还是本地图片&lt;/li&gt;
&lt;li&gt;统一加载成 &lt;code&gt;PIL.Image&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;放入缓存，避免同一张图在多个 section 中重复读取&lt;/li&gt;
&lt;li&gt;后续如果某个 section 对应多张图片，再交给 &lt;code&gt;concat_img&lt;/code&gt; 合并&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;也就是说，RAGFlow 在 Markdown 中并不是把每一张图片都单独当成一个 chunk，而是先尝试把&lt;strong&gt;同一个 section 内的图片聚合&lt;/strong&gt;起来，再与文本一起进入后续流程。&lt;/p&gt;
&lt;h4 id="urls_in_section--"&gt;&lt;code&gt;urls_in_section = [...]&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;在 &lt;code&gt;Markdown.__call__()&lt;/code&gt; 中，真正把文本 section 和图片联系起来的代码是这一段：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;element_sections&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;content&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;start_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;start_line&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;end_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;end_line&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;urls_in_section&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;image_refs&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;start_line&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;line&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;end_line&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;其核心思想非常直接：&lt;strong&gt;按行号做区间归属&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个 Markdown 元素先被标记 &lt;code&gt;start_line&lt;/code&gt; 和 &lt;code&gt;end_line&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;所有图片引用也带有自己的 &lt;code&gt;line&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;只要图片所在行落在元素区间内，就认为这张图属于这个 section&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这是一种很工程化的做法。它不追求复杂语义理解，而是利用 Markdown 本身“按行组织”的特点，以较低成本建立图文关联。&lt;/p&gt;
&lt;p&gt;例如下面这段 Markdown：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;### 模型结构
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;这里介绍整体流程。
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;![&lt;span class="nt"&gt;pipeline&lt;/span&gt;](&lt;span class="na"&gt;./pipeline.png&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;接着说明各模块职责。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果这一整段被 &lt;code&gt;MarkdownElementExtractor&lt;/code&gt; 视为同一个 &lt;code&gt;text_block&lt;/code&gt;，那么图片就会和这一段正文绑定在一起；如果标题和正文被分成两个元素，则图片通常会归到正文所在的 section，而不会归到标题 section。&lt;/p&gt;
&lt;h4 id="表格处理细节"&gt;表格处理细节
&lt;/h4&gt;&lt;p&gt;前面提到，&lt;code&gt;Markdown.__call__()&lt;/code&gt; 中虽然调用了：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;remainder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extract_tables_and_remainder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;separate_tables&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;separate_tables&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;但后面真正做元素扫描时，使用的是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;extractor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MarkdownElementExtractor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;而不是 &lt;code&gt;remainder&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;源码里其实已经留了注释：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# To eliminate duplicate tables in chunking result, uncomment code below and set separate_tables to True ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# extractor = MarkdownElementExtractor(remainder)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;extractor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MarkdownElementExtractor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这说明作者其实也意识到了一个现象：&lt;strong&gt;表格可能同时出现在 section chunk 和 table result 中&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;从实现角度看，这未必是 bug，更像是一种偏保守的召回策略：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;正文 chunk 中保留表格原始上下文&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tables&lt;/code&gt; 中再额外保留结构化表格内容&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样做可能带来一定冗余，但也提高了检索时命中表格信息的概率。&lt;/p&gt;
&lt;h3 id="chunk"&gt;&lt;code&gt;chunk()&lt;/code&gt;
&lt;/h3&gt;&lt;p&gt;看到这里，其实还只是完成了解析和预处理。真正决定最终 chunk 长什么样的，不在 &lt;code&gt;Markdown.__call__()&lt;/code&gt;，而在 &lt;code&gt;rag/app/naive.py&lt;/code&gt; 下面的 &lt;code&gt;chunk()&lt;/code&gt; 函数里。&lt;/p&gt;
&lt;p&gt;Markdown 文件分支一开始会先调用前面的解析器：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;markdown_parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Markdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parser_config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;chunk_token_num&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;sections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tables&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;section_images&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;markdown_parser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;separate_tables&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;delimiter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;parser_config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;delimiter&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;!?;。；！？&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;return_section_images&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这里有两个细节值得注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;return_section_images=True&lt;/code&gt;
说明 Markdown 解析阶段生成的图片不会丢，而是继续带到后面的 chunk 合并流程中。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;separate_tables=False&lt;/code&gt;
说明这里并没有把表格完全从正文切走，而是倾向于让表格继续留在 Markdown 上下文里，同时又额外生成 &lt;code&gt;tables&lt;/code&gt; 供表格索引使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;接着，如果当前租户存在 &lt;code&gt;IMAGE2TEXT&lt;/code&gt; 模型，&lt;code&gt;chunk()&lt;/code&gt; 会尝试给 Markdown 中的图片补一段描述文本：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;vision_model_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_tenant_default_model_by_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;tenant_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;LLMType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IMAGE2TEXT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;vision_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LLMBundle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;tenant_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;vision_model_config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Failed to detect figure extraction: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;vision_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果视觉模型可用，则继续遍历每个 section：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;section_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sections&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;images&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;section_images&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;section_images&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;section_images&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;section_images&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;images&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;combined_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;concat_img&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;markdown_vision_parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VisionFigureParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;vision_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vision_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;figures_data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[((&lt;/span&gt;&lt;span class="n"&gt;combined_image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;markdown image&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)])],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;boosted_figures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;markdown_vision_parser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sections&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;section_text&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;fig&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;boosted_figures&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sections&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这里可以看出 Markdown 图片增强的几个特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;粒度是 &lt;strong&gt;section 级别&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;输入图片是前面已经聚合好的 &lt;code&gt;section_images[idx]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;输出不是新的 chunk，而是把图片描述文本直接追加回原 &lt;code&gt;section_text&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="visionfigureparser"&gt;&lt;code&gt;VisionFigureParser&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;该类定义在 &lt;code&gt;deepdoc/parser/figure_parser.py&lt;/code&gt; 中：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;VisionFigureParser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vision_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;figures_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vision_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vision_model&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;figure_contexts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;figure_contexts&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;context_size&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_extract_figures_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figures_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这个类的职责并不复杂，可以理解为一个“图片描述批处理器”：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;接收图片列表 &lt;code&gt;figures_data&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;整理出图片、描述、位置信息&lt;/li&gt;
&lt;li&gt;调用视觉模型生成描述&lt;/li&gt;
&lt;li&gt;再把结果重新组装回原来的数据结构&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Markdown 分支给它传入的 &lt;code&gt;figures_data&lt;/code&gt; 形式是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;[((&lt;/span&gt;&lt;span class="n"&gt;combined_image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;markdown image&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)])]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;也就是说，每次只处理当前 section 对应的一张聚合图，原始描述先放一个占位值 &lt;code&gt;&amp;quot;markdown image&amp;quot;&lt;/code&gt;，位置则放一个 dummy tuple。&lt;/p&gt;
&lt;h4 id="_extract_figures_info"&gt;&lt;code&gt;_extract_figures_info()&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;这个方法负责把 &lt;code&gt;figures_data&lt;/code&gt; 拆成内部使用的三个列表：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_extract_figures_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;figures_data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;figures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;descriptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;positions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;其中核心分支是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;img_desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ensure_pil_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img_desc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;figures&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;descriptions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img_desc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;positions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;因此传入的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;combined_image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;markdown image&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;会被拆成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;self.figures&lt;/code&gt; : &lt;code&gt;[combined_image]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;self.descriptions&lt;/code&gt; : &lt;code&gt;[[&amp;quot;markdown image&amp;quot;]]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;self.positions&lt;/code&gt; : &lt;code&gt;[[(0, 0, 0, 0, 0)]]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这里的 &lt;code&gt;ensure_pil_image()&lt;/code&gt; 负责把输入统一成 &lt;code&gt;PIL.Image&lt;/code&gt; 对象，因此前面无论传入的是普通图片对象还是惰性图片对象，到了这里都会被标准化。&lt;/p&gt;
&lt;h4 id="__call__-1"&gt;&lt;code&gt;__call__()&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;&lt;code&gt;VisionFigureParser.__call__()&lt;/code&gt; 才是真正执行视觉增强的入口：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;callback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;callback&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;它内部先定义了一个 &lt;code&gt;process()&lt;/code&gt;，用于处理单张图片：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figure_idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;figure_binary&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;context_above&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;context_below&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;figure_idx&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;figure_contexts&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;context_above&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context_below&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;figure_contexts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;figure_idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;context_above&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;context_below&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vision_llm_figure_describe_prompt_with_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;context_above&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;context_above&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;context_below&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;context_below&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vision_llm_figure_describe_prompt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;然后通过线程池并发调用：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;img_binary&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;figures&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;futures&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shared_executor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;img_binary&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;等所有任务完成之后，将返回的描述文本写回：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;future&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;as_completed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;futures&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;figure_num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;txt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;txt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;descriptions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;figure_num&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;txt&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;descriptions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;figure_num&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;最后再调用 &lt;code&gt;_assemble()&lt;/code&gt; 重新组装：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_assemble&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assembled&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;对于 Markdown 分支来说，这里有两个细节：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;没有显式传入 &lt;code&gt;figure_contexts&lt;/code&gt;，因此默认使用 &lt;code&gt;vision_llm_figure_describe_prompt()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;回填时会把模型输出和原始描述拼在一起，因此最终描述中理论上可能保留 &lt;code&gt;&amp;quot;markdown image&amp;quot;&lt;/code&gt; 这个占位文本&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="picture_vision_llm_chunk"&gt;&lt;code&gt;picture_vision_llm_chunk()&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;&lt;code&gt;process()&lt;/code&gt; 里真正调用视觉模型的函数是 &lt;code&gt;rag/app/picture.py&lt;/code&gt; 中的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;vision_llm_chunk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vision_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;虽然名字叫 &lt;code&gt;vision_llm_chunk&lt;/code&gt;，但其作用其实很直接，就是把图片交给 VLM 并返回描述文本。&lt;/p&gt;
&lt;p&gt;其主要步骤如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BytesIO&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;img_binary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img_binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;JPEG&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;img_binary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;img_binary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;truncate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img_binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;PNG&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;img_binary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ans&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clean_markdown_block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vision_model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;describe_with_prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img_binary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;txt&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ans&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;txt&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这里做了几件事：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;先把 &lt;code&gt;PIL.Image&lt;/code&gt; 编码成二进制&lt;/li&gt;
&lt;li&gt;优先尝试保存为 &lt;code&gt;JPEG&lt;/code&gt;，失败则退回 &lt;code&gt;PNG&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;调用 &lt;code&gt;vision_model.describe_with_prompt()&lt;/code&gt; 生成描述&lt;/li&gt;
&lt;li&gt;用 &lt;code&gt;clean_markdown_block()&lt;/code&gt; 清理模型输出中的 Markdown 包裹&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此这个函数返回的是一段纯文本，而不是结构化对象。&lt;/p&gt;
&lt;h4 id="vision_llm_figure_describe_prompt"&gt;&lt;code&gt;vision_llm_figure_describe_prompt()&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;在 &lt;code&gt;VisionFigureParser.__call__()&lt;/code&gt; 中，无上下文情况下使用的是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vision_llm_figure_describe_prompt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;而如果存在上下文，则切换到：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vision_llm_figure_describe_prompt_with_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;context_above&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;context_above&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;context_below&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;context_below&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这两组 prompt 都定义在 &lt;code&gt;rag/prompts/&lt;/code&gt; 下。其核心约束是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;只根据图中可见内容生成文本&lt;/li&gt;
&lt;li&gt;如果是表格、柱状图、折线图这类“可枚举数据图”，则按固定字段输出&lt;/li&gt;
&lt;li&gt;如果不是结构化数据图，则按空间顺序描述可见内容&lt;/li&gt;
&lt;li&gt;不允许额外推断流程、功能或语义&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;也就是说，这一步生成的不是泛化摘要，而是偏向&lt;strong&gt;检索友好&lt;/strong&gt;的图片文本表示。&lt;/p&gt;
&lt;h4 id="sectionsidx--"&gt;&lt;code&gt;sections[idx] = (...)&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;最终在 &lt;code&gt;rag/app/naive.py&lt;/code&gt; 中，增强结果是这样写回 section 的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;sections&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;section_text&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;fig&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;boosted_figures&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sections&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;因此 Markdown 图像增强不会引入新的切片层级，而是把图片描述文本直接拼回现有 section。&lt;/p&gt;
&lt;p&gt;在这一轮增强之后，&lt;code&gt;chunk()&lt;/code&gt; 才会真正进入 Markdown 专属的 chunk 合并逻辑：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_markdown&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;merged_chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;merged_images&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;chunk_limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parser_config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;chunk_token_num&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;current_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;current_tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;current_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sec&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sections&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;sec&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sec_tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;num_tokens_from_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sec_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;section_images&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;section_images&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;section_images&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这段代码表明，Markdown 的切片单位不是“原始全文直接按分隔符硬切”，而是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-plaintext" data-lang="plaintext"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Markdown 文本
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;按元素扫描成多个 section
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;每个 section 绑定对应图片
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;图片描述增强（如果启用）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;按 token 上限逐个累积合并
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;得到最终 chunk
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;RAGFlow 对 Markdown 没有直接调用通用的 &lt;code&gt;naive_merge_with_images()&lt;/code&gt;，而是单独写了一套更简单的逻辑。其规则是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果加入下一个 section 后仍未超过 &lt;code&gt;chunk_token_num&lt;/code&gt;，则继续追加&lt;/li&gt;
&lt;li&gt;如果会超过上限，就先把当前 chunk 落盘，再开启一个新的 chunk&lt;/li&gt;
&lt;li&gt;如果开启新 chunk 时配置了 &lt;code&gt;overlapped_percent&lt;/code&gt;，则保留上一 chunk 尾部的一部分文本作为重叠上下文&lt;/li&gt;
&lt;li&gt;与此同时，当前 chunk 内涉及的所有图片会被不断 &lt;code&gt;concat_img&lt;/code&gt; 合并&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关键代码如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current_text&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;current_tokens&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;sec_tokens&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;chunk_limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;merged_chunks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;merged_images&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;overlap_part&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;overlapped_percent&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;overlap_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;overlapped_percent&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;overlap_len&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;overlap_part&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current_text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;overlap_len&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;current_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;overlap_part&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;current_tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;num_tokens_from_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;current_image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current_image&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;overlap_part&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这里可以看出两个特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;重叠是按&lt;strong&gt;字符长度&lt;/strong&gt;截尾，而不是按 section 粒度重叠&lt;/li&gt;
&lt;li&gt;图片是按 chunk 聚合的，只要 section 被并入同一个 chunk，其图片也会被拼到同一张图上&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，一个最终的 Markdown chunk，本质上是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;text&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;若干相邻 section 合并后的文本&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;image&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;这些 section 内图片拼接后的结果（如果有）&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;在 chunk 合并完成之后，RAGFlow 会根据该批 chunk 是否含图走两条不同路径：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;has_images&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;merged_images&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;merged_images&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;has_images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokenize_chunks_with_images&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is_english&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;merged_images&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;child_delimiters_pattern&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;child_deli&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokenize_chunks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is_english&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pdf_parser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;child_delimiters_pattern&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;child_deli&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;其中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tokenize_chunks()&lt;/code&gt; 负责纯文本 chunk 的分词和字段封装&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tokenize_chunks_with_images()&lt;/code&gt; 则会把对应图片写入文档对象的 &lt;code&gt;image&lt;/code&gt; 字段&lt;/li&gt;
&lt;li&gt;表格则另外通过 &lt;code&gt;tokenize_table(tables, doc, is_english)&lt;/code&gt; 进入结果集&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;也就是说，Markdown 在 RAGFlow 中最后会被拆成三类可检索对象：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;普通文本 chunk&lt;/li&gt;
&lt;li&gt;携带图片的多模态 chunk&lt;/li&gt;
&lt;li&gt;表格对象&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="小结"&gt;小结
&lt;/h3&gt;&lt;p&gt;至此，RAGFlow 对 Markdown 的“切片”逻辑就比较清楚了。它并不是简单地按固定长度裁文本，而是分成了几层：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;先识别表格、标题、代码块、列表、引用块和普通文本块&lt;/li&gt;
&lt;li&gt;再根据图片引用所在行号，把图片绑定到对应 section&lt;/li&gt;
&lt;li&gt;然后按 token 上限把多个相邻 section 合并为 chunk&lt;/li&gt;
&lt;li&gt;最后把文本、图片、表格分别包装成可检索对象&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;从工程实现上看，这套方案的优点是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;实现简单，可维护性高&lt;/li&gt;
&lt;li&gt;比纯分隔符切片更保留 Markdown 结构&lt;/li&gt;
&lt;li&gt;能较自然地支持图文混合检索&lt;/li&gt;
&lt;li&gt;表格被单独抽出后，也便于做专门处理&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当然，它也有一些局限，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;图片归属依赖行号，精度有限&lt;/li&gt;
&lt;li&gt;section 的粒度较粗，未做更深层的语义切分&lt;/li&gt;
&lt;li&gt;表格与正文可能存在信息重复&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但对一个通用 RAG 系统来说，这样的取舍是相当合理的。它没有追求复杂而昂贵的 Markdown AST 解析，而是用较低复杂度完成了“结构感知切片”。&lt;/p&gt;
&lt;p&gt;笔者认为，这也是 RAGFlow 值得学习的一点：很多时候，切片策略不一定要非常“聪明”，但一定要足够稳定、可解释，并且方便与后续检索流程对接。&lt;/p&gt;</description></item><item><title>CS224N Assignment3 NMT</title><link>https://ottercoconut.github.io/p/cs224n-assignment3-nmt/</link><pubDate>Wed, 08 Apr 2026 09:46:07 +0800</pubDate><guid>https://ottercoconut.github.io/p/cs224n-assignment3-nmt/</guid><description>&lt;h1 id="cs-224n-spring-2024-assignment-3"&gt;CS 224n Spring 2024: Assignment #3
&lt;/h1&gt;&lt;p&gt;&lt;a class="link" href="https://web.stanford.edu/class/archive/cs/cs224n/cs224n.1246/assignments/a3_spr24_student_handout.pdf" target="_blank" rel="noopener"
 &gt;a3_spr24_student_handout.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;本post从cs224n独立出来，旨在尽可能掌握Assignment3中基于RNN的NMT背后各步的数学原理，以及将代码部分和数学部分对应起来。&lt;/p&gt;
&lt;p&gt;参考论文：&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://arxiv.org/pdf/1409.0473" target="_blank" rel="noopener"
 &gt;NEURAL MACHINE TRANSLATION BY JOINTLY LEARNING TO ALIGN AND TRANSLATE&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="neural-machine-translation-with-rnns"&gt;Neural Machine Translation with RNNs
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n-a3/figure1.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h3 id="model-description-training-procedure"&gt;Model description (training procedure)
&lt;/h3&gt;&lt;p&gt;Given a sentence in the source language, we look up the character or word embeddings from an &lt;strong&gt;embeddings matrix&lt;/strong&gt;, yielding $\mathbf{x}_1, \ldots, \mathbf{x}_m$ ($\mathbf{x}_i \in \mathbb{R}^{e \times 1}$), where $m$ is the length of the source sentence and $e$ is the embedding size.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;我们手里的一条源语言句子，由于计算机无法直接理解文字，我们首先要进行“查表”操作，也就是文本中提到的&lt;strong&gt;获取词嵌入&lt;/strong&gt;（look up &amp;hellip; embeddings matrix）。假设句子有 $m$ 个词，经过这一步，每个词都被映射成了一个长度为 $e$ 的列向量 $\mathbf{x}_i$。这样一来，整句话就被转换成了一个由实数向量构成的序列&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;We then feed the embeddings to a &lt;strong&gt;convolutional layer&lt;/strong&gt;$^1$ while maintaining their shapes.&lt;/p&gt;
&lt;p&gt;$^1$ : Checkout &lt;a class="link" href="https://cs231n.github.io/convolutional-networks" target="_blank" rel="noopener"
 &gt;Convolutional Neural Networks&lt;/a&gt; for an in-depth description for convolutional layers if you are not familiar.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;带着这些初步的向量表示，模型并没有直接把它们送入主要的编码器，而是先让它们穿过一个&lt;strong&gt;卷积层&lt;/strong&gt;（convolutional layer）。文本中特别强调了这一步“保持了它们的形状”，这意味着经过卷积处理后，我们依然拥有 $m$ 个向量，且每个向量的维度依然是 $e$。这一步的作用通常是对局部的特征进行一次平滑和提取，为后续更深层的语义理解打好基础。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;We feed the convolutional layer outputs to the &lt;strong&gt;bidirectional encoder&lt;/strong&gt;, yielding hidden states and cell states for both the forwards ($\rightarrow$) and backwards ($\leftarrow$) LSTMs. The forwards and backwards versions are concatenated to give hidden states $\mathbf{h}_i^{\text{enc}}$ and cell states $\mathbf{c}_i^{\text{enc}}$:&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;接下来，这些被初步加工过的特征向量正式进入了核心组件——&lt;strong&gt;双向编码器&lt;/strong&gt;（bidirectional encoder）。这里其实包含了两条流水线：一条是前向 LSTM（在数学符号中用向右的箭头 $\rightarrow$ 表示），它顺着我们阅读的习惯，从第一个词读到最后一个词，负责收集每个词左侧的“上文”信息；另一条是后向 LSTM（用向左的箭头 $\leftarrow$ 表示），它逆着顺序，从最后一个词倒着读回来，负责收集每个词右侧的“下文”信息。当这两条流水线各自运转完毕后，对于句子中的任意第 $i$ 个位置，我们就得到了两个不同视角的隐藏状态 $\mathbf{h}_i^{\text{enc}}$ 和细胞状态 $\mathbf{c}_i^{\text{enc}}$，前向( $\overrightarrow{\mathbf{h}_i^{\text{enc}}}$ , $\overrightarrow{\mathbf{c}_i^{\text{enc}}}$ )或后向( $\overleftarrow{\mathbf{h}_i^{\text{enc}}}$ , $\overleftarrow{\mathbf{c}_i^{\text{enc}}}$ )分别的状态量，维度都是 $h \times 1$ 。&lt;/p&gt;

 &lt;/blockquote&gt;
$$
\mathbf{h}_i^{\text{enc}} = [\overleftarrow{\mathbf{h}_i^{\text{enc}}} ; \overrightarrow{\mathbf{h}_i^{\text{enc}}}] \quad \text{where} \quad \mathbf{h}_i^{\text{enc}} \in \mathbb{R}^{2h \times 1}, \overleftarrow{\mathbf{h}_i^{\text{enc}}}, \overrightarrow{\mathbf{h}_i^{\text{enc}}} \in \mathbb{R}^{h \times 1} \quad 1 \leq i \leq m \quad (1)
$$$$
\mathbf{c}_i^{\text{enc}} = [\overleftarrow{\mathbf{c}_i^{\text{enc}}} ; \overrightarrow{\mathbf{c}_i^{\text{enc}}}] \quad \text{where} \quad \mathbf{c}_i^{\text{enc}} \in \mathbb{R}^{2h \times 1}, \overleftarrow{\mathbf{c}_i^{\text{enc}}}, \overrightarrow{\mathbf{c}_i^{\text{enc}}} \in \mathbb{R}^{h \times 1} \quad 1 \leq i \leq m \quad (2)
$$
 &lt;blockquote&gt;
 &lt;p&gt;$[ ; ]$ 在线性代数中通常表示向量或矩阵的拼接。&lt;strong&gt;为了让第 $i$ 个位置最终的表示既包含左侧上下文，又包含右侧上下文&lt;/strong&gt;，模型将同一时刻 $i$ 的前向状态和后向状态直接“拼接”在一起。因为前向和后向状态都是 $h \times 1$ 的列向量，将它们沿行方向拼接后，最终的&lt;strong&gt;联合隐藏状态&lt;/strong&gt; $\mathbf{h}_i^{\text{enc}}$ 和&lt;strong&gt;联合细胞状态&lt;/strong&gt; $\mathbf{c}_i^{\text{enc}}$ 的维度就翻倍了，变成了 $(h+h) \times 1 = \mathbf{2h \times 1}$。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;We then initialize the &lt;strong&gt;decoder&lt;/strong&gt;&amp;rsquo;s first hidden state $\mathbf{h}_0^{\text{dec}}$ and cell state $\mathbf{c}_0^{\text{dec}}$ with a linear projection of the encoder&amp;rsquo;s final hidden state and final cell state.$^2$&lt;/p&gt;
&lt;p&gt;$^2$ : If it’s not obvious, think about why we regard $[\overleftarrow{\mathbf{h}_1^{\text{enc}}} , \overrightarrow{\mathbf{h}_m^{\text{enc}}}]$ as the ‘final hidden state’ of the Encoder.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;双向编码器（Encoder）已经工作完毕，看完了整句源语言文本，并在每一个位置都留下了浓缩的上下文信息。接下来的任务就是把这些信息传递给&lt;strong&gt;解码器&lt;/strong&gt;（Decoder），让它开始生成翻译。传递的过程就是通过下面公式中，&lt;strong&gt;初始化解码器&lt;/strong&gt;在第0步的隐藏状态 $\mathbf{h}_0^{\text{dec}}$ 和细胞状态 $\mathbf{c}_0^{\text{dec}}$ 来完成的。解码器的初始状态是从编码器那里继承来的“最终状态”。&lt;/p&gt;

 &lt;/blockquote&gt;
$$
\mathbf{h}_0^{\text{dec}} = \mathbf{W}_h [\overleftarrow{\mathbf{h}_1^{\text{enc}}} ; \overrightarrow{\mathbf{h}_m^{\text{enc}}}] \quad \text{where} \quad \mathbf{h}_0^{\text{dec}} \in \mathbb{R}^{h \times 1}, \mathbf{W}_h \in \mathbb{R}^{h \times 2h} \quad (3)
$$$$
\mathbf{c}_0^{\text{dec}} = \mathbf{W}_c [\overleftarrow{\mathbf{c}_1^{\text{enc}}} ; \overrightarrow{\mathbf{c}_m^{\text{enc}}}] \quad \text{where} \quad \mathbf{c}_0^{\text{dec}} \in \mathbb{R}^{h \times 1}, \mathbf{W}_c \in \mathbb{R}^{h \times 2h} \quad (4)
$$
 &lt;blockquote&gt;
 &lt;p&gt;编码器在“读完”整句话后的最终状态，可见公式：前向 LSTM 是顺着语序从左到右读的，所以当它读完最后一个词时，它的最终状态自然就落在了句尾，也就是第 $m$ 个位置，记作 $\overrightarrow{\mathbf{h}_m^{\text{enc}}}$。相反，后向 LSTM 是倒着从右向左读的，它“通读全文”后的最后一站其实是句子的开头，也就是第 $1$ 个位置，记作 $\overleftarrow{\mathbf{h}_1^{\text{enc}}}$。&lt;/p&gt;
&lt;p&gt;为了把前向和后向这两股贯穿全文的“记忆”汇聚起来，我们按照公式将它们进行了拼接操作 $[\overleftarrow{\mathbf{h}_1^{\text{enc}}} ; \overrightarrow{\mathbf{h}_m^{\text{enc}}}]$。（需注意，在Decoder这一步和公式 (1) (2) 的上下文状态量不一样）&lt;/p&gt;
&lt;p&gt;通过这个拼接，我们得到了一个维度为 $2h \times 1$ 的长向量。同样地，对于细胞状态 $\mathbf{c}$，我们用完全相同的逻辑提取出 $[\overleftarrow{\mathbf{c}_1^{\text{enc}}} ; \overrightarrow{\mathbf{c}_m^{\text{enc}}}]$。那么对于 $2h \times 1$ 的向量，我们要将其转换成 $h\times 1$ 才能满足解码器的隐藏层容量。&lt;/p&gt;
&lt;p&gt;所以引入权重（投影）矩阵，用来做线性投影(linear projection)，维度是 $h \times 2h$ ，再通过矩阵相乘，映射出 $h\times 1$ 的向量。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;With the decoder initialized, we must now feed it a target sentence.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;成功初始化了解码器的第 0 步状态（$\mathbf{h}_0^{\text{dec}}$ 和 $\mathbf{c}_0^{\text{dec}}$）之后。现在，解码器已经准备好生成（或在训练时接收）目标语言的句子了。下面内容讲的就是在任意的第 $t$ 步，解码器是如何“吃进”数据并更新自己状态的。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;On the $t^{th}$ step, we look up the embedding for the $t^{th}$ subword, $\mathbf{y}_t \in \mathbb{R}^{e \times 1}$.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;要让解码器在第 $t$ 步进行工作，我们首先得给它提供当前的输入词，同样需要查表，把目标语言的第 $t$ 个子词（subword）变成一个维度为 $e$ 的词嵌入向量，记作 $\mathbf{y}_t$。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;We then concatenate $\mathbf{y}_t$ with the &lt;em&gt;combined-output vector&lt;/em&gt; $\mathbf{o}_{t-1} \in \mathbb{R}^{h \times 1}$ from the previous timestep (we will explain what this is later down this page!) to produce $\overline{\mathbf{y}_t} \in \mathbb{R}^{(e+h) \times 1}$.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;但是，如果只把 $\mathbf{y}_t$ 喂给解码器，它会缺乏连贯性。为了让解码器知道“我刚才干了什么”，文本中引入了一个非常关键的设计：把当前的词向量 $\mathbf{y}_t$ 与上一步（第 $t-1$ 步）的维度为 $h$ 的&lt;strong&gt;联合输出向量 (combined-output vector)&lt;/strong&gt; $\mathbf{o}_{t-1}$ 拼接在一起，得到新的输入向量 $\overline{\mathbf{y}_t}$，它的维度变成了 $e+h$。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;Note that for the first target subword (i.e. the start token) $\mathbf{o}_0$ is a zero-vector. We then feed $\overline{\mathbf{y}_t}$ as input to the decoder.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;注意到当 $t=1$ ，也就是解码器刚开始吐出第一个词（或者接收 start token）时，因为前面还没有任何输出，所以初始的 $\mathbf{o}_0$ 就简单地设定为一个全零向量。&lt;/p&gt;

 &lt;/blockquote&gt;
$$
\mathbf{h}_t^{\text{dec}}, \mathbf{c}_t^{\text{dec}} = \text{Decoder}(\overline{\mathbf{y}_t}, \mathbf{h}_{t-1}^{\text{dec}}, \mathbf{c}_{t-1}^{\text{dec}}) \quad \text{where} \quad \mathbf{h}_t^{\text{dec}} \in \mathbb{R}^{h \times 1}, \mathbf{c}_t^{\text{dec}} \in \mathbb{R}^{h \times 1} \quad (5)
$$
 &lt;blockquote&gt;
 &lt;p&gt;关于向Decoder中输入了三个变量后，在LSTM的Decoder里进行了什么计算，需结合&lt;a class="link" href="https://ottercoconut.github.io/p/cs224n/" target="_blank" rel="noopener"
 &gt;CS224N&lt;/a&gt;中LSTM的部分进行理解：(generated by Gemini)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;遗忘门 (Forget Gate)
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;参与者：&lt;/strong&gt; 新输入$\overline{\mathbf{y}_t}$和旧的短期记忆$\mathbf{h}_{t-1}^{\text{dec}}$。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;动作：&lt;/strong&gt; 把这两个变量拼接在一起，乘上一个权重矩阵，加上偏置，然后送入一个 &lt;strong&gt;Sigmoid 激活函数&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;产出：&lt;/strong&gt; 得到一个介于 0 到 1 之间的向量 $f_t$。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;意义：&lt;/strong&gt; 这个 $f_t$ 会盯着传送带上的旧长期记忆 $\mathbf{c}_{t-1}^{\text{dec}}$ 看。0 代表“彻底忘掉”，1 代表“完全保留”。比如遇到新的主语，它可能就会决定忘掉旧主语的单复数信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;输入门与候选记忆 (Input Gate &amp;amp; Candidate Memory)
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;参与者：&lt;/strong&gt; 依然是 $\overline{\mathbf{y}_t}$ 和 $\mathbf{h}_{t-1}^{\text{dec}}$。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;动作：&lt;/strong&gt; 这里分两头行动：
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;输入门 $i_t$：&lt;/strong&gt; 再次经过一个 Sigmoid 函数，产生 0 到 1 的值，决定我们&lt;strong&gt;有多希望&lt;/strong&gt;把新信息存进去。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;候选记忆 $\tilde{\mathbf{c}}_t$：&lt;/strong&gt; 经过一个 &lt;strong&gt;tanh 激活函数&lt;/strong&gt;，产生 -1 到 1 的值，这代表从当前输入中提取出的&lt;strong&gt;全部潜在新知识&lt;/strong&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;意义：&lt;/strong&gt; 这两步结合，就是要把提炼出的新知识（$\tilde{\mathbf{c}}_t$）按照我们的渴望程度（$i_t$）进行打包，准备放到传送带上。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;状态更新 (Cell State Update)
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;参与者：&lt;/strong&gt; 旧记忆 $\mathbf{c}_{t-1}^{\text{dec}}$，遗忘门 $f_t$，输入门 $i_t$，候选记忆 $\tilde{\mathbf{c}}_t$。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;动作：&lt;/strong&gt; 纯粹的数学运算。首先用旧记忆乘以遗忘门：$f_t * \mathbf{c}_{t-1}^{\text{dec}}$ （执行“丢弃”动作）；然后加上新的包裹：$i_t * \tilde{\mathbf{c}}_t$ （执行“装载”动作）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;产出：&lt;/strong&gt; 我们得到了&lt;strong&gt;当前时刻的全新细胞状态 $\mathbf{c}_t^{\text{dec}}$&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;意义：&lt;/strong&gt; 长期记忆的传送带在这里完成了向前推进，旧的糟粕被剔除，新的信息被注入。这就是 LSTM 能够跨越长距离保持梯度的核心。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;输出门与隐藏状态 (Output Gate &amp;amp; Hidden State)
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;参与者：&lt;/strong&gt; $\overline{\mathbf{y}_t}$，$\mathbf{h}_{t-1}^{\text{dec}}$，以及刚刚出炉的新细胞状态 $\mathbf{c}_t^{\text{dec}}$。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;动作：&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;用 $\overline{\mathbf{y}_t}$ 和 $\mathbf{h}_{t-1}^{\text{dec}}$ 经过 Sigmoid 算出一个输出门 $o_t$（决定展示的比例）。&lt;/li&gt;
&lt;li&gt;把刚刚做好的新细胞状态 $\mathbf{c}_t^{\text{dec}}$ 用 tanh 函数“压”到 -1 到 1 之间。&lt;/li&gt;
&lt;li&gt;两者相乘：$\mathbf{h}_t^{\text{dec}} = o_t * \tanh(\mathbf{c}_t^{\text{dec}})$。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;产出：&lt;/strong&gt; 我们得到了&lt;strong&gt;当前时刻的全新隐藏状态 $\mathbf{h}_t^{\text{dec}}$&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;意义：&lt;/strong&gt; 细胞状态 $\mathbf{c}_t$ 包含的信息太庞杂了（有些可能是给未来留的伏笔），我们不能全部暴露。输出门 $o_t$ 就像一个滤网，只把当前这一步预测下一个词&lt;strong&gt;最需要&lt;/strong&gt;的那部分特征提取出来，作为对外的公开展示（$\mathbf{h}_t$）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;p&gt;We then use $\mathbf{h}_t^{\text{dec}}$ to compute multiplicative attention over $\mathbf{h}_1^{\text{enc}}, \dots, \mathbf{h}_m^{\text{enc}}$:
&lt;/p&gt;
$$
\mathbf{e}_{t,i} = (\mathbf{h}_t^{\text{dec}})^T \mathbf{W}_{\text{attProj}} \mathbf{h}_i^{\text{enc}} \quad \text{where} \quad \mathbf{e}_t \in \mathbb{R}^{m \times 1}, \mathbf{W}_{\text{attProj}} \in \mathbb{R}^{h \times 2h} \quad 1 \leq i \leq m \quad (6)
$$&lt;p&gt;
$\mathbf{e}_{t,i}$ is a scalar, the $i$ th element of $\mathbf{e}_t \in \mathbb{R}^{m \times 1}$, computed using the hidden state of the decoder at the $t$ th step, $\mathbf{h}_t^{\text{dec}} \in \mathbb{R}^{h \times 1}$, the attention projection $\mathbf{W}_{\text{attProj}} \in \mathbb{R}^{h \times 2h}$, and the hidden state of the encoder at the $i$ th step, $\mathbf{h}_i^{\text{enc}} \in \mathbb{R}^{2h \times 1}$.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;公式(6)是注意力机制的Scoring，解码器现在的状态是 $\mathbf{h}_t^{\text{dec}}$，它需要和字典里的每一个词 $\mathbf{h}_i^{\text{enc}}$进行比对，看看有多匹配。&lt;/p&gt;
&lt;p&gt;$(\mathbf{h}_t^{\text{dec}})^T$ , $\mathbf{W}_{\text{attProj}}$ , $\mathbf{h}_i^{\text{enc}}$ 这三者相乘后维度为 $1\times 1$ ，即Scoring出的标量 $\mathbf{e}_{t,i}$ ，它代表了在生成第 $t$ 个翻译词时，源语言句子中第 $i$ 个词的重要程度。 我们把对所有 $m$ 个词的打分收集起来，就得到了一个长度为 $m$ 的得分向量 $\mathbf{e}_t$ 。&lt;/p&gt;

 &lt;/blockquote&gt;
$$
\alpha_t = \text{softmax}(\mathbf{e}_t) \quad \text{where} \quad \alpha_t \in \mathbb{R}^{m \times 1} \quad (7)
$$
 &lt;blockquote&gt;
 &lt;p&gt;为了把公式 (6) 的得分变成标准的“注意力分配比例”，公式 (7) 引入了 &lt;code&gt;softmax&lt;/code&gt; 函数。它把向量 $\mathbf{e}_t$ 里的所有数字全部转换为 $0$ 到 $1$ 之间的正数，并且保证它们的&lt;strong&gt;总和严格等于 $1$&lt;/strong&gt;。转换后的结果就是 $\alpha_t$（被称为注意力分布 Attention Distribution）。&lt;/p&gt;

 &lt;/blockquote&gt;
$$
\mathbf{a}_t = \sum_{i=1}^m \alpha_{t,i} \mathbf{h}_i^{\text{enc}} \quad \text{where} \quad \mathbf{a}_t \in \mathbb{R}^{2h \times 1} \quad (8)
$$
 &lt;blockquote&gt;
 &lt;p&gt;公式 (8) 用刚算出来的注意力百分比 $\alpha_{t,i}$，去对字典里的词 $\mathbf{h}_i^{\text{enc}}$ 进行&lt;strong&gt;加权求和&lt;/strong&gt;。把这 $m$ 个按比例缩放的向量全部加起来，我们就得到了最终的&lt;strong&gt;注意力输出向量&lt;/strong&gt;（Attention Output / Context Vector），记作 $\mathbf{a}_t$。
由于被加和的 $\mathbf{h}_i^{\text{enc}}$ 都是 $2h \times 1$ 维的，所以最终得到的 $\mathbf{a}_t$ 也是 &lt;strong&gt;$2h \times 1$&lt;/strong&gt; 维。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;We now concatenate the attention output $\mathbf{a}_t$ with the decoder hidden state $\mathbf{h}_t^{\text{dec}}$ and pass this through a linear layer, tanh, and dropout to attain the &lt;em&gt;combined-output&lt;/em&gt; vector $\mathbf{o}_t$.
&lt;/p&gt;
$$
\mathbf{u}_t = [\mathbf{a}_t ; \mathbf{h}_t^{\text{dec}}] \quad \text{where} \quad \mathbf{u}_t \in \mathbb{R}^{3h \times 1} \quad (9)
$$
 &lt;blockquote&gt;
 &lt;p&gt;将注意力输出向量和解码器隐藏状态结合，得到维度为 $3h\times 1$ 的 $u_t$&lt;/p&gt;

 &lt;/blockquote&gt;
$$
\mathbf{v}_t = \mathbf{W}_u \mathbf{u}_t \quad \text{where} \quad \mathbf{v}_t \in \mathbb{R}^{h \times 1}, \mathbf{W}_u \in \mathbb{R}^{h \times 3h} \quad (10)
$$
 &lt;blockquote&gt;
 &lt;p&gt;加入了一个线性投影矩阵 $\mathbf{W}_u$（维度是 $h \times 3h$ ，当它和 $\mathbf{u}_t$ 相乘时，把维度压缩回了标准尺寸 $h \times 1$&lt;/p&gt;

 &lt;/blockquote&gt;
$$
\mathbf{o}_t = \text{dropout}(\tanh(\mathbf{v}_t)) \quad \text{where} \quad \mathbf{o}_t \in \mathbb{R}^{h \times 1} \quad (11)
$$
 &lt;blockquote&gt;
 &lt;p&gt;首先给它套上一个 &lt;code&gt;tanh&lt;/code&gt; 激活函数，将其内部的数值平滑地压缩到 -1 到 1 之间，这赋予了模型非线性的表达能力。紧接着，再让它穿过一层 &lt;code&gt;dropout&lt;/code&gt;。&lt;code&gt;dropout&lt;/code&gt; 是一种防止模型过拟合的正则化技术，它在训练时会随机屏蔽掉一部分神经元，逼迫模型学到更鲁棒、更泛化的特征。&lt;/p&gt;
&lt;p&gt;最后得到&lt;strong&gt;联合输出向量&lt;/strong&gt;(combined-output vector) $\mathbf{o}_t$&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;Then, we produce a probability distribution $\mathbf{P}_t$ over target subwords at the $t^{th}$ timestep:
&lt;/p&gt;
$$
\mathbf{P}_t = \text{softmax}(\mathbf{W}_{\text{vocab}}\mathbf{o}_t) \quad \text{where} \quad \mathbf{P}_t \in \mathbb{R}^{V_t \times 1}, \mathbf{W}_{\text{vocab}} \in \mathbb{R}^{V_t \times h} \quad (12)
$$
 &lt;blockquote&gt;
 &lt;p&gt;我们要把一个 $h$ 维的向量，变成目标语言词典里的一个具体词汇。我们的目标语言词典（Vocabulary）里一共有 $V_t$ 个单词。公式 (12) 引入了一个最终的变换矩阵 $\mathbf{W}_{\text{vocab}}$，它的维度是 $V_t \times h$。相乘后输出一个 $[V_t \times 1]$ 的列向量。这个向量里的每一个数字，就代表了模型对词典里对应单词的“打分”（Logits）。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;Here, $V_t$ is the size of the target vocabulary. Finally, to train the network we then compute the cross entropy loss between $\mathbf{P}_t$ and $\mathbf{g}_t$, where $\mathbf{g}_t$ is the one-hot vector of the target subword at timestep $t$:
&lt;/p&gt;
$$
J_t(\theta) = \text{CrossEntropy}(\mathbf{P}_t, \mathbf{g}_t) \quad (13)
$$
 &lt;blockquote&gt;
 &lt;p&gt;训练过程使用了&lt;strong&gt;交叉熵损失 (Cross Entropy Loss)&lt;/strong&gt; 函数。简单来说，交叉熵会去对比 $\mathbf{P}_t$ 和 $\mathbf{g}_t$ (one-hot vector)之间的差距。计算出损失 $J_t(\theta)$ 之后，在接下来的代码实现中，模型就会利用反向传播机制，顺着网络一路往回找，去微调那些导致错误的参数 $\theta$。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="implementation-and-written-questions"&gt;Implementation and written questions
&lt;/h3&gt;&lt;h4 id="__init__"&gt;&lt;code&gt;__init__()&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;在问题 (c) 的&lt;code&gt;nmt_model.py&lt;/code&gt;的&lt;code&gt;__inti__()&lt;/code&gt;中，关于神经网络各层的定义，其中&lt;code&gt;self.att_projection&lt;/code&gt;的定义需注意，虽然它对应的是 $W_{attProj}$ ，但是在编写代码时，要拆解结合律，决定计算顺序。&lt;/p&gt;
&lt;p&gt;应该先算$\mathbf{W}_{\text{attProj}} $ 和 $\mathbf{h}_i^{\text{enc}}$ 相乘，再将其乘积与 $(\mathbf{h}_t^{dec})^T$ 相乘求最终结果，这是因为所有的编码器状态 $\mathbf{h}_i^{\text{enc}}$ 在 Decoder 开始工作前就已经全部计算好了。你可以&lt;strong&gt;一次性&lt;/strong&gt;把整句话的 $\mathbf{h}^{\text{enc}}$ 丢进 &lt;code&gt;Linear&lt;/code&gt; 层进行投影（这叫 Pre-computation 预计算）。但是在某一时刻只有一个 $\mathbf{h}_t^{dec}$ 而没有未来的量，导致不能一次性投影完成，而只能把线性层放到了循环中，引发严重的性能问题（虽然数学原理上没错）。下面是一个例子(generated by Gemini) :&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;假设我们的模型参数如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;隐藏层大小 $h = 512$&lt;/li&gt;
&lt;li&gt;句子长度 $m = 50$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;把 &lt;code&gt;Linear&lt;/code&gt; 层塞进循环里&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在这个路线里，&lt;code&gt;Linear&lt;/code&gt; 层每次要干的活是：把解码器 $1 \times 512$ 的向量，乘以一个 $512 \times 1024$ 的巨大投影矩阵 $\mathbf{W}$。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;计算量&lt;/strong&gt;：这需要进行 $512 \times 1024 = \mathbf{524,288}$ 次乘加运算！&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;额外开销&lt;/strong&gt;：每次循环，PyTorch 都要去内存里把这个包含 50 多万个参数的 $\mathbf{W}$ 矩阵重新搬出来读一遍，并且要经过一层完整的 &lt;code&gt;nn.Linear&lt;/code&gt; 封装代码（包含各种维度检查、梯度跟踪的准备）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然后，算出投影结果后，还得再去和字典做点积：$1 \times 1024$ 的向量乘以 $1024 \times 50$ 的字典，又是 $\mathbf{51,200}$ 次运算。&lt;/p&gt;
&lt;p&gt;所以在这个路线下，解码器每走一步，都要背着将近 &lt;strong&gt;60万次运算&lt;/strong&gt; 和一个巨大的矩阵跑。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;预计算 + 循环内纯点积&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们把庞大的 &lt;code&gt;Linear&lt;/code&gt; 投影放在循环外面，利用 GPU 的超级并行能力，**“一瞬间”**把整本字典从 $50 \times 1024$ 压成了 $50 \times 512$。我们把这本新字典称为 &lt;strong&gt;“投影后字典”&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;现在我们进入了 &lt;code&gt;for&lt;/code&gt; 循环。在第 $t$ 步，我们需要做的乘法是什么呢？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;计算量&lt;/strong&gt;：我们直接拿解码器原生的 $1 \times 512$ 向量，去乘以准备好的“投影后字典”（$512 \times 50$）。只需要进行 $512 \times 50 = \mathbf{25,600}$ 次乘加运算！&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;没有额外的层开销&lt;/strong&gt;：这里不需要调用 &lt;code&gt;nn.Linear&lt;/code&gt;，我们在代码里只要写一个极其轻量的纯矩阵乘法指令（比如 &lt;code&gt;torch.matmul&lt;/code&gt; 或 &lt;code&gt;@&lt;/code&gt; 符号）就搞定了。不需要加载任何权重矩阵，因为权重矩阵的任务在循环外已经完成了！&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;h4 id="encode"&gt;&lt;code&gt;encode&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;问题 (d) 是encoder部分，以及对decoder部分的初始化：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model_embeddings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ModelEmbeddings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;embed_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vocab&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;self.model_embeddings&lt;/code&gt;是对&lt;code&gt;ModelEmbeddings&lt;/code&gt;的一个实例化，而回到问题 (a) 发现&lt;code&gt;.source&lt;/code&gt;是一个&lt;code&gt;nn.Embedding&lt;/code&gt;对象：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Embedding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_embeddings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vocab&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;embedding_dim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;embed_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;padding_idx&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;src_pad_token_idx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;但是在问题 (a) 中只是对它的实例化，在内存中申请了一个形状为 &lt;code&gt;(num_embeddings, embedding_dim)&lt;/code&gt; 的&lt;strong&gt;大矩阵&lt;/strong&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model_embeddings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source_padded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;又因为 &lt;code&gt;nn.Embedding&lt;/code&gt; 继承自 &lt;code&gt;nn.Module&lt;/code&gt;，而 &lt;code&gt;nn.Module&lt;/code&gt; 重写了 &lt;code&gt;__call__&lt;/code&gt; 方法，所以你可以像函数一样使用它（调用），参数设为&lt;code&gt;source_padded&lt;/code&gt;这样一个Tensor，它把 Tensor 里的每一个数字当成“行号”，去刚才创建的那个大矩阵里把对应的行找出来，然后输出包含词向量的 Tensor。&lt;/p&gt;
&lt;p&gt;下面在将Tensor送进Encoder之前，要用&lt;code&gt;torch.permute&lt;/code&gt;变换形状，从&lt;code&gt;(src_len, b, e)&lt;/code&gt;变到&lt;code&gt;(b, e, src_len)&lt;/code&gt;。那么&lt;code&gt;torch.permute&lt;/code&gt;的参数，只是参数位置（索引号）。如下，将原来索引为1的&lt;code&gt;b&lt;/code&gt;放到第0个位置，原来索引为2的放到第1个位置，原来索引为0的放到第2个位置。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;permute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;之后将Tensor &lt;code&gt;X&lt;/code&gt;送进LSTM的Encoder后，得到输出：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="n"&gt;last_hidden&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;last_cell&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;output&lt;/code&gt;对应的就是双向LSTM的全局上下文向量： $\mathbf{h}_1^{\text{enc}}, \ldots, \mathbf{h}_m^{\text{enc}}$&lt;/p&gt;
&lt;p&gt;&lt;code&gt;last_hidden&lt;/code&gt;对应的是：$\overrightarrow{\mathbf{h}_m^{\text{enc}}}$ 和 $\overleftarrow{\mathbf{h}_1^{\text{enc}}}$ ，它的形状是 &lt;code&gt;(num_layers * num_directions, batch_size, hidden_size)&lt;/code&gt; ，由于它是双向的，所以索引0和索引1分别对应，我们需要将其分离再拼接，形成我们需要的$\overleftarrow{\mathbf{h}_1^{\text{enc}}} ; \overrightarrow{\mathbf{h}_m^{\text{enc}}}$ 。注意&lt;code&gt;torch.cat&lt;/code&gt;的参数&lt;code&gt;dim=1&lt;/code&gt;表示为横向拼接，即拼接好的向量的列数变成了&lt;code&gt;2 * hidden_size&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;与投影矩阵相乘的部分，由实例化好的线性层&lt;code&gt;self.h_projection&lt;/code&gt;完成。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;init_decoder_hidden&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;h_projection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;last_hidden&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;last_hidden&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;&lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;last_cell&lt;/code&gt;同理，不再赘述。&lt;/p&gt;
&lt;h4 id="decode"&gt;&lt;code&gt;decode&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;问题 (e) 是decode部分：
&lt;code&gt;enc_hiddens_proj = self.att_projection(enc_hiddens)&lt;/code&gt; 对应公式 (6) 中 $\mathbf{W}_{\text{attProj}} \mathbf{h}_i^{\text{enc}}$ 的部分。正如在 &lt;code&gt;__init__()&lt;/code&gt; 部分讨论的，编码器的全部隐藏状态在进入 &lt;code&gt;decode&lt;/code&gt; 时已经固定，所以可以&lt;strong&gt;在循环外一次性&lt;/strong&gt;完成投影预计算，将 &lt;code&gt;enc_hiddens&lt;/code&gt; 从 &lt;code&gt;(b, src_len, 2h)&lt;/code&gt; 投影为 &lt;code&gt;(b, src_len, h)&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Y = self.model_embeddings.target(target_padded)&lt;/code&gt; 和 &lt;code&gt;encode&lt;/code&gt; 中对源语言做查表的操作对称，这里调用&lt;strong&gt;目标语言&lt;/strong&gt;的嵌入矩阵，将 &lt;code&gt;target_padded&lt;/code&gt; 中的词索引映射成词向量，得到形状为 &lt;code&gt;(tgt_len, b, e)&lt;/code&gt; 的张量 &lt;code&gt;Y&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;torch.split(Y, 1)&lt;/code&gt; 沿第 0 维（时间维度）将 &lt;code&gt;Y&lt;/code&gt; 切成一系列 &lt;code&gt;(1, b, e)&lt;/code&gt; 的张量。&lt;code&gt;squeeze(Y_t, 0)&lt;/code&gt; 去掉多余的维度变为 &lt;code&gt;(b, e)&lt;/code&gt;。注意&lt;strong&gt;必须指定 &lt;code&gt;dim=0&lt;/code&gt;&lt;/strong&gt;，否则当 &lt;code&gt;batch_size = 1&lt;/code&gt; 时会误删 batch 维度。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;torch.cat((Y_t, o_prev), dim=1)&lt;/code&gt; 对应前文的拼接操作：将 $\mathbf{y}_t$（维度 $e$）与 $\mathbf{o}_{t-1}$（维度 $h$）拼接为 $\overline{\mathbf{y}_t} \in \mathbb{R}^{(e+h)}$。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;self.step(...)&lt;/code&gt; 内部一次性完成公式 (5)-(11) 的计算：Decoder LSTM 前向传播 → 注意力评分与分布 → 加权求和得到上下文向量 → 线性投影、tanh、dropout，最终产出联合输出向量 $\mathbf{o}_t$。每步将 $\mathbf{o}_t$ 存入列表并更新 &lt;code&gt;o_prev&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;torch.stack(combined_outputs, dim=0)&lt;/code&gt; 将列表中所有 &lt;code&gt;(b, h)&lt;/code&gt; 的张量堆叠为 &lt;code&gt;(tgt_len, b, h)&lt;/code&gt;，随后送入公式 (12) 的词汇投影层生成概率分布。&lt;/p&gt;
&lt;h4 id="step"&gt;&lt;code&gt;step&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;问题 (f) 是step部分，即解码器单步计算，内部完成公式 (5)-(11)。核心代码分两段：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一段（~3行）：Decoder LSTM 前向 + 注意力评分&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dec_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Ybar_t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dec_state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dec_hidden&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dec_cell&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dec_state&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;e_t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bmm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;enc_hiddens_proj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unsqueeze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dec_hidden&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;squeeze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;前两行直接对应公式 (5)：将 $\overline{\mathbf{y}_t}$ 和上一步状态送入 Decoder LSTM，得到新的 &lt;code&gt;dec_state&lt;/code&gt;，再拆分为 &lt;code&gt;dec_hidden&lt;/code&gt;（$\mathbf{h}_t^{\text{dec}}$）和 &lt;code&gt;dec_cell&lt;/code&gt;（$\mathbf{c}_t^{\text{dec}}$），形状均为 &lt;code&gt;(b, h)&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;第三行对应公式 (6) 中的注意力评分。这里的关键在于 &lt;code&gt;torch.bmm&lt;/code&gt; 的形状要求——它执行&lt;strong&gt;批量矩阵乘法&lt;/strong&gt;，要求输入严格为三维张量 &lt;code&gt;(b, n, m)&lt;/code&gt; × &lt;code&gt;(b, m, p)&lt;/code&gt; → &lt;code&gt;(b, n, p)&lt;/code&gt;。而我们手里的张量：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;enc_hiddens_proj&lt;/code&gt;：形状 &lt;code&gt;(b, src_len, h)&lt;/code&gt; — 已经是三维，无需处理&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dec_hidden&lt;/code&gt;：形状 &lt;code&gt;(b, h)&lt;/code&gt; — 只有二维，不满足 &lt;code&gt;bmm&lt;/code&gt; 的要求&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以需要 &lt;code&gt;torch.unsqueeze(dec_hidden, 2)&lt;/code&gt; 在第 2 维（最后）插入一个维度，将 &lt;code&gt;(b, h)&lt;/code&gt; 变为 &lt;code&gt;(b, h, 1)&lt;/code&gt;。这样 &lt;code&gt;bmm&lt;/code&gt; 的乘法就变成了：&lt;/p&gt;
$$\underbrace{(b, \text{src\_len}, h)}_{\text{enc\_hiddens\_proj}} \times \underbrace{(b, h, 1)}_{\text{dec\_hidden}} = \underbrace{(b, \text{src\_len}, 1)}_{e_t}$$&lt;p&gt;这实质上就是对 batch 内的每一条样本，让 &lt;code&gt;enc_hiddens_proj&lt;/code&gt; 的每一行（某个源词的投影）与 &lt;code&gt;dec_hidden&lt;/code&gt; 做点积，得到该源词的注意力分数——正是公式 (6) 的 $(\mathbf{h}_t^{\text{dec}})^T \mathbf{W}_{\text{attProj}} \mathbf{h}_i^{\text{enc}}$。&lt;/p&gt;
&lt;p&gt;最后 &lt;code&gt;.squeeze(2)&lt;/code&gt; 去掉末尾多余的维度 &lt;code&gt;1&lt;/code&gt;，从 &lt;code&gt;(b, src_len, 1)&lt;/code&gt; 变回 &lt;code&gt;(b, src_len)&lt;/code&gt;，得到注意力得分向量 $\mathbf{e}_t$。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二段（~6行）：注意力加权 → 联合输出&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;alpha_t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;softmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e_t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;a_t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bmm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unsqueeze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alpha_t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;enc_hiddens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;squeeze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;U_t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;a_t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dec_hidden&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;V_t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;combined_output_projection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;U_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;O_t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dropout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tanh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;V_t&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;F.softmax(e_t, dim=1)&lt;/code&gt; 对应公式 (7)，沿 &lt;code&gt;dim=1&lt;/code&gt;（即 &lt;code&gt;src_len&lt;/code&gt; 维度）做 softmax，将分数归一化为注意力分布 $\alpha_t$，形状仍为 &lt;code&gt;(b, src_len)&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;计算上下文向量 $\mathbf{a}_t$（公式 (8)）时又遇到了 &lt;code&gt;bmm&lt;/code&gt; 的三维要求。&lt;code&gt;alpha_t&lt;/code&gt; 是 &lt;code&gt;(b, src_len)&lt;/code&gt;，需要 &lt;code&gt;unsqueeze(alpha_t, 1)&lt;/code&gt; 在第 1 维插入，变为 &lt;code&gt;(b, 1, src_len)&lt;/code&gt;：&lt;/p&gt;
$$\underbrace{(b, 1, \text{src_len})}_{\alpha_t} \times \underbrace{(b, \text{src_len}, 2h)}_{\text{enc_hiddens}} = \underbrace{(b, 1, 2h)}_{a_t}$$&lt;p&gt;这就是用注意力权重对编码器隐藏状态做加权求和。&lt;code&gt;.squeeze(1)&lt;/code&gt; 去掉中间的 &lt;code&gt;1&lt;/code&gt;，得到 &lt;code&gt;(b, 2h)&lt;/code&gt; 的上下文向量 $\mathbf{a}_t$。&lt;/p&gt;
&lt;p&gt;后三行依次对应公式 (9)(10)(11)：&lt;code&gt;torch.cat&lt;/code&gt; 拼接 $\mathbf{a}_t$ 与 $\mathbf{h}_t^{\text{dec}}$ 得到 &lt;code&gt;(b, 3h)&lt;/code&gt; 的 $\mathbf{u}_t$；线性层投影回 &lt;code&gt;(b, h)&lt;/code&gt; 的 $\mathbf{v}_t$；最后 tanh + dropout 得到联合输出 $\mathbf{o}_t$。&lt;/p&gt;
&lt;h4 id="attention-masking"&gt;Attention Masking
&lt;/h4&gt;&lt;p&gt;问题 (g) 是关于 &lt;code&gt;step()&lt;/code&gt; 中注意力掩码的作用。在 &lt;code&gt;step()&lt;/code&gt; 的两段代码之间，有这样一段：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;enc_masks&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;e_t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;masked_fill_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;enc_masks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;inf&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;enc_masks&lt;/code&gt; 由 &lt;code&gt;generate_sent_masks()&lt;/code&gt; 生成：它创建一个 &lt;code&gt;(b, src_len)&lt;/code&gt; 的零矩阵，然后对 batch 中每条句子，在其&lt;strong&gt;实际长度之后&lt;/strong&gt;的位置全部填 &lt;code&gt;1&lt;/code&gt;。换言之，&lt;code&gt;1&lt;/code&gt; 标记的是 &lt;code&gt;&amp;lt;pad&amp;gt;&lt;/code&gt; token 的位置，&lt;code&gt;0&lt;/code&gt; 标记的是真实词的位置。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;掩码对注意力计算的影响：&lt;/strong&gt; &lt;code&gt;masked_fill_&lt;/code&gt; 将 $\mathbf{e}_t$ 中所有对应 &lt;code&gt;&amp;lt;pad&amp;gt;&lt;/code&gt; 位置的注意力分数替换为 $-\infty$。当这些 $-\infty$ 的值随后经过 &lt;code&gt;softmax&lt;/code&gt; 时，$e^{-\infty} = 0$，因此 &lt;code&gt;&amp;lt;pad&amp;gt;&lt;/code&gt; 位置的注意力权重 $\alpha_{t,i}$ 会变为 $0$，而所有真实词的权重之和仍归一化为 $1$。这意味着在公式 (8) 的加权求和中，&lt;code&gt;&amp;lt;pad&amp;gt;&lt;/code&gt; 位置的编码器隐藏状态对上下文向量 $\mathbf{a}_t$ 完全没有贡献。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么必须这样做：&lt;/strong&gt; 由于 batch 内各句子长度不一，短句会被 &lt;code&gt;&amp;lt;pad&amp;gt;&lt;/code&gt; 填充到统一长度。如果不加掩码，&lt;code&gt;&amp;lt;pad&amp;gt;&lt;/code&gt; 对应位置的编码器隐藏状态（本质上是无意义的噪声）会分走一部分注意力权重，从而污染上下文向量，导致翻译质量下降。&lt;/p&gt;
&lt;h4 id="training"&gt;Training
&lt;/h4&gt;&lt;p&gt;问题 (h) 是在代码工作完成后，进入训练阶段。由于我没有海外支付方式，用不了cs224n指定的Google Cloud，所以使用本机显卡进行训练（速度快于文档的预估值）&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash run.sh train
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;观察&lt;code&gt;tensorboard&lt;/code&gt;可见loss曲线并无异常，待训练完成后进行测试评估：
&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n-a3/figure2.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash run.sh &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;结果：the model’s corpus BLEU Score is larger than 18, tests passed.&lt;/p&gt;
&lt;h4 id="attention-comparison"&gt;Attention Comparison
&lt;/h4&gt;&lt;p&gt;最后问题 (i) 是点积注意力、加性注意力分别与乘性注意力进行比较：&lt;/p&gt;
&lt;h5 id="dot-product-vs-multiplicative"&gt;Dot Product vs. Multiplicative
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;Dot Product Attention: $\mathbf{e}_{t,i} = \mathbf{s}_t^T \mathbf{h}_i$&lt;/li&gt;
&lt;li&gt;Multiplicative Attention: $\mathbf{e}_{t,i} = \mathbf{s}_t^T \mathbf{W} \mathbf{h}_i$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;点积注意力的优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;计算速度更快，显存占用更小。&lt;/strong&gt; 点积注意力没有任何可学习的权重矩阵 $\mathbf{W}$，它仅仅是两个向量的内积。在 GPU 上，这种纯粹的向量点积运算被优化到了极致，没有任何额外的内存开销和参数更新负担。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;点积注意力的劣势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;强制要求维度严格一致，且表达能力较弱。&lt;/strong&gt; 要做点积，解码器状态 $\mathbf{s}_t$ 和编码器状态 $\mathbf{h}_i$ 的维度必须&lt;strong&gt;完全相同&lt;/strong&gt;。更致命的是，它假设这两个空间天然就是对齐的。而乘性注意力多了一个矩阵 $\mathbf{W}$，不仅允许两者的维度不同（$\mathbf{W}$ 可以做维度转换），还能通过学习 $\mathbf{W}$ 将它们投影到一个更好的共享特征空间中再进行比较。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="additive-vs-multiplicative"&gt;Additive vs. Multiplicative
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;Additive Attention: $\mathbf{e}_{t,i} = \mathbf{v}^T \tanh(\mathbf{W}_1 \mathbf{h}_i + \mathbf{W}_2 \mathbf{s}_t)$&lt;/li&gt;
&lt;li&gt;Multiplicative Attention: $\mathbf{e}_{t,i} = \mathbf{s}_t^T \mathbf{W} \mathbf{h}_i$&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;(注：Additive Attention 也就是大名鼎鼎的 Bahdanau Attention，它是 Attention 机制的开山鼻祖；而 Multiplicative 则是 Luong Attention 的核心。)&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;加性注意力的优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;在特征维度很大时，表现通常更好（模型容量大）。&lt;/strong&gt; 乘性注意力在维度很大时，点积的结果方差会变得极其巨大，容易把 Softmax 推向梯度消失的边缘（也就是后来 Transformer 引入缩放因子的原因）。而加性注意力通过 $\tanh$ 激活函数将内部数值稳稳地压制在 $[-1, 1]$ 之间，天然具有极好的数值稳定性，对超大维度的宽容度更高。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;加性注意力的劣势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;计算效率较低，难以发挥底层矩阵乘法的极致加速。&lt;/strong&gt; 乘性注意力可以极其优雅地打包成一个巨大的矩阵乘法（在 Transformer 里就是 $\mathbf{Q}\mathbf{K}^T$），这正是现代 GPU 最擅长的事情。而加性注意力不仅要做两次独立的线性变换，还要过一遍非线性激活函数 $\tanh$，最后再乘一个向量 $\mathbf{v}$。这种复杂的计算图打破了矩阵乘法的纯粹性，导致它在实际工程中的运行速度明显慢于乘性注意力。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="analyzing-nmt-systems"&gt;Analyzing NMT Systems
&lt;/h2&gt;&lt;p&gt;问题 (a) 是为什么在embedding层后加1D卷积后，再输入双向encoder效果会好一些？&lt;/p&gt;
&lt;p&gt;添加一维卷积层可以作为 n-gram 特征提取器，用于捕捉局部组合性。由于中文词语通常由多个词素组成（例如，“电”+“脑”=“电脑”），一维卷积神经网络的滑动窗口会在序列建模之前，将相邻字符/子词的嵌入向量显式地组合成更高层次的语义表示（一个词或短语）。这提供了一种层级结构，其中卷积神经网络处理局部词汇语义（充当软分词器），从而使双向编码器能够专注于学习全局的、长程的句法依存关系。&lt;/p&gt;
&lt;p&gt;问题 (b) 是分析四句中文为什么翻译错了，那么作为普通话母语者不难解答：&lt;/p&gt;
&lt;p&gt;i. (2 points) &lt;strong&gt;Source Sentence:&lt;/strong&gt; 贼人其后被警方拘捕及被判处盗窃罪名成立。
&lt;strong&gt;Reference Translation:&lt;/strong&gt; &lt;u&gt;&lt;em&gt;the culprits were&lt;/em&gt;&lt;/u&gt; &lt;em&gt;subsequently arrested and convicted.&lt;/em&gt;
&lt;strong&gt;NMT Translation:&lt;/strong&gt; &lt;u&gt;&lt;em&gt;the culprit was&lt;/em&gt;&lt;/u&gt; &lt;em&gt;subsequently arrested and sentenced to theft.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;ii. (2 points) &lt;strong&gt;Source Sentence:&lt;/strong&gt; 几乎已经没有地方容纳这些人, 资源已经用尽。
&lt;strong&gt;Reference Translation:&lt;/strong&gt; &lt;em&gt;there is almost no space to accommodate these people, and resources have run out.&lt;/em&gt;
&lt;strong&gt;NMT Translation:&lt;/strong&gt; &lt;em&gt;the resources have been exhausted and&lt;/em&gt; &lt;u&gt;&lt;em&gt;resources have been exhausted&lt;/em&gt;&lt;/u&gt;.&lt;/p&gt;
&lt;p&gt;iii. (2 points) &lt;strong&gt;Source Sentence:&lt;/strong&gt; 当局已经宣布今天是国殇日。
&lt;strong&gt;Reference Translation:&lt;/strong&gt; &lt;em&gt;authorities have announced&lt;/em&gt; &lt;u&gt;&lt;em&gt;a national mourning today.&lt;/em&gt;&lt;/u&gt; &lt;strong&gt;NMT Translation:&lt;/strong&gt; the administration has announced today&amp;rsquo;s day.
&lt;strong&gt;NMT Translation:&lt;/strong&gt; &lt;em&gt;the administration has announced&lt;/em&gt; &lt;u&gt;&lt;em&gt;today&amp;rsquo;s day.&lt;/em&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;iv. (2 points) &lt;strong&gt;Source Sentence&lt;/strong&gt;: 俗语有云:“唔做唔错”。
&lt;strong&gt;Reference Translation:&lt;/strong&gt; &lt;u&gt;&lt;em&gt;“ act not, err not ”&lt;/em&gt;&lt;/u&gt;, &lt;em&gt;so a saying goes.&lt;/em&gt;
&lt;strong&gt;NMT Translation:&lt;/strong&gt; &lt;em&gt;as the saying goes,&lt;/em&gt; &lt;u&gt;&lt;em&gt;“ it&amp;rsquo;s not wrong. ”&lt;/em&gt;&lt;/u&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(i) 是单/复数的问题，缺少上下文以及整体理解，难以判断“贼人”是复数还是单数。&lt;/li&gt;
&lt;li&gt;(ii) “资源已经用尽”被重复翻译了两遍，简单来说是注意力先偏移到了后半句，然后NMT不知道前半句没有翻译，加上前面错译出的&amp;quot;&amp;hellip;and&amp;quot;，导致重复翻译后半句。&lt;/li&gt;
&lt;li&gt;(iii) &lt;code&gt;src.vocab&lt;/code&gt;没有记录“国殇”，所以NMT越过了这个词。&lt;/li&gt;
&lt;li&gt;(iv) 本质是句俗语，或者说是粤语，而多数模型都是基于普通话训练的。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="bleu"&gt;BLEU
&lt;/h3&gt;&lt;p&gt;BLEU score is the most commonly used automatic evaluation metric for NMT systems.
It is usually calculated across the entire test set, but here we will consider BLEU defined for a single
example. Suppose we have a source sentence s, a set of k reference translations $\mathbf{r}_1,\dots,\mathbf{r}_k$, and a
candidate translation c. To compute the BLEU score of c, we first compute the modified n-gram
precision pn of c, for each of n = 1,2,3,4, where n is the n in n-gram:&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;BLEU 分数是 NMT (神经机器翻译) 系统中最常用的自动评估指标。它通常在整个测试集上计算，但在这里我们将考虑为单个示例定义的 BLEU。假设我们有一个源句子 $\mathbf{s}$，一组 $k$ 个参考翻译 $\mathbf{r}_1,\dots,\mathbf{r}_k$，以及一个候选翻译 $\mathbf{c}$。为了计算 $\mathbf{c}$ 的 BLEU 分数，我们首先计算 $\mathbf{c}$ 的&lt;em&gt;修正 n-gram 精确度 (modified n-gram precision)&lt;/em&gt; $p_n$，其中 $n = 1, 2, 3, 4$，$n$ 是 n-gram 中的 $n$：&lt;/p&gt;

 &lt;/blockquote&gt;
$$
p_n = \frac{\sum_{\text{ngram} \in \mathbf{c}} \min \left( \max_{i=1,\dots,k} \text{Count}_{\mathbf{r}_i}(\text{ngram}), \text{Count}_{\mathbf{c}}(\text{ngram}) \right)}{\sum_{\text{ngram} \in \mathbf{c}} \text{Count}_{\mathbf{c}}(\text{ngram})}
$$&lt;p&gt;Here, for each of the n-grams that appear in the candidate translation c, we count the maxi
mum number of times it appears in any one reference translation, capped by the number of times
it appears in c (this is the numerator). We divide this by the number of n-grams in c (denominator).&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;这里，对于出现在候选翻译 $\mathbf{c}$ 中的每一个 $n$-gram，我们计算它在任何一个参考翻译中出现的最大次数，上限为它在 $\mathbf{c}$ 中出现的次数（这是分子）。我们将其除以 $\mathbf{c}$ 中 $n$-gram 的数量（分母）。&lt;/p&gt;
&lt;p&gt;$p_n$ 公式的分母部分比较清晰，分子部分我们继续拆解：&lt;/p&gt;
&lt;p&gt;$\text{Count}_{\mathbf{c}}(\text{ngram})$ : 该词组在模型输出中出现几次。&lt;/p&gt;
&lt;p&gt;$\max_{i=1,\dots,k} \text{Count}_{\mathbf{r}_i}(\text{ngram})$ : 该词组在&lt;strong&gt;所有参考答案&lt;/strong&gt;中出现次数最多的那一次。比如三个参考答案里，&lt;code&gt;the&lt;/code&gt; 分别出现了 1、2、1 次，那么这个值就是 2。&lt;/p&gt;
&lt;p&gt;$\min(\dots)$ : 这是**截断（Clipping）**机制。它规定：即便你在输出里写了 10 个 &lt;code&gt;the&lt;/code&gt;，如果参考答案里最多只出现了 2 个，那我也只算你命中了 2 个。&lt;/p&gt;
&lt;p&gt;综上，公式可以被翻译成：
&lt;/p&gt;
$$
&gt; p_n = \frac{\text{被认可的 n-gram 匹配总数}}{\text{候选翻译中总共生成的 n-gram 数量}}
&gt; $$
 &lt;/blockquote&gt;
&lt;p&gt;Next, we compute the brevity penalty BP. Let $len(\mathbf{c})$ be the length of c and let $len(\mathbf{r})$ be the
length of the reference translation that is closest to $len(\mathbf{c})$ (in the case of two equally-close reference
translation lengths, choose $len(\mathbf{r})$ as the shorter one).&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;接下来，我们计算&lt;em&gt;长度惩罚 (brevity penalty)&lt;/em&gt; $BP$。令 $len(\mathbf{c})$ 为 $\mathbf{c}$ 的长度，令 $len(\mathbf{r})$ 为最接近 $len(\mathbf{c})$ 的参考翻译的长度（在有两个同样接近的参考翻译长度的情况下，选择较短的那个作为 $len(\mathbf{r})$）。&lt;/p&gt;

 &lt;/blockquote&gt;
$$
BP = \begin{cases} 1 &amp; \text{if } len(\mathbf{c}) \geq len(\mathbf{r}) \\ \exp\left(1 - \frac{len(\mathbf{r})}{len(\mathbf{c})}\right) &amp; \text{otherwise} \end{cases}
$$
 &lt;blockquote&gt;
 &lt;p&gt;那么引入 $BP$ 有什么用？首先 $len(\mathbf{c}) \geq len(\mathbf{r})$ 时 $BP=1$ ，这是在NMT输出较长时，$BP$ 不需要惩罚它，而会在 $p_n$ 的分母体现（分母变大，概率降低）。&lt;/p&gt;
&lt;p&gt;$len(\mathbf{c}) &lt; len(\mathbf{r})$ 时引入指数惩罚，如果NMT只翻译最有把握的一个词（比如输出一个单词 &lt;code&gt;apple&lt;/code&gt;），$p_n$ 可能是 100%，但这没有意义。这个指数函数 $\exp(1 - r/c)$ 在 $c$ 越小时，值会迅速接近 0，从而给短句一个沉重的打击。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;Lastly, the BLEU score for candidate c with respect to $\mathbf{r}_1,\dots,\mathbf{r}_k$ is:&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;最后，候选 $\mathbf{c}$ 相对于 $\mathbf{r}_1,\dots,\mathbf{r}_k$ 的 BLEU 分数为：&lt;/p&gt;

 &lt;/blockquote&gt;
$$
BLEU = BP \times \exp \left( \sum_{n=1}^4 \lambda_n \log p_n \right)
$$
 &lt;blockquote&gt;
 &lt;p&gt;本质上等同于：
&lt;/p&gt;
$$
&gt; BLEU = BP \times (p_1^{\lambda_1} \cdot p_2^{\lambda_2} \cdot p_3^{\lambda_3} \cdot p_4^{\lambda_4})
&gt; $$
 &lt;/blockquote&gt;
&lt;p&gt;where $\lambda_1, \lambda_2, \lambda_3, \lambda_4$ are weights that sum to 1. The log here is natural log.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;其中 $\lambda_1, \lambda_2, \lambda_3, \lambda_4$ 是总和为 1 的权重。此处的 $\log$ 是自然对数。&lt;/p&gt;
&lt;p&gt;几何平均的一个特性是：&lt;strong&gt;如果其中任何一项 $p_n$ 为 0，最终结果就会是 0&lt;/strong&gt;。所以模型的词汇和语序的正确性都会被计算。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;问题 (c) 结合实例运算：&lt;/p&gt;
&lt;p&gt;i. Source Sentence &lt;strong&gt;s&lt;/strong&gt;: 需要有充足和可预测的资源。
Reference Translation $r_1$ : &lt;em&gt;resources have to be sufficient and they have to be predictable&lt;/em&gt;
Reference Translation $r_2$ : &lt;em&gt;adequate and predictable resources are required&lt;/em&gt;
NMT Translation $c_1$ : there is a need for adequate and predictable resources
NMT Translation $c_2$ : resources be sufficient and predictable to
Please compute the BLEU scores for and $c_1$ $c_2$. Let $\lambda_i = 0.5$ for $i \in \{1, 2\}$ and $\lambda_i = 0$ for $i \in \{3, 4\}$ (&lt;strong&gt;this means we ignore 3-grams and 4-grams&lt;/strong&gt;, i.e., don&amp;rsquo;t compute $p_3$ or $p_4$).
When computing BLEU scores, show your work (i.e., show your computed values for $p_1$, $p_2$, $len(c)$, $len(r)$ and $BP$). Note that the BLEU scores can be expressed between 0 and 1 or between 0 and 100. The code is using the 0 to 100 scale while in this question we are using the &lt;strong&gt;0 to 1&lt;/strong&gt; scale. Please round your responses to 3 decimal places.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;先计算 $c_1$ : $len(c_1)=9$ 更接近于 $len(r_1)=11$ , $BP=exp(1-\frac{11}{9})$&lt;/p&gt;
&lt;p&gt;$p_1$ 匹配的Unigrams 为 {adequate, and, predictable, resources}，共 4 个。 $p_1=4/9$&lt;/p&gt;
&lt;p&gt;$p_2$ 匹配的Bigrams 为 {adequate and, and predictable, predictable resources}，共 3 个。 $p_2=3/8$&lt;/p&gt;
&lt;p&gt;$BLEU_{c1} = BP \times \sqrt{p_1 \times p_2}$&lt;/p&gt;
&lt;p&gt;$c_2$ 同理。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;ii. Our hard drive was corrupted and we lost Reference Translation $r_1$. Please recom
pute BLEU scores for $c_1$ and $c_2$, this time with respect to $r_2$ only. Which of the two NMT
translations now receives the higher BLEU score? Do you agree that it is the better translation?&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;计算方式不变，但是在去掉了 $r_1$ 后， ${BLEU}_{c_1}$ 不变， ${BLEU}_{c_2}$ 大幅缩小（由于 $p_1$ 和 $p_2$ 下降）&lt;/p&gt;
&lt;p&gt;这说明了 &lt;strong&gt;$c_1$ 的鲁棒性更强&lt;/strong&gt;，它使用了更通用的词汇（如 &lt;code&gt;adequate&lt;/code&gt;），即使在参考答案有限的情况下，依然能保持较合理的得分，这更符合人类对“好翻译”的评价标准。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;iv. List two advantages and two disadvantages of BLEU, compared to human evaluation,
as an evaluation metric for Machine Translation.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;优点不列了，缺点：BLEU 仅进行&lt;strong&gt;字面上的 N-gram 匹配&lt;/strong&gt;，缺乏语义理解。由于 BLEU 主要关注局部词汇的重合度，它往往无法识别严重的语法错误或逻辑扭曲。一个逻辑完全相反、但在词汇上高度重合的句子可能获得极高的 BLEU 分，却无法被人类理解，所以它无法准确衡量语言质量。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;问题 (d) 是Beam Search相关的，关于训练次数与其“假设”质量的问题，比如i. 要求进行三个对比：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// iteration 200
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;hypothesis&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁it&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁is&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁not&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁that&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁the&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁united&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁nations&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁of&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁the&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁united&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁nations&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁of&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁the&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁united&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁nations&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;score&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;-31.211565017700195&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// iteration 3000
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;hypothesis&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁i&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁would&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁also&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁like&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁to&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁clarify&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁the&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁number&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁of&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁cases&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁in&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁the&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁conference&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;score&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;-15.013087272644043&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// iteration 17200 (last)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;hypothesis&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁i&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁have&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁also&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁clarified&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁a&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁number&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁of&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁matters&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁raised&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁by&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁the&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;▁conference&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;score&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;-7.69414758682251&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>计算机网络</title><link>https://ottercoconut.github.io/p/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/</link><pubDate>Fri, 20 Feb 2026 14:10:19 +0800</pubDate><guid>https://ottercoconut.github.io/p/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/</guid><description>&lt;p&gt;&lt;a class="link" href="https://space.bilibili.com/360996402/lists/533771?type=season" target="_blank" rel="noopener"
 &gt;湖科大教书匠 深入浅出计算机网络&lt;/a&gt;&lt;/p&gt;
&lt;h1 id="计算机网络"&gt;计算机网络
&lt;/h1&gt;&lt;h2 id="11-计算机网络在信息时代的作用"&gt;1.1 计算机网络在信息时代的作用
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;计算机网络已由一种&lt;strong&gt;通信基础设施&lt;/strong&gt;发展成为一种重要的&lt;strong&gt;信息服务基础设施&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;计算机网络已经像水、电、煤气这些基础设施一样，成为我们&lt;strong&gt;生活中不可或缺的&lt;/strong&gt;一部分。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="12-因特网概述"&gt;1.2 因特网概述
&lt;/h2&gt;&lt;h4 id="网络互连网互联网和因特网"&gt;网络、互连网（互联网）和因特网
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;网络（Network）由若干**结点（Node）&lt;strong&gt;和连接这些结点的&lt;/strong&gt;链路（Link）**组成。&lt;/li&gt;
&lt;li&gt;多个网络还可以通过路由器互连起来，这样就构成了一个覆盖范围更大的网络，即互联网（或互连网）。因此，互联网是“&lt;strong&gt;网络的网络&lt;/strong&gt;（Network of Networks）”。&lt;/li&gt;
&lt;li&gt;因特网（Internet）是世界上最大的互连网络（用户数以亿计，互连的网络数以百万计）。&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;internet（互联网或互连网）是一个通用名词，它泛指由多个计算机网络互连而成的网络。在这些网络之间的通信协议可以是任意的。&lt;/p&gt;
&lt;p&gt;Internet（因特网）则是一个专用名词，它指当前全球最大的、开放的、由众多网络相互连接而成的特定计算机网络，它采用&lt;strong&gt;TCP/IP协议簇&lt;/strong&gt;作为通信的规则，其前身是美国的ARPANET。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h4 id="因特网发展的三个阶段"&gt;因特网发展的三个阶段
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;从单个网络ARPANET向互联网发展
&lt;ul&gt;
&lt;li&gt;1969年，第一个分组交换网&lt;strong&gt;ARPANET&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;70年代中期，研究多种网络之间的互连；&lt;/li&gt;
&lt;li&gt;1983年，&lt;strong&gt;TCP/IP协议&lt;/strong&gt;成为ARPANET的标准协议（因特网诞生时间）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;逐步建成三级结构的因特网
&lt;ul&gt;
&lt;li&gt;1985年，NSF围绕六个大型计算机中心建设&lt;strong&gt;NSFNET&lt;/strong&gt;（主干网、地区网和校园网）；&lt;/li&gt;
&lt;li&gt;1990年，ARPANET任务完成，正式关闭；&lt;/li&gt;
&lt;li&gt;1991年，美国政府将因特网主干网交给私人公司经营，并开始对接入因特网的单位收费；&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;逐步形成了多层次ISP结构的因特网
&lt;ul&gt;
&lt;li&gt;1993年，NSFNET逐渐被若干个商用因特网主干网替代；政府机构不再负责因特网运营，让各种&lt;strong&gt;因特网服务提供者ISP&lt;/strong&gt;来运营。&lt;/li&gt;
&lt;li&gt;1994年，&lt;strong&gt;万维网WWW技术&lt;/strong&gt;促使因特网迅猛发展；&lt;/li&gt;
&lt;li&gt;1995年，NSFNET停止运作，因特网彻底商业化。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="因特网的组成"&gt;因特网的组成
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;边缘部分
&lt;ul&gt;
&lt;li&gt;由所有连接在因特网上的&lt;strong&gt;主机&lt;/strong&gt;组成。这部分是用户直接使用的，用来进行通信（传送数据、音频或视频）和&lt;strong&gt;资源共享&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;核心部分
&lt;ul&gt;
&lt;li&gt;核心部分 由大量&lt;strong&gt;网络&lt;/strong&gt;和连接这些网络的路由器组成。这部分是为边缘部分提供服务的（提供连通性和交换）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="13-三种交换方式"&gt;1.3 三种交换方式
&lt;/h2&gt;&lt;h4 id="电路交换"&gt;电路交换
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;电话交换机接通电话线的方式称为电路交换；&lt;/li&gt;
&lt;li&gt;从通信资源的分配角度来看，交换（Switching）就是按照某种方式动态地分配传输线路的资源；&lt;/li&gt;
&lt;li&gt;电路交换的三个步骤：
&lt;ol&gt;
&lt;li&gt;建立连接（分配通信资源）&lt;/li&gt;
&lt;li&gt;通话（一直占用通信资源）&lt;/li&gt;
&lt;li&gt;释放连接（归还通信资源）&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;当使用电路交换来传送计算机数据时，其线路的&lt;strong&gt;传输效率往往很低&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="分组交换"&gt;分组交换
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;通常我们把表示消息的整块数据称为一个&lt;strong&gt;报文&lt;/strong&gt;，在发送报文之前，先把较长的报文划分成为一个个更小的等长数据段。在每一个数据段前面，加上一些由必要的控制信息组成的&lt;strong&gt;首部&lt;/strong&gt;后，就构成了一个分组，也可简称为“包”，相应地，首部也可叫作“包头”。&lt;/li&gt;
&lt;li&gt;分组交换机收到一个分组后，先将分组&lt;strong&gt;暂时存储下来&lt;/strong&gt;，再检查其首部，按照首部中的目的地址进行查表转发，找到合适的转发接口，通过该接口&lt;strong&gt;将分组转发给下一个分组交换机&lt;/strong&gt;。各分组经过途中各分组交换机的存储转发，最终达到目标主机。&lt;/li&gt;
&lt;li&gt;目标主机收到这些分组后，去掉它们的首部，将各数据段组合还原出原始报文。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="电路交换报文交换分组交换的对比"&gt;电路交换、报文交换、分组交换的对比
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-01-04-151109.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;电路交换&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;优点&lt;/th&gt;
					&lt;th&gt;缺点&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;通信时延小&lt;/td&gt;
					&lt;td&gt;建立连接时间长&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;有序传输&lt;/td&gt;
					&lt;td&gt;线路独占，使用效率低&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;没有冲突&lt;/td&gt;
					&lt;td&gt;灵活性差&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;适用范围广&lt;/td&gt;
					&lt;td&gt;难以规范化&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;实时性强&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;控制简单&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;报文交换&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;优点&lt;/th&gt;
					&lt;th&gt;缺点&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;无需建立连接&lt;/td&gt;
					&lt;td&gt;引起了转发时延&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;动态分配线路&lt;/td&gt;
					&lt;td&gt;需要较大存储缓存空间&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;提高线路可靠性&lt;/td&gt;
					&lt;td&gt;需要传输额外的信息量&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;提高线路利用率&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;提供多目标服务&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;分组交换&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;优点&lt;/th&gt;
					&lt;th&gt;缺点&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;无需建立连接&lt;/td&gt;
					&lt;td&gt;引起了转发时延&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;线路利用率高&lt;/td&gt;
					&lt;td&gt;需要传输额外的信息量&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;简化了存储管理&lt;/td&gt;
					&lt;td&gt;对于数据报服务，存在失序、丢失或重复分组的问题；对于虚电路服务，存在呼叫建立、数据传输和虚电路释放三个过程&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;加速传输&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;减少出错概率和重发数据量&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="14-计算机网络的定义和分类"&gt;1.4 计算机网络的定义和分类
&lt;/h2&gt;&lt;h4 id="计算机网络的定义"&gt;计算机网络的定义
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;计算机网络的精确定义并未统一&lt;/li&gt;
&lt;li&gt;计算机网络的最简单的定义是：一些&lt;strong&gt;互相连接的&lt;/strong&gt;、&lt;strong&gt;自治的&lt;/strong&gt;计算机的集合。
&lt;ul&gt;
&lt;li&gt;互连 是指计算机之间可以通过有线或无线的方式进行数据通信；&lt;/li&gt;
&lt;li&gt;自治 是指独立的计算机，它有自己的硬件和软件，可以单独运行使用；&lt;/li&gt;
&lt;li&gt;集合 是指至少需要两台计算机；&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;计算机网络的较好的定义是：计算机网络主要是由一些通用的、可编程的硬件&lt;strong&gt;互连&lt;/strong&gt;而成的，而这些硬件并非专门用来实现某一特定目的（例如，传送数据或视频信号）。这些可编程的硬件能够用来&lt;strong&gt;传送多种不同类型的数据&lt;/strong&gt;，并能&lt;strong&gt;支持广泛的和日益增长的应用&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="计算机网络的分类"&gt;计算机网络的分类
&lt;/h4&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;分类方式&lt;/th&gt;
					&lt;th&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;按交换技术分类&lt;/td&gt;
					&lt;td&gt;电路交换网络、报文交换网络、分组交换网络&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;按使用者分类&lt;/td&gt;
					&lt;td&gt;公用网、专用网&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;按传输介质分类&lt;/td&gt;
					&lt;td&gt;有线网络、无线网络&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;按覆盖范围分类&lt;/td&gt;
					&lt;td&gt;广域网WAN、城域网MAN、局域网LAN、个域网PAN&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;按覆盖范围分类&lt;/td&gt;
					&lt;td&gt;总线型网络、星型网络、环型网络、网状型网络&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="15-计算机网络的性能指标"&gt;1.5 计算机网络的性能指标
&lt;/h2&gt;&lt;h4 id="速率"&gt;速率
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;计算机中&lt;strong&gt;数据量的单位&lt;/strong&gt;，也是信息论中信息量的单位。一个比特就是二进制数字中的一个1或0。&lt;/li&gt;
&lt;li&gt;常用数据量单位：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$8 bit = 1 Byte$&lt;/p&gt;
&lt;p&gt;$KB = 2^{10} B$&lt;/p&gt;
&lt;p&gt;$MB = K·KB = 2^{10}·2^{10} B = 2^{20} B$&lt;/p&gt;
&lt;p&gt;$GB = K·MB = 2^{10}·2^{20} B = 2^{30} B$&lt;/p&gt;
&lt;p&gt;$TB = K·GB = 2^{10}·2^{30} B = 2^{40} B$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;连接在计算机网络上的主机在数字信道上传送比特的速率，也称为&lt;strong&gt;比特率或数据率&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;常用数据率单位：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;bit/s (b/s, bps)&lt;/p&gt;
&lt;p&gt;$k b/s = 10^3 b/s$ (bps)&lt;/p&gt;
&lt;p&gt;$M b/s = k \cdot k b/s = 10^3 \cdot 10^3 b/s = 10^6 b/s$ (bps)&lt;/p&gt;
&lt;p&gt;$G b/s = k \cdot M b/s = 10^3 \cdot 10^6 b/s = 10^9 b/s$ (bps)&lt;/p&gt;
&lt;p&gt;$T b/s = k \cdot G b/s = 10^3 \cdot 10^9 b/s = 10^{12} b/s$ (bps)&lt;/p&gt;
&lt;h4 id="带宽"&gt;带宽
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;用来表示网络的&lt;strong&gt;通信线路&lt;/strong&gt;所能传送数据的能力，因此网络带宽表示在单位时间内从网络中的某一点到另一点所能通过的“&lt;strong&gt;最高数据率&lt;/strong&gt;”；&lt;/li&gt;
&lt;li&gt;单位：b/s（kb/s, Mb/s, Gb/s, Tb/s）和速率相同&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="吞吐量"&gt;吞吐量
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;吞吐量表示在单位时间内通过某个网络（或信道、接口）的&lt;strong&gt;数据量&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;吞吐量被经常用于对现实世界中的网络的一种测量，以便知道实际上到底有多少数据量能够通过网络。&lt;/li&gt;
&lt;li&gt;吞吐量&lt;strong&gt;受网络的带宽或额定速率的限制&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="时延"&gt;时延
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-01-04-172857.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="时延带宽积"&gt;时延带宽积
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;$时延带宽积 = 传播时延 \times 带宽 $&lt;/li&gt;
&lt;li&gt;若发送端连续发送数据，则在所发送的第一个比特即将到达终点时，发送端就已经发送了时延带宽积$B \cdot W$个比特；&lt;/li&gt;
&lt;li&gt;链路的时延带宽积又称为&lt;strong&gt;以比特为单位的链路长度&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="往返时间"&gt;往返时间
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;在许多情况下，因特网上的信息不仅仅单方向传输，而是双向交互；&lt;/li&gt;
&lt;li&gt;我们有时很需要知道双向交互一次所需的时间；因此，往返时间&lt;strong&gt;RTT&lt;/strong&gt;(Round-Trip Time)也是一个重要的性能指标。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="利用率"&gt;利用率
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;信道利用率：用来表示某信道有百分之几的时间是被利用的（有数据通过）。&lt;/li&gt;
&lt;li&gt;网络利用率：全网络的信道利用率的加权平均。&lt;/li&gt;
&lt;li&gt;根据排队论，当某信道的利用率增大时，该信道引起的时延也会迅速增加； 因此，&lt;strong&gt;信道利用率并非越高越好&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;如果令$D_0$表示网络空闲时的时延，$D$表示网络当前的时延，那么在适当的假定条件下，可以用下面的简单公式来表示$D$、$D_0$和利用率$U$之间的关系： $D = \frac{D_0}{1 - U}$
&lt;ul&gt;
&lt;li&gt;当网络的利用率达到50%时，时延就要加倍；&lt;/li&gt;
&lt;li&gt;当网络的利用率超过50%时，时延急剧增大；&lt;/li&gt;
&lt;li&gt;当网络的利用率接近100%时，时延就趋于无穷大。&lt;/li&gt;
&lt;li&gt;因此，一些拥有较大主干网的ISP通常会控制它的信道利用率不超过50%。如果超过了，就要准备扩容，增大线路的带宽。&lt;/li&gt;
&lt;li&gt;也不能使信道利用率太低，这会使宝贵的通信资源输白白浪费。应该使用一些机制，可以根据情况动态调整输入到网络中的通信量，使网络利用率保持在一个合理的范围内。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="丢包率"&gt;丢包率
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;丢包率即分组丢失率，是指在一定的时间范围内，传输过程中丢失的分组数量与总分组数量的&lt;strong&gt;比率&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;丢包率具体可分为接口丢包率、结点丢包率、链路丢包率、路径丢包率、网络丢包率等。&lt;/li&gt;
&lt;li&gt;丢包率是网络运维人员非常关心的一个网络性能指标，但对于普通用户来说往往并不关心这个指标，因为他们通常意识不到网络丢包。&lt;/li&gt;
&lt;li&gt;分组丢失主要有两种情况：
&lt;ul&gt;
&lt;li&gt;分组在传输过程中出现&lt;strong&gt;误码&lt;/strong&gt;，被结点丢弃；&lt;/li&gt;
&lt;li&gt;分组到达一台队列已满的分组交换机时被丢弃；在通信量较大时就可能造成&lt;strong&gt;网络拥塞&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;因此，丢包率反映了网络的拥塞情况：
&lt;ul&gt;
&lt;li&gt;无拥塞时路径丢包率为0&lt;/li&gt;
&lt;li&gt;轻度拥塞时路径丢包率为1%~4%&lt;/li&gt;
&lt;li&gt;严重拥塞时路径丢包率为5%~15%&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="16-计算机网络体系结构"&gt;1.6 计算机网络体系结构
&lt;/h2&gt;&lt;h4 id="常见的计算机网络体系结构"&gt;常见的计算机网络体系结构
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;原理参考模型，从下到上以此为：&lt;strong&gt;物理层、数据链路层、网络层、运输层、应用层&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-01-04-181131.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="分层的必要性"&gt;分层的必要性
&lt;/h4&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;/th&gt;
					&lt;th&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;应用层&lt;/td&gt;
					&lt;td&gt;解决通过应用进程的交互来实现特定网络应用的问题&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;运输层&lt;/td&gt;
					&lt;td&gt;解决进程之间基于网络的通信问题&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;网络层&lt;/td&gt;
					&lt;td&gt;解决数据包在多个网络之间传输和路由的问题&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;数据链路层&lt;/td&gt;
					&lt;td&gt;解决数据包在一个网络或一段链路上传输的问题&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;物理层&lt;/td&gt;
					&lt;td&gt;解决使用何种信号来表示比特0和1的问题&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id="分层思想举例"&gt;分层思想举例
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-01-04-233936.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="专用术语"&gt;专用术语
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;实体&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;实体是指任何可发送或接收信息的&lt;strong&gt;硬件或软件进程&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;对等实体是指通信双方&lt;strong&gt;相同层次中的实体&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;协议&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;协议是控制两个对等实体在“&lt;strong&gt;水平方向&lt;/strong&gt;”进行“&lt;strong&gt;逻辑通信&lt;/strong&gt;”的&lt;strong&gt;规则&lt;/strong&gt;的集合。&lt;/li&gt;
&lt;li&gt;协议的三要素：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;语法&lt;/strong&gt; 定义所交换信息的&lt;strong&gt;格式&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;语义&lt;/strong&gt; 定义通信双方所要完成的&lt;strong&gt;操作&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;同步&lt;/strong&gt; 定义通信双方的&lt;strong&gt;时序关系&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;服务&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;在协议的控制下，&lt;strong&gt;两个对等实体在水平方向的逻辑通信使得本层能够向上一层提供服务&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;要实现本层协议，还需要使用下面一层所提供的服务。&lt;/li&gt;
&lt;li&gt;协议是“&lt;strong&gt;水平&lt;/strong&gt;”的，而服务是“&lt;strong&gt;垂直&lt;/strong&gt;”的。&lt;/li&gt;
&lt;li&gt;实体看得见下层提供的服务，但并不知道实现该服务的具体协议。下层的协议对上层的实体是“&lt;strong&gt;透明&lt;/strong&gt;”的。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;在同一系统中&lt;strong&gt;相邻两层的实体交换信息的逻辑接口&lt;/strong&gt;称为&lt;strong&gt;服务访问点SAP&lt;/strong&gt;，它被用于区分不同的服务类型。&lt;/li&gt;
&lt;li&gt;帧的“类型”字段、IP数据报的“协议”字段，TCP报文段或UDP用户数据报的“端口号”字段都是SAP。&lt;/li&gt;
&lt;li&gt;上层要使用下层所提供的服务，必须通过与下层&lt;strong&gt;交换一些命令&lt;/strong&gt;，这些命令称为&lt;strong&gt;服务原语&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;对等层次之间传送的数据包称为该层的&lt;strong&gt;协议数据单元&lt;/strong&gt;（Protocol Data Unit，PDU）。&lt;/li&gt;
&lt;li&gt;同一系统内层与层之间交换的数据包称为&lt;strong&gt;服务数据单元&lt;/strong&gt;（Service Data Unit，SDU）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="21-物理层概述"&gt;2.1 物理层概述
&lt;/h2&gt;&lt;h4 id="物理层要实现的功能"&gt;物理层要实现的功能
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;数据链路层“&lt;strong&gt;看不见&lt;/strong&gt;”（也无需看见）物理层究竟使用的是什么方法来传输比特流。数据链路层**只管“享受”**物理层提供的比特流传输服务即可。&lt;/li&gt;
&lt;li&gt;物理层之间“&lt;strong&gt;透明&lt;/strong&gt;”传输比特流。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="物理层接口特性"&gt;物理层接口特性
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;机械特性&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;形状和尺寸&lt;/li&gt;
&lt;li&gt;引脚数目和排列&lt;/li&gt;
&lt;li&gt;固定和锁定装置&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;电气特性&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;信号电压的范围&lt;/li&gt;
&lt;li&gt;阻抗匹配的情况&lt;/li&gt;
&lt;li&gt;传输速率&lt;/li&gt;
&lt;li&gt;距离限制&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;功能特性&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;规定接口电缆的各条信号线的作用&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;过程特性&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;规定在信号线上传输比特流的一组操作过程，包括各信号间的时序关系&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="22-传输媒体"&gt;2.2 传输媒体
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;传输媒体&lt;/strong&gt;是计算机网络设备之间的物理通路，也称为传输介质或传输媒介。&lt;/li&gt;
&lt;li&gt;传输媒体并&lt;strong&gt;不包含在计算机网络体系结构中&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;导向型传输媒体&lt;/strong&gt;（固体媒体）
&lt;ul&gt;
&lt;li&gt;同轴电缆&lt;/li&gt;
&lt;li&gt;双绞线&lt;/li&gt;
&lt;li&gt;光纤&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;非导向型传输媒体&lt;/strong&gt;（自由空间）
&lt;ul&gt;
&lt;li&gt;无线电波&lt;/li&gt;
&lt;li&gt;微波&lt;/li&gt;
&lt;li&gt;红外线&lt;/li&gt;
&lt;li&gt;大气激光&lt;/li&gt;
&lt;li&gt;可见光&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="23-传输方式"&gt;2.3 传输方式
&lt;/h2&gt;&lt;h4 id="串行运输和并行运输"&gt;串行运输和并行运输
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-01-05-171623.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="同步传输和异步传输"&gt;同步传输和异步传输
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-01-05-171637.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-01-05-171654.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="单向通信双向交替通信和双向同时通信"&gt;单向通信、双向交替通信和双向同时通信
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-01-05-171705.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2 id="24-编码与调制"&gt;2.4 编码与调制
&lt;/h2&gt;&lt;h4 id="基本概念"&gt;基本概念
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;基带调制（编码）&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;以太网采用的曼彻斯特编码、4B/5B、8B/10B&lt;/li&gt;
&lt;li&gt;数字基带信号 -&amp;gt; 数字信道&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;带通调制&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Wi-Fi采用的CCK/DSSS/OFDM调制&lt;/li&gt;
&lt;li&gt;数字基带信号 -&amp;gt; 模拟信道&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;码元&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;在使用时间域的波形表示信号时，代表不同离散数值的&lt;strong&gt;基本波形&lt;/strong&gt;称为码元。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="常用编码方式"&gt;常用编码方式
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;双极性不归零编码&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;编码效率高，但存在同步问题&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;双极性归零编码&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;自同步，但编码效率低&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;曼彻斯特编码&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;自同步，10Mb/s传统以太网&lt;/li&gt;
&lt;li&gt;码元中间时刻的电平跳变既表示时钟信号，也表示数据。正跳变表示1还是0，负跳变表示0还是1，可以自行定义。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;差分曼彻斯特编码&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;码元中间时刻的电平跳变仅表示时钟信号，而不表示数据。 数据的表示在于每一个码元开始处是否有电平跳变：无跳变表示1，有跳变表示0。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;差分曼彻斯特编码对比曼彻斯特编码&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在传输大量连续1或连续0的情况下，差分曼彻斯特编码信号比曼彻斯特编码信号的变化少。&lt;/li&gt;
&lt;li&gt;在噪声干扰环境下，检测有无跳变比检测跳变方向更不容易出错，因此差分曼彻斯特编码信号比曼彻斯特编码信号更易于检测。&lt;/li&gt;
&lt;li&gt;在传输介质接线错误导致高低电平翻转的情况下，差分曼彻斯特编码仍然有效。&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-01-05-175121.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="带通调制方法和混合调制方法"&gt;带通调制方法和混合调制方法
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-01-05-180704.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2 id="25-信道的极限容量"&gt;2.5 信道的极限容量
&lt;/h2&gt;&lt;h4 id="造成信号失真的主要因素"&gt;造成信号失真的主要因素
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;传输速率越高，信号经过传输后的失真就越严重。&lt;/p&gt;
&lt;p&gt;传输距离越远，信号经过传输后的失真就越严重。&lt;/p&gt;
&lt;p&gt;噪声干扰越大，信号经过传输后的失真就越严重。&lt;/p&gt;
&lt;p&gt;传输媒体质量越差，信号经过传输后的失真就越严重。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;信道上传输的&lt;strong&gt;数字信号&lt;/strong&gt;，可以看做是&lt;strong&gt;多个频率的模拟信号进行多次叠加后形成的方波&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果数字信号中的高频分量在传输时受到衰减甚至不能通过信道，则接收端接收到的波形前沿和后沿就变得不那么陡峭，每一个码元所占的时间界限也不再明确。这样，在接收端接收到的信号波形就失去了码元之间的清晰界限，这种现象称为&lt;strong&gt;码间串扰&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果&lt;strong&gt;信道的频带越宽&lt;/strong&gt;，则能够&lt;strong&gt;通过的信号的高频分量就越多&lt;/strong&gt;，那么&lt;strong&gt;码元的传输速率就可以更高&lt;/strong&gt;，而&lt;strong&gt;不会导致码间串扰&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;然而，&lt;strong&gt;信道的频率带宽是有上限的&lt;/strong&gt;，不可能无限大。因此，&lt;strong&gt;码元的传输速率也有上限&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="奈氏准则"&gt;奈氏准则
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;理想&lt;/strong&gt;低通信道的&lt;strong&gt;最高码元传输速率&lt;/strong&gt; = $2W Baud=2W(码元/秒)=2Wlog_2X(比特/秒)$&lt;/p&gt;
&lt;p&gt;W：信道的频率带宽（单位为Hz） Baud：波特，即码元/秒&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用奈氏准则给出的公式，就可以根据信道的频率带宽，计算出信道的最高码元传输速率。&lt;/li&gt;
&lt;li&gt;只要码元传输速率不超过根据奈氏准则计算出的上限，就可以避免码间串扰。&lt;/li&gt;
&lt;li&gt;奈氏准则给出的是理想低通信道的最高码元传输速率，它和实际信道有较大的差别。因此，一个实际的信道所能传输的最高码元传输速率，要明显低于奈氏准则给出的上限值。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;码元传输速率又称为波特率&lt;/strong&gt;、调制速率、波形速率或符号速率。&lt;/li&gt;
&lt;li&gt;波特率与比特率有一定的关系：
&lt;ul&gt;
&lt;li&gt;当1个码元只携带1比特的信息量时，波特率（码元/秒）与比特率（比特/秒）在数值上是相等的。&lt;/li&gt;
&lt;li&gt;当1个码元携带n比特的信息量时，波特率（码元/秒）转换成比特率（比特/秒）时，数值要乘以n。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-01-05-194812.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="香农公式"&gt;香农公式
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;带宽受限&lt;/strong&gt;且有&lt;strong&gt;高斯白噪声&lt;/strong&gt;干扰的信道的&lt;strong&gt;极限信息传输速率&lt;/strong&gt;&lt;/p&gt;
$$
C=Wlog_2(1+\frac{S}{N})(b/s)
$$&lt;p&gt;
C：信道的极限信息传输速率（单位为b/s）&lt;/p&gt;
&lt;p&gt;W：信道的频率带宽（单位为Hz）&lt;/p&gt;
&lt;p&gt;S：信道内所传信号的平均功率&lt;/p&gt;
&lt;p&gt;N：信道内的高斯噪声功率&lt;/p&gt;
&lt;p&gt;S/N：信噪比，常用分贝（dB）表示&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;信噪比&lt;/strong&gt;（dB）=$10log_{10}(\frac{S}{N})(dB)$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;信道的频率带宽W或信道中的信噪比S/N越大，信道的极限信息传输速率C就越高。&lt;/li&gt;
&lt;li&gt;实际信道不可能无限制地提高频率带宽W或信道中的信噪比S/N。&lt;/li&gt;
&lt;li&gt;实际信道中能够达到的信息传输速率，要比香农公式给出的极限传输速率低不少。这是因为在实际信道中，信号还要受到其他一些损伤，例如各种脉冲干扰和信号衰减等，这些因素在香农公式中并未考虑。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-01-05-195041.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-01-05-195412.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2 id="26-信道复用技术"&gt;2.6 信道复用技术
&lt;/h2&gt;&lt;h4 id="基本原理"&gt;基本原理
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;复用（Multiplexing）就是&lt;strong&gt;在一条传输媒体上同时传输多路用户的信号&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;当一条传输媒体的传输容量大于多条信道传输的总容量时，就可以通过复用技术，在这条传输媒体上建立多条通信信道，以便&lt;strong&gt;充分利用传输媒体的带宽&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;尽管实现信道复用会增加通信成本（需要复用器、分用器以及费用较高的大容量共享信道），但如果&lt;strong&gt;复用的信道数量较大，还是比较划算的&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="常见技术"&gt;常见技术
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;频分复用 FDM
&lt;ul&gt;
&lt;li&gt;所有用户&lt;strong&gt;同时&lt;/strong&gt;占用不同的频带资源并行通信&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;时分复用 TDM
&lt;ul&gt;
&lt;li&gt;所有用户&lt;strong&gt;在不同的时间占用同样的频带&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;波分复用 WDM
&lt;ul&gt;
&lt;li&gt;根据频分复用的设计思想，可在一根光纤上&lt;strong&gt;同时传输多个频率（波长）相近的光载波信号&lt;/strong&gt;，实现基于光纤的频分复用技术。&lt;/li&gt;
&lt;li&gt;目前可以在一根光纤上复用80路或更多路的光载波信号。因此，这种复用技术也称为&lt;strong&gt;密集波分复用DWDM&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;码分复用 CDM
&lt;ul&gt;
&lt;li&gt;如果有两个或多个站同时发送数据，则信道中的信号就是这些站各自所发送一系列码片序列或码片序列反码的&lt;strong&gt;叠加&lt;/strong&gt;。为了从信道中&lt;strong&gt;分离&lt;/strong&gt;出每个站的信号，给每个站&lt;strong&gt;指派码片序列&lt;/strong&gt;时，必须遵循以下规则：
&lt;ul&gt;
&lt;li&gt;分配给每个站的码片序列必须各不相同，实际常采用伪随机码序列。&lt;/li&gt;
&lt;li&gt;分配给每个站的码片序列必须相互正交，即各码片序列相应的码片向量之间的规格化内积为0。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;令向量A表示站A的码片向量，向量B表示站B的码片向量。两个不同站A和B的码片序列相互正交，就是向量A与向量B的规格化内积为0，如下式所示。
$A\cdot B=\frac{1}{m}A_iB_i=0$&lt;/li&gt;
&lt;li&gt;假设知道各手机的码片序列，给手机A发送比特1，给手机B发送比特0，各手机用自己的码片向量与收到的叠加后的码片向量，做规格化内积运算：
&lt;ul&gt;
&lt;li&gt;$(A + \overline{B}) \cdot A = A \cdot A + A \cdot \overline{B} = 1 + 0 = 1$ 运算结果为1，表明收到的是比特1&lt;/li&gt;
&lt;li&gt;$(A + \overline{B}) \cdot B = A \cdot B + \overline{B} \cdot B = 0 + (-1) = -1$ 运算结果为-1，表明收到的是比特0&lt;/li&gt;
&lt;li&gt;$(A + \overline{B}) \cdot C = A \cdot C + \overline{B} \cdot C = 0 + 0 = 0$ 运算结果为0，表明没有收到信息&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-01-05-231025.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2 id="31-数据链路层概述"&gt;3.1 数据链路层概述
&lt;/h2&gt;&lt;h4 id="在网络体系中的地位"&gt;在网络体系中的地位
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-01-05-234331.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="链路数据链路和帧"&gt;链路、数据链路和帧
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;链路（Link）是指从一个节点到相邻节点的一段物理线路（有线或无线），而&lt;strong&gt;中间没有任何其他的交换节点&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;数据链路（Data Link）是基于链路的。当在一条链路上传送数据时，除需要链路本身，还需要一些必要的通信协议来控制这些数据的传输，把&lt;strong&gt;实现这些协议的硬件和软件加到链路上&lt;/strong&gt;，就构成了数据链路。&lt;/li&gt;
&lt;li&gt;计算机中的网络适配器（俗称网卡）和其相应的&lt;strong&gt;软件驱动程序&lt;/strong&gt;就实现了这些协议。&lt;strong&gt;一般的网络适配器都包含了物理层和数据链路层这两层的功能&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;帧（Frame）是&lt;strong&gt;数据链路层&lt;/strong&gt;对等实体之间在水平方向进行逻辑通信的&lt;strong&gt;协议数据单元PDU&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-01-05-233458.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2 id="32-数据链路层的三个重要问题"&gt;3.2 数据链路层的三个重要问题
&lt;/h2&gt;&lt;h4 id="封装成帧和透明传输"&gt;封装成帧和透明传输
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;数据链路层给上层交付下来的协议数据单元PDU添加帧首部和帧尾部，这称为&lt;strong&gt;封装成帧&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;如果能够采取措施，使得数据链路层对上层交付的PDU的内容没有任何限制，就好像数据链路层不存在一样，就称其为&lt;strong&gt;透明传输&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="差错检测"&gt;差错检测
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;帧在传输的过程中可能出现误码。&lt;/li&gt;
&lt;li&gt;接收方根据发送方添加在帧尾部中的&lt;strong&gt;检错码&lt;/strong&gt;，可以检测出帧是否出现了误码。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="可靠传输"&gt;可靠传输
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;不可靠传输服务：收到有误码的帧，直接丢弃，其他什么也不做；未收到发送方发送的帧，也不进行任何处理。&lt;/li&gt;
&lt;li&gt;可靠传输服务：实现发送方发送什么，接收方最终都能正确收到。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="321-封装成帧和透明传输"&gt;3.2.1 封装成帧和透明传输
&lt;/h3&gt;&lt;h4 id="封装成帧"&gt;封装成帧
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;封装成帧是指数据链路层给上层交付下来的协议数据单元PDU添加一个首部和一个尾部，使之成为帧。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;帧的首部和尾部中有包含一些&lt;strong&gt;重要的控制信息&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;帧首部和尾部的作用之一就是&lt;strong&gt;帧定界&lt;/strong&gt;。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;但帧首部和尾部不一定有帧定界标志。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;为了提高数据链路层传输帧的效率，应当使&lt;strong&gt;帧的数据载荷的长度尽可能地大于首部和尾部的长度&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;考虑到对缓存空间的需求以及差错控制等诸多因素，每一种数据链路层协议都规定了帧的数据载荷的长度上限，即&lt;strong&gt;最大传送单元&lt;/strong&gt;（Maximum Transfer Unit，MTU）。例如，以太网的MTU为1500个字节。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="透明传输"&gt;透明传输
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;透明传输是指&lt;strong&gt;数据链路层对上层交付的PDU的内容没有任何限制&lt;/strong&gt;，就好像数据链路层不存在一样。&lt;/li&gt;
&lt;li&gt;如果传输的内容中有和定界符完全一样的内容，那么就会误判帧结束，但是如果限制了内容，就不是透明传输。
&lt;ul&gt;
&lt;li&gt;面向字节的物理链路使用&lt;strong&gt;字节填充&lt;/strong&gt;的方法实现透明传输。即在把帧交给物理层之前，要在和定界符相同的内容前加入&lt;strong&gt;转义字符&lt;/strong&gt;，或者在和转义字符相同的内容前加入&lt;strong&gt;转义字符&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;面向比特的物理链路使用&lt;strong&gt;比特填充&lt;/strong&gt;的方法实现透明传输。即在内容中连续遇到5个1时，在后面加0（因为01111110就是帧定界符了）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-24-135310.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-24-135929.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="322-差错检测"&gt;3.2.2 差错检测
&lt;/h3&gt;&lt;h4 id="误码"&gt;误码
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;实际的通信链路都不是理想的，受到噪声干扰、传输媒体质量等因素影响，&lt;strong&gt;比特在传输过程中可能会产生差错&lt;/strong&gt;（称为比特差错）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;比特1可能变成比特0&lt;/li&gt;
&lt;li&gt;比特0可能变成比特1&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在一段时间内，传输错误的比特数量占所传输比特总数的比率称为&lt;strong&gt;误码率&lt;/strong&gt;（Bit Error Rate, BER）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;提高链路的信噪比，可以降低误码率&lt;/strong&gt;。但在实际的通信链路上，不可能使误码率下降为零。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="奇偶校验"&gt;奇偶校验
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;奇校验是在待发送的数据后面添加1个&lt;strong&gt;校验位&lt;/strong&gt;，使得添加该校验位后的整个数据中比特&lt;strong&gt;1的个数为奇数&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;偶校验是在待发送的数据后面添加1个&lt;strong&gt;校验位&lt;/strong&gt;，使得添加该校验位后的整个数据中比特&lt;strong&gt;1的个数为偶数&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;如果在数据位产生了1位误码，&lt;strong&gt;1的个数的奇偶性发生改变&lt;/strong&gt;，可检出错误。校验位同理。但是若数据位和校验位&lt;strong&gt;各&lt;/strong&gt;出现1位误码，那么1个数的&lt;strong&gt;奇偶性不变&lt;/strong&gt;，检验不到错误&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="循环冗余校验"&gt;循环冗余校验
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;数据链路层广泛使用漏检率极低的&lt;strong&gt;循环冗余校验&lt;/strong&gt;（Cyclic Redundancy Check，CRC）检错技术。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="生成多项式"&gt;生成多项式
&lt;/h5&gt;$$
G(X) = X^4 + X^2 + X + 1= \boxed{1} \cdot X^4 + \boxed{0} \cdot X^3 + \boxed{1} \cdot X^2 + \boxed{1} \cdot X^1 + \boxed{1} \cdot X^0
$$&lt;p&gt;生成多项式各项系数构成的比特串：10111（计算冗余码时作为除数）&lt;/p&gt;
&lt;p&gt;生成多项式必须包含最低此项，即&amp;quot;1&amp;quot;&lt;/p&gt;
&lt;h5 id="crc操作"&gt;CRC操作
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;发送方CRC操作&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-26-101057.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-26-102333.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;接收方CRC操作&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-26-101439.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-26-103107.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="总结"&gt;总结
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;奇偶校验、循环冗余校验等差错检测技术&lt;/strong&gt;，只能检测出传输过程中出现了差错，但并&lt;strong&gt;不能定位错误&lt;/strong&gt;，因此&lt;strong&gt;无法纠正错误&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;要想纠正传输中的差错，可以使用冗余信息更多的&lt;strong&gt;纠错码&lt;/strong&gt;（例如海明码）进行&lt;strong&gt;前向纠错&lt;/strong&gt;。但纠错码的开销比较大，在计算机网络中较少使用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在计算机网络中，通常采用后续课程中将要介绍的&lt;strong&gt;检错重传方式来纠正传输中的差错，或者仅仅丢弃检测到差错的帧&lt;/strong&gt;，这取决于数据链路层向其上层提供的是可靠传输服务还是不可靠传输服务。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;循环冗余校验CRC具有很好的检错能力（漏检率极低）&lt;/strong&gt;，虽然计算比较复杂，但非常&lt;strong&gt;易于用硬件实现&lt;/strong&gt;，因此被广泛应用于数据链路层。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="323-可靠传输"&gt;3.2.3 可靠传输
&lt;/h3&gt;&lt;h4 id="可靠传输的相关概念"&gt;可靠传输的相关概念
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;可靠传输服务：通过某种机制实现&lt;strong&gt;发送方发送什么，接收方最终就能收到什么&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;传输差错包括：&lt;strong&gt;分组重复、分组失序、分组丢失和误码&lt;/strong&gt;（比特差错）。其中分组重复、分组失序、分组丢失出现在数据链路层的上层，误码出现在数据链路层的下层&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可靠传输服务并不局限于数据链路层&lt;/strong&gt;，其他各层均可选择实现可靠传输。&lt;/li&gt;
&lt;li&gt;可靠传输的实现比较复杂，开销比较大，是否使用可靠传输取决于应用需求。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-26-104300.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="停止-等待-sw-协议"&gt;停止-等待 (SW) 协议
&lt;/h4&gt;&lt;h5 id="实现原理"&gt;实现原理
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;发送方发送DATA，接收方的差错检测若检测&lt;strong&gt;无误码&lt;/strong&gt;，则接受并发送&lt;strong&gt;确认分组&lt;/strong&gt;ACK。&lt;/li&gt;
&lt;li&gt;发送方发送DATA，接收方的差错检测若检测&lt;strong&gt;有误码&lt;/strong&gt;，则丢弃并发送&lt;strong&gt;否认分组&lt;/strong&gt;NAK。那么然后发送方要&lt;strong&gt;重传&lt;/strong&gt;之前有误码的数据分组，再去经过接收方的差错检测。&lt;/li&gt;
&lt;li&gt;发送方发送DATA，若是传输&lt;strong&gt;中途丢失&lt;/strong&gt;，接收方就不会返回分组，发送方需要设置&lt;strong&gt;超时重传时间RTO&lt;/strong&gt;，而且要略大于收发双方的&lt;strong&gt;平均往返时间RTT&lt;/strong&gt;。然后进行重新传输。
&lt;ul&gt;
&lt;li&gt;在数据链路层，点对点的往返时间 RTT 比较固定，RTO 就比较好设定。&lt;/li&gt;
&lt;li&gt;在运输层，由于端到端往返时间非常不确定，设置合适的超时重传时间 RTO 有时并不容易。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;接收方发送ACK，若是传输&lt;strong&gt;中途丢失&lt;/strong&gt;，结合上一条，发送方就会&lt;strong&gt;超时重传&lt;/strong&gt;，但这样接收方就&lt;strong&gt;重复接收&lt;/strong&gt;了同一个DATA。为解决该问题，引入数据&lt;strong&gt;分组编号&lt;/strong&gt;，分组编号即0和1，DATA就该叫做DATA0/1。接收方&lt;strong&gt;丢弃重复的数据分组，再发送一个确认分组&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;更复杂的情况会出现ACK被发送方重复接收，同理需要给ACK分组编号。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-26-112517.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;停止-等待协议属于自动请求重传（Automatic Repeat reQuest, ARQ）协议。&lt;/strong&gt; 即重传的请求是发送方自动进行的，而不是接收方请求发送方重传某个误码的数据分组。&lt;/p&gt;
&lt;h5 id="信道利用率"&gt;信道利用率
&lt;/h5&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-26-113359.png" alt="" loading="lazy" /&gt;
&lt;/p&gt;
$$
信道利用率\ U \approx \frac{T_D}{T_D + RTT + T_A}
$$&lt;p&gt;
说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;$T_D$&lt;/strong&gt;：发送方发送数据分组所耗费的发送时延。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;$RTT$&lt;/strong&gt;：收发双方之间的往返时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;$T_A$&lt;/strong&gt;：接收方发送确认分组所耗费的发送时延。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于确认分组的长度通常远小于数据分组的长度，即 &lt;strong&gt;$T_A \ll T_D$&lt;/strong&gt;，公式可以简化为：
&lt;/p&gt;
$$
U \approx \frac{T_D}{T_D + RTT}
$$&lt;p&gt;
简化后的利用率主要受 $RTT$ 与 $T_D$ 比例关系的影响：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;当 $RTT \gg T_D$ 时&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;结果&lt;/strong&gt;：信道利用率 &lt;strong&gt;$U$ 很低&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;典型案例&lt;/strong&gt;：卫星链路（由于距离极远，往返时延很大）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;当 $RTT \ll T_D$ 时&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;结果&lt;/strong&gt;：信道利用率 &lt;strong&gt;$U$ 比较高&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;典型案例&lt;/strong&gt;：无线局域网（往返时间远小于数据发送时间）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-26-111200.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="回退n帧-gbn-协议"&gt;回退N帧 (GBN) 协议
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-26-115114.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;在使用流水线传输方式时，发送方不能无限制地连续发送数据分组&lt;/strong&gt;，否则可能会导致网络中的路由器或接收方来不及处理这些数据分组，进而导致数据分组的丢失，这实际上是对网络资源的浪费。因此，必须采取措施来限制发送方连续发送数据分组的数量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;回退N帧协议采用流水线传输方式，并且利用发送窗口来限制发送方连续发送数据分组的数量，这属于连续ARQ协议。&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="发送方"&gt;发送方
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;发送窗口 $W_T$ 的取值范围是 $1 &lt; W_T \leq (2^n - 1)$，其中，$n$ 是构成&lt;strong&gt;分组序号的比特数量&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;如果 $W_T = 1$&lt;/strong&gt;：变成了停止-等待协议。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;如果 $W_T &gt; (2^n - 1)$&lt;/strong&gt;：接收方&lt;strong&gt;无法分辨新旧数据分组&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;可在未收到接收方确认分组的情况下，将序号落入发送窗口内的多个数据分组全部发送出去。&lt;/li&gt;
&lt;li&gt;只有收到对已发送数据分组的确认分组时，发送窗口才能向前滑动到相应位置。&lt;/li&gt;
&lt;li&gt;收到多个重复确认时，可在重传计时器超时前尽早开始重传，由具体实现决定（即确定收到几个重复确认进行重传）。&lt;/li&gt;
&lt;li&gt;发送窗口内某个已发送的数据分组产生超时重传时，发送窗口内该数据分组的后续已发送的数据分组也必须全部重传，这就是回退N帧 (Go-back-N, GBN) 协议名称的由来。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-26-141807.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h5 id="接收方"&gt;接收方
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;接收窗口 $W_R = 1$ 的，因此只能按序接收数据分组。&lt;/li&gt;
&lt;li&gt;只接收序号落入接收窗口内且无误码的数据分组，并且将接收窗口向前滑动一个位置，与此同时给发送方发送相应的确认分组。&lt;/li&gt;
&lt;li&gt;为了减少开销，接收方不必每收到一个按序到达且无误码的数据分组就给发送方发送一个相应的确认分组。
&lt;ul&gt;
&lt;li&gt;可以在连续收到多个按序到达且无误码的数据分组后（数量由具体实现决定），才针对最后一个数据分组发送确认分组，这称为&lt;strong&gt;累积确认&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;或者可以在自己有数据分组要发送时才对之前按序接收且无误码的数据分组进行捎带确认。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;接收方收到未按序到达的数据分组后，除丢弃外，还可对之前最后一个按序到达的数据分组进行重复确认，以便发送方尽快重传。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-26-142240.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="选择重传协议"&gt;选择重传协议
&lt;/h4&gt;&lt;p&gt;用 $n (n &gt; 1)$ 个比特给分组编号，发送窗口 $W_T$ 与接收窗口 $W_R$ 的关系如下：
&lt;/p&gt;
$$
\begin{cases} 1 &lt; W_R \leq W_T \\ W_T + W_R \leq 2^n \end{cases} \implies 1 &lt; W_R \leq 2^{(n-1)}
$$&lt;ul&gt;
&lt;li&gt;当 $W_R$ 取最大值 $2^{(n-1)}$ 时，$W_T$ 能取到的最大值也为 $2^{(n-1)}$。&lt;/li&gt;
&lt;li&gt;$W_R$ 超过 $W_T$ 没有意义&lt;/li&gt;
&lt;li&gt;确保接收窗口向前滑动后，落入接收窗口内的新序号与之前的旧序号没有重叠，避免无法分辨新旧数据分组。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="发送方-1"&gt;发送方
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;可在未收到接收方确认分组的情况下，将序号落入发送窗口内的多个数据分组全部发送出去。&lt;/li&gt;
&lt;li&gt;只有按序收到对已发送数据分组的确认分组时，发送窗口才能向前滑动到相应位置。&lt;/li&gt;
&lt;li&gt;如果收到未按序到达的确认分组，应对其进行记录，以防止其相应数据分组的超时重发，但发送窗口不能向前滑动。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="接收方-1"&gt;接收方
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;可接收未按序到达但没有误码并且序号落入接收窗口内的数据分组。&lt;/li&gt;
&lt;li&gt;为了使发送方仅重传出现差错的分组，接收方不再采用累积确认，而需要对每一个正确接收的数据分组进行逐一确认。&lt;/li&gt;
&lt;li&gt;只有在按序接收数据分组后，接收窗口才能向前滑动到相应位置。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="33-点对点协议-ppp"&gt;3.3 点对点协议 (PPP)
&lt;/h2&gt;&lt;h4 id="概述"&gt;概述
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;点对点协议（Point-to-Point Protocol, PPP）是目前使用最广泛的点对点&lt;strong&gt;数据链路层协议&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;点对点协议PPP主要有两种应用：
&lt;ul&gt;
&lt;li&gt;用户到 ISP 的连接：例如通过拨号或 ADSL 接入互联网。&lt;/li&gt;
&lt;li&gt;路由器之间的点对点链路：用于连接核心网络中的两个节点。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;从网络体系结构的角度看点对点协议 PPP 的组成
&lt;ul&gt;
&lt;li&gt;一套网络控制协议 NCPs&lt;/li&gt;
&lt;li&gt;一个网络层 PDU 封装到串行链路的方法&lt;/li&gt;
&lt;li&gt;一个链路控制协议 LCP&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="帧格式"&gt;帧格式
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-26-150751.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;标志（Flag）字段&lt;/strong&gt;：PPP帧的定界符，取值为 &lt;strong&gt;0x7E&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;地址（Address）字段&lt;/strong&gt;：取值为 &lt;strong&gt;0xFF&lt;/strong&gt;，预留（目前没有什么作用）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;控制（Control）字段&lt;/strong&gt;：取值为 &lt;strong&gt;0x03&lt;/strong&gt;，预留（目前没有什么作用）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;协议（Protocol）字段&lt;/strong&gt;：其值用来指明帧的数据载荷应向上交付给哪个协议处理。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;帧检验序列（Frame Check Sequence, FCS）字段&lt;/strong&gt;：其值是使用循环冗余校验CRC计算出的检错码。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="透明传输-1"&gt;透明传输
&lt;/h4&gt;&lt;h5 id="面向字节的异步链路"&gt;面向字节的异步链路
&lt;/h5&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-26-151729.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;发送方的处理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将数据载荷中出现的每一个 0x7E &lt;strong&gt;减去 0x20&lt;/strong&gt;（相当于异或 0x20），然后在其前面&lt;strong&gt;插入转义字符 0x7D&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;若数据载荷中原来就含有 &lt;strong&gt;0x7D&lt;/strong&gt;，则把每一个 0x7D &lt;strong&gt;减去 0x20&lt;/strong&gt;，然后在其前面&lt;strong&gt;插入转义字符 0x7D&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;将数据载荷中出现的每一个 &lt;strong&gt;ASCII 码控制字符&lt;/strong&gt;（即数值小于 0x20 的字符），&lt;strong&gt;加上 0x20&lt;/strong&gt;（相当于异或 0x20，将其转换成非控制字符），然后在其前面&lt;strong&gt;插入转义字符 0x7D&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;接收方的处理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;进行与发送方相反的变换，就可以正确地恢复出未经字节填充的原始数据载荷。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="面向比特的同步链路"&gt;面向比特的同步链路
&lt;/h5&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-26-152240.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;发送方的处理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对帧的数据载荷进行扫描（一般由硬件完成），每出现 &lt;strong&gt;5 个连续的比特 1&lt;/strong&gt;，则在其后&lt;strong&gt;填充一个比特 0&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;接收方的处理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对帧的数据载荷进行扫描，每出现 5 个连续的比特 1 时，就把其后的一个比特 0 删除。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="差错检测-1"&gt;差错检测
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-26-153004.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;帧检验序列FCS字段&lt;/strong&gt;：其值是使用&lt;strong&gt;循环冗余校验CRC&lt;/strong&gt;计算出的检错码。&lt;/li&gt;
&lt;li&gt;CRC采用的生成多项式为：&lt;/li&gt;
&lt;/ul&gt;
$$
CRC-CCITT = X^{16} + X^{12} + X^5 + 1
$$&lt;h4 id="工作状态"&gt;工作状态
&lt;/h4&gt;&lt;p&gt;以用户主机拨号接入因特网服务提供者ISP的拨号服务器的过程为例&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-26-153348.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2 id="34-共享式以太网"&gt;3.4 共享式以太网
&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;年份&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;里程碑事件&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;关键细节&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;1975年&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;以太网诞生&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Robert Metcalfe (1946-)，美国Xerox公司，速率 &lt;strong&gt;2.94Mb/s&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;1976年&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;以太网里程碑论文&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Robert Metcalfe 与助手 David Boggs 发表论文《以太网：局域计算机网络的分布式包交换技术》&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;1979年&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;3Com公司成立&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Robert Metcalfe 离开 Xerox 成立 3Com；游说 DEC、Intel 和 Xerox 共同将以太网标准化&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;1980年&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;以太网标准V1&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;DIX Ethernet V1&lt;/strong&gt;，速率 &lt;strong&gt;10Mb/s&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;1982年&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;以太网标准V2&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;DIX Ethernet V2&lt;/strong&gt;：第一个局域网产品的标准，被大量使用&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;1983年&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;IEEE 以太网标准&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;IEEE 802.3 以太网标准&lt;/strong&gt;：对 DIX Ethernet V2 的帧格式做了很小的改动，当时没有被广泛使用&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;以太网目前已经从传统的共享式以太网发展到&lt;strong&gt;交换式以太网&lt;/strong&gt;，传输速率已经大幅提高。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="341-网络适配器和mac地址"&gt;3.4.1 网络适配器和MAC地址
&lt;/h3&gt;&lt;h4 id="网络适配器"&gt;网络适配器
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;要将计算机连接到以太网，需要使用相应的&lt;strong&gt;网络适配器&lt;/strong&gt;（Adapter），网络适配器一般简称为“网卡”。&lt;/li&gt;
&lt;li&gt;在计算机内部，&lt;strong&gt;网卡与CPU&lt;/strong&gt;之间的通信，一般是通过计算机主板上的I/O总线以并行传输方式进行的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;网卡与外部以太网&lt;/strong&gt;（局域网）之间的通信，一般是通过传输媒体（同轴电缆、双绞线电缆、光纤）以&lt;strong&gt;串行方式&lt;/strong&gt;进行的。&lt;/li&gt;
&lt;li&gt;网卡除要&lt;strong&gt;实现物理层和数据链路层功能&lt;/strong&gt;，其另外一个重要功能就是要进行&lt;strong&gt;并行传输和串行传输&lt;/strong&gt;的转换。由于网络的传输速率和计算机内部总线上的传输速率并不相同，因此在网卡的核心芯片中都会包含用于缓存数据的存储器。&lt;/li&gt;
&lt;li&gt;在确保网卡硬件正确的情况下，为了使网卡正常工作，还必须要在计算机的操作系统中为网卡安装相应的设备驱动程序。驱动程序负责驱动网卡发送和接收帧。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-26-160633.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="mac地址"&gt;MAC地址
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;在点对点信道，数据链路层不需要使用地址。而在广播信道，数据链路层必须使用地址来区分各主机。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MAC地址&lt;/strong&gt;一般被固化在网卡的电可擦可编程只读存储器EEPROM中，因此MAC地址也被称为硬件地址，有时被称为物理地址（和物理层无关，属于数据链路层范畴）&lt;/li&gt;
&lt;li&gt;MAC地址是对网络上&lt;strong&gt;各接口&lt;/strong&gt;的唯一标识，而不是各设备的唯一标识。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="地址格式"&gt;地址格式
&lt;/h5&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-26-161212.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;其中第 1 字节的 b1 位：G/L (Global/Local)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$G/L = 0$：全球管理&lt;/li&gt;
&lt;li&gt;$G/L = 1$：本地管理&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第 1 字节的 b0 位：I/G (Individual/Group)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$I/G = 0$：单播地址&lt;/li&gt;
&lt;li&gt;$I/G = 1$：多播地址&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;第 1 字节 b1 位&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;第 1 字节 b0 位&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;MAC 地址类型&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;地址占比&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;全球单播&lt;/strong&gt;（由厂商生产网络设备时固化在设备中）&lt;/td&gt;
					&lt;td&gt;1/4&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;全球多播&lt;/strong&gt;（交换机、路由器等标准网络设备所支持的多播地址）&lt;/td&gt;
					&lt;td&gt;1/4&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;本地单播&lt;/strong&gt;（由网络管理员分配，优先级高于网络接口的全球单播地址）&lt;/td&gt;
					&lt;td&gt;1/4&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;本地多播&lt;/strong&gt;（可由用户对网卡编程实现，以表明其属于哪些多播组）&lt;/td&gt;
					&lt;td&gt;1/4&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;其字节发送顺序是从第1字节开始，到第6字节。字节内的比特发送顺序是从b0到b7。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="网卡对无误码帧的处理"&gt;网卡对无误码帧的处理
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;网卡从网络上每收到一个无误码的帧，就检查帧首部中的目的 MAC 地址，按以下情况处理：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;如果目的 MAC 地址是广播地址（FF-FF-FF-FF-FF-FF），则接受该帧。&lt;/li&gt;
&lt;li&gt;如果目的 MAC 地址与网卡上固化的全球单播 MAC 地址相同，则接受该帧。&lt;/li&gt;
&lt;li&gt;如果目的 MAC 地址是网卡支持的多播地址，则接受该帧。&lt;/li&gt;
&lt;li&gt;除上述 (1)、(2) 和 (3) 情况外，丢弃该帧。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;网卡还可被设置为一种特殊的工作方式：&lt;strong&gt;混杂方式&lt;/strong&gt;。工作在混杂方式的网卡，只要收到共享媒体上传来的帧就会收下，而不管帧的目的 MAC 地址是什么。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用途： 对于网络维护和管理人员，这种方式可以监视和分析局域网上的流量，以便找出提高网络性能的具体措施。&lt;/li&gt;
&lt;li&gt;工具示例： &lt;strong&gt;嗅探器&lt;/strong&gt; (Sniffer) 就是一种工作在混杂方式的网卡，再配合相应的工具软件（WireShark），就可以作为一种非常有用的网络工具来学习和分析网络。&lt;/li&gt;
&lt;li&gt;风险提示： 混杂方式就像一把“双刃剑”，黑客常利用这种方式非法获取网络用户的口令。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="342-以太网在共享信道下的运作机制"&gt;3.4.2 以太网在共享信道下的运作机制
&lt;/h3&gt;&lt;h4 id="csmacd协议"&gt;CSMA/CD协议
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;在以太网的发展初期，人们普遍认为“无源的电缆线比有源器件可靠”，因此将多个站点连接在一条总线上来构建&lt;strong&gt;共享总线以太网&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;共享总线以太网具有&lt;strong&gt;天然的广播特性&lt;/strong&gt;，即使总线上某个站点给另一个站点发送单播帧，表示帧的信号也会沿着总线传播到总线上的其他各站点。&lt;/li&gt;
&lt;li&gt;当某个站点在总线上发送帧时，总线资源会被该站点独占。此时，如果总线上的其他站点也要在总线上发送帧，就会产生&lt;strong&gt;信号碰撞&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;当两个或多个站点同时使用总线发送帧时，就会产生信号碰撞。&lt;/li&gt;
&lt;li&gt;为了解决各站点争用总线的问题，共享总线以太网使用了一种专用协议 &lt;strong&gt;CSMA/CD&lt;/strong&gt;，它是&lt;strong&gt;载波监听多址接入/碰撞检测&lt;/strong&gt; (Carrier Sense Multiple Access/Collision Detection) 的英文缩写词。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="协议组成"&gt;协议组成
&lt;/h5&gt;&lt;p&gt;&lt;strong&gt;多址接入 MA&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;多个站点连接在一条总线上，竞争使用总线。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;载波监听 CS&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个站点在发送帧之前，先要检测一下总线上是否有其他站点在发送帧（“&lt;strong&gt;先听后说&lt;/strong&gt;”）：
&lt;ul&gt;
&lt;li&gt;若检测到总线空闲 96 比特时间（发送 96 比特所耗费的时间，也称为帧间最小间隔），则发送这个帧；&lt;/li&gt;
&lt;li&gt;若检测到总线忙，则继续检测并等待总线转为空闲 96 比特时间，然后发送这个帧。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;碰撞检测 CD&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个正在发送帧的站点边发送边检测碰撞（“&lt;strong&gt;边说边听&lt;/strong&gt;”）：
&lt;ul&gt;
&lt;li&gt;一旦发现总线上出现碰撞，立即停止发送，退避一段随机时间后再次从载波监听开始进行发送（“一旦冲突，立即停说，等待时机，重新再说”）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="协议局限"&gt;协议局限
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;载波监听检测到总线空闲，但&lt;strong&gt;总线并不一定空闲&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;使用CSMA/CD协议的共享总线以太网上的各站点，只是尽量避免碰撞并在出现碰撞时做出退避后重发的处理，但&lt;strong&gt;不能完全避免碰撞&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;在使用CSMA/CD协议时，由于正在发送帧的站点必须“边发送帧边检测碰撞”，因此站点不可能同时进行发送和接收，也就是不可能进行全双工通信，而&lt;strong&gt;只能进行半双工通信&lt;/strong&gt;（双向交替通信）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="共享式以太网的争用期"&gt;共享式以太网的争用期
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-26-172730.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;站点从发送帧开始，最多经过时长 $2\tau$（即 $\delta \to 0$）就可检测出所发送的帧是否遭遇了碰撞。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;因此，共享总线以太网的&lt;strong&gt;端到端往返时间&lt;/strong&gt; $2\tau$ 被称为&lt;strong&gt;争用期&lt;/strong&gt;（Contention Period）或&lt;strong&gt;碰撞窗口&lt;/strong&gt;（Collision Window），它是一个非常重要的参数。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;站点从发送帧开始，&lt;strong&gt;经过争用期&lt;/strong&gt; $2\tau$ &lt;strong&gt;这段时间还没有检测到碰撞，就可以肯定这次发送不会产生碰撞&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;从争用期的概念可以看出，共享总线以太网上的每一个站点从发送帧开始，到之后的一小段时间内，都有可能遭遇碰撞，而&lt;strong&gt;这一小段时间的长短是不确定&lt;/strong&gt;的，它&lt;strong&gt;取决于另一个发送帧的站点与本站点的距离&lt;/strong&gt;，但不会超过总线的端到端往返传播时延，即一个争用期 $2\tau$。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;很显然，总线的长度越长（单程端到端传播时延越大），网络中站点数量越多，发生碰撞的概率就越大。&lt;/li&gt;
&lt;li&gt;因此，共享以太网的总线长度不能太长，接入的站点数量也不能太多。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;10Mb/s 共享总线以太网参数规定：争用期 $2\tau$ 的值为 512 比特的发送时间，即 $51.2\mu s$。也称为512 比特时间：这是传统以太网的一个基石参数。
由于 $10Mb/s$ 下 512 比特等于 64 字节，这也就是&lt;strong&gt;以太网最短帧长为 64 字节&lt;/strong&gt;的物理由来：为了确保在发送完 64 字节之前，信号一定能完成一个来回（争用期），从而检测出是否发生了碰撞。
&lt;/p&gt;
$$
 2\tau = \frac{512\ b}{10\ Mb/s} = \frac{512\ b}{10 \times 10^6\ b/s} = 51.2\mu s
$$&lt;p&gt;
除考虑了信号传播时延外，还考虑到网络中可能存在转发器所带来的时延以及产生碰撞时继续发送 32 比特或 48 比特人为干扰信号所持续的时间等。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;假设信号的传播速率为：$2 \times 10^8\ m/s$&lt;/p&gt;
&lt;p&gt;则总线长度为：$2 \times 10^8\ m/s \times 25.6\mu s = 5120m$&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-26-174651.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="共享式以太网的最小最大帧长"&gt;共享式以太网的最小/最大帧长
&lt;/h4&gt;&lt;h5 id="最小帧长"&gt;最小帧长
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;为了确保共享总线以太网上的每一个站点在发送完一个完整的帧之前，能够检测出是否产生了碰撞，帧的发送时延就不能少于共享总线以太网端到端的往返时间，即一个争用期 $2\tau$。
&lt;/p&gt;
$$
 \frac{帧长度 (bit)}{发送速率 (b/s)} \ge 2\tau
 $$&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对于 $10Mb/s$ 的共享总线以太网，其争用期 $2\tau$ 的值规定为 $51.2\mu s$，因此其&lt;strong&gt;最小帧长为 $512b$，即 $64B$。&lt;/strong&gt;
&lt;/p&gt;
$$
 10Mb/s \times 51.2\mu s = 512b = 64B
 $$&lt;ul&gt;
&lt;li&gt;当某个站点在发送帧时，如果帧的前 $64B$ 没有遭遇碰撞，那么帧的后续部分也就不会遭遇碰撞。也就是说，如果遭遇碰撞，就一定是在帧的前 $64B$ 之内。&lt;/li&gt;
&lt;li&gt;由于发送帧的站点边发送帧边检测碰撞，一旦检测到碰撞就立即中止帧的发送，此时已发送的数据量一定小于 $64B$。因此，接收站点收到&lt;strong&gt;长度小于 $64B$ 的帧&lt;/strong&gt;，就可判定这是一个&lt;strong&gt;遭遇了碰撞而异常中止的无效帧&lt;/strong&gt;，将其丢弃即可。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-27-111734.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h5 id="最大帧长"&gt;最大帧长
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;一般来说，&lt;strong&gt;帧的数据载荷的长度应远大于帧首部和尾部的总长度&lt;/strong&gt;，这样可以&lt;strong&gt;提高帧的传输效率&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;然而，如果不限制数据载荷的长度上限，就可能使得&lt;strong&gt;帧的长度太长&lt;/strong&gt;，这会&lt;strong&gt;带来一些问题&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-27-112615.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;以太网V2的MAC帧，最大长度为1518B。其中数据载荷最大为1500B，最小为46B。其它的部分：目的地址、源地址、类型和FCS共占了18B&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="退避算法"&gt;退避算法
&lt;/h4&gt;$$
\text{退避时间} = \text{基本退避时间（争用期 } 2\tau\text{）} \times \text{随机数 } r
$$&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;随机数 $r$ 的取值规则&lt;/strong&gt;：$r$ 从离散的整数集合 $\{0, 1, \dots, (2^k - 1)\}$ 中随机选出一个数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数 $k$ 的定义&lt;/strong&gt;：$k = \min[\text{重传次数}, 10]$。&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;重传次数&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;k&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;离散整数集合 {0,1,…,(2k−1)}&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;可能的退避时间&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;$\{0, 1\}$&lt;/td&gt;
					&lt;td&gt;$0 \times 2\tau, 1 \times 2\tau$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;$\{0, 1, 2, 3\}$&lt;/td&gt;
					&lt;td&gt;$0 \times 2\tau, 1 \times 2\tau, 2 \times 2\tau, 3 \times 2\tau$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;12&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;$\{0, 1, 2, 3, 4, 5, \dots, 1023\}$&lt;/td&gt;
					&lt;td&gt;$0 \times 2\tau, 1 \times 2\tau, 2 \times 2\tau, \dots, 1023 \times 2\tau$&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;如果连续多次发生碰撞，表明可能有较多的站点参与竞争信道。使用上述退避算法可&lt;strong&gt;使重传需要推迟的平均时间随重传次数而增大&lt;/strong&gt;（即&lt;strong&gt;动态退避&lt;/strong&gt;），从而&lt;strong&gt;减小产生碰撞的概率&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;当重传达 16次仍不能成功时&lt;/strong&gt;，表明同时打算发送帧的站点太多，以至于连续产生碰撞。此时应&lt;strong&gt;放弃重传&lt;/strong&gt;并向高层报告。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="信道利用率-1"&gt;信道利用率
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-27-115237.png" alt="" loading="lazy" /&gt;
&lt;/p&gt;
$$
S_{max} = \frac{T_0}{T_0 + \tau} = \frac{1}{1 + \frac{\tau}{T_0}} = \frac{1}{1 + a}
$$&lt;ul&gt;
&lt;li&gt;参数 $a$ 的定义：$a = \frac{\tau}{T_0}$&lt;/li&gt;
&lt;li&gt;参数 $a$ 的值&lt;strong&gt;应尽量小&lt;/strong&gt;，以&lt;strong&gt;提高信道利用率&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;$\tau \downarrow$（分子减小）：共享总线以太网端到端的距离不应太长。&lt;/li&gt;
&lt;li&gt;$T_0 \uparrow$（分母增大）**：**帧的长度应尽量大。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="343-使用集线器的共享式以太网"&gt;3.4.3 使用集线器的共享式以太网
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;若总线上的某个机械连接点接触不良或断开，则整个网络通信就不稳定或彻底断网。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在使用细同轴电缆的共享总线以太网之后，以太网发展出来了一种使用大规模集成电路来替代总线、并且可靠性非常高的设备，叫做&lt;strong&gt;集线器&lt;/strong&gt; (Hub)。&lt;/p&gt;
&lt;p&gt;站点连接到集线器的传输媒体也转而使用更便宜、更灵活的双绞线电缆。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;补充：双绞线电缆两端为 RJ-45 插头，连接至集线器的 RJ-45 插座。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;集线器的一些主要特点如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用集线器的以太网虽然&lt;strong&gt;物理拓扑是星型&lt;/strong&gt;的，但在&lt;strong&gt;逻辑上&lt;/strong&gt;仍然是一个&lt;strong&gt;总线网&lt;/strong&gt;。总线上的各站点共享总线资源，&lt;strong&gt;使用的还是 CSMA/CD 协议&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;集线器&lt;strong&gt;只工作在物理层&lt;/strong&gt;。它的每个接口仅简单地转发比特，并不进行碰撞检测。碰撞检测的任务由各站点中的网卡负责。&lt;/li&gt;
&lt;li&gt;集线器一般都有&lt;strong&gt;少量的容错能力和网络管理功能&lt;/strong&gt;。例如，若网络中某个站点的网卡出现了故障而不停地发送帧，集线器可以检测到这个问题，在内部断开与出故障网卡的连线，使整个以太网能正常工作。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;“传统总线型以太网”向“集线器星型以太网”的异同点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;物理拓扑不相同&lt;/li&gt;
&lt;li&gt;但工作逻辑相同&lt;/li&gt;
&lt;li&gt;网络中的各站点都使用&lt;/li&gt;
&lt;li&gt;CSMA/CD协议来共享&lt;/li&gt;
&lt;li&gt;（争用）网络资源&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="10base-t"&gt;10BASE-T
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;BASE：采用基带信号进行传输，10：传输速率为 10Mb/s，T：采用双绞线作为传输媒体&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;IEEE于1990年制定了10BASE-T星型以太网的标准802.3i，这种以太网是局域网发展史上的一座非常重要的里程碑，它为以太网在局域网中的统治地位奠定了牢固的基础。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;10BASE-T以太网的通信距离较短，每个站点到集线器的距离不能超过100m。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;IEEE 802.3以太网还可使用光纤作为传输媒体，相应的标准为10BASE-F，“F”表示光纤。光纤主要用作集线器之间的远程连接。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="344-在物理层扩展以太网"&gt;3.4.4 在物理层扩展以太网
&lt;/h3&gt;&lt;h4 id="扩展站点与集线器之间的距离"&gt;扩展站点与集线器之间的距离
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;共享总线以太网中两站点之间的&lt;strong&gt;距离不能太远&lt;/strong&gt;，否则它们之间所传输的&lt;strong&gt;信号就会衰减到使CSMA/CD协议无法正常工作&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;在早期广泛使用粗同轴电缆或细同轴电缆共享总线以太网时，为了提高网络的地理覆盖范围，常用的是&lt;strong&gt;工作在物理层的转发器&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;IEEE 802.3标准规定，两个网段可用一个转发器连接起来，任意两个站点之间最多可以经过三个网段。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;随着使用双绞线和集线器的10BASE-T星型以太网成为以太网的主流类型，扩展网络覆盖范围就很少使用转发器了。10BASE-T星型以太网中每个站点到集线器的距离不能超过100m，因此两站点间的通信距离最大不能超过200m。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在&lt;strong&gt;10BASE-T星型以太网&lt;/strong&gt;中，可使用&lt;strong&gt;光纤&lt;/strong&gt;和一对&lt;strong&gt;光纤调制解调器&lt;/strong&gt;来扩展站点与集线器之间的距离。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这种扩展方法比较简单，所需付出的代价是：为站点和集线器各增加一个用于电信号和光信号转换的光纤调制解调器，以及它们之间的一对通信光纤。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;信号在光纤中的衰减和失真很小，因此使用这种方法可以很简单地将站点与集线器之间的距离扩展到&lt;strong&gt;1000m以上&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="扩展共享式以太网的覆盖范围和站点数量"&gt;扩展共享式以太网的覆盖范围和站点数量
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;以太网集线器一般具有8~32个接口，如果要连接的站点数量超过了单个集线器能够提供的接口数量，就需要使用多个集线器，这样就可以连接成覆盖更大范围、连接更多站点的多级星型以太网。&lt;/li&gt;
&lt;li&gt;采用多个集线器连接而成的多级星型以太网，在扩展了网络覆盖范围和站点数量的同时，也带来了一些负面因素。&lt;/li&gt;
&lt;li&gt;在物理层扩展的共享式以太网仍然是一个&lt;strong&gt;碰撞域&lt;/strong&gt;，不能连接太多的站点，否则可能会出现&lt;strong&gt;大量的碰撞&lt;/strong&gt;，导致平均吞吐量太低。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="345-在数据链路层扩展以太网"&gt;3.4.5 在数据链路层扩展以太网
&lt;/h3&gt;&lt;h4 id="网桥的基本工作原理"&gt;网桥的基本工作原理
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;网桥 (bridge) 工作在数据链路层 (包含其下的物理层)，因此&lt;strong&gt;网桥具备属于数据链路层范畴的相关能力&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;网桥可以&lt;strong&gt;识别帧的结构&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;网桥可以根据帧首部中的&lt;strong&gt;目的MAC地址&lt;/strong&gt;和网桥自身的&lt;strong&gt;帧转发表&lt;/strong&gt;来转发或丢弃所收到的帧。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-27-141446.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="透明网桥的自学习和转发帧的流程"&gt;透明网桥的自学习和转发帧的流程
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;透明网桥 (Transparent Bridge) 通过&lt;strong&gt;自学习算法&lt;/strong&gt;建立转发表。&lt;/p&gt;
&lt;p&gt;透明网桥中的“&lt;strong&gt;透明&lt;/strong&gt;”，是指以太网中的各站点并不知道自己所发送的帧将会经过哪些网桥的转发，最终到达目的站点。也就是说，&lt;strong&gt;以太网中的各网桥对于各站点而言是看不见的&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;透明网桥的标准是IEEE 802.1D，它通过一种自学习算法&lt;strong&gt;基于以太网中各站点间的相互通信逐步建立起自己的转发表&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;网桥收到帧后进行登记（即自学习），登记的内容为帧的&lt;strong&gt;源MAC地址&lt;/strong&gt;和进入网桥的&lt;strong&gt;接口号&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;网桥根据帧的&lt;strong&gt;目的MAC地址&lt;/strong&gt;和网桥的&lt;strong&gt;转发表&lt;/strong&gt;对帧进行转发，包含以下三种情况：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;明确转发&lt;/strong&gt;：网桥知道应当从哪个接口转发帧。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;盲目转发&lt;/strong&gt;：网桥不知道应当从哪个接口转发帧，只能将其通过除进入网桥的接口外的其他所有接口转发。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;丢弃&lt;/strong&gt;：网桥知道不应该转发该帧，将其丢弃。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;需注意：
&lt;ul&gt;
&lt;li&gt;如果网桥收到有&lt;strong&gt;误码的帧&lt;/strong&gt;则直接&lt;strong&gt;丢弃&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;如果网桥收到一个无误码的&lt;strong&gt;广播帧&lt;/strong&gt;，则不用进行查表，而是直接从除接收该广播帧的接口的&lt;strong&gt;其他接口转发&lt;/strong&gt;该广播帧。&lt;/li&gt;
&lt;li&gt;转发表中的每条记录都有其&lt;strong&gt;有效时间&lt;/strong&gt;，&lt;strong&gt;到期自动删除&lt;/strong&gt;！这是因为各站点的MAC地址与网桥接口的对应关系并不是永久性的，例如某个站点更换了网卡，其MAC地址就会改变。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="透明网桥的生成树协议stp"&gt;透明网桥的生成树协议STP
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;为了提高以太网的&lt;strong&gt;可靠性&lt;/strong&gt;，有时需要在两个以太网之间使用多个透明网桥来提供&lt;strong&gt;冗余链路&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;在增加冗余链路提高以太网可靠性的同时，却给网络引入了&lt;strong&gt;环路&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;网络中的&lt;strong&gt;广播帧将在环路中永久兜圈&lt;/strong&gt;，造成广播帧充斥整个网络，&lt;strong&gt;网络资源被白白浪费&lt;/strong&gt;，而网络中的主机之间无法正常通信！&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;为了避免广播帧在环路中永久兜圈，透明网桥使用&lt;strong&gt;生成树协议&lt;/strong&gt;（Spanning Tree Protocol, &lt;strong&gt;STP&lt;/strong&gt;），可以在增加冗余链路提高网络可靠性的同时，又避免环路带来的问题。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不管网桥之间连接成了怎样复杂的带环拓扑，网桥之间通过&lt;strong&gt;交互网桥协议单元&lt;/strong&gt;（Bridge Protocol Data Unit, BPDU），&lt;strong&gt;找出原网络拓扑的一个连通子集&lt;/strong&gt;（即生成树），在这个子集里整个连通的网络中&lt;strong&gt;不存在环路&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;当首次连接网桥或网络拓扑发生变化时（人为改变或出现故障），网桥都会重新构造生成树，以确保网络的连通。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="35-交换式以太网"&gt;3.5 交换式以太网
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;网桥的&lt;strong&gt;接口数量很少&lt;/strong&gt;，通常只有2~4个，一般只用来&lt;strong&gt;连接不同的网段&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;1990年面世的&lt;strong&gt;交换式集线器&lt;/strong&gt;（Switching Hub），实质上是具有多个接口的网桥，常称为&lt;strong&gt;以太网交换机&lt;/strong&gt;（Switch）或&lt;strong&gt;二层交换机&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;“&lt;strong&gt;二层&lt;/strong&gt;”是指以太网交换机工作在数据链路层（包括物理层）。&lt;/li&gt;
&lt;li&gt;与网桥相同，交换机内部的转发表也是通过自学习算法，基于网络中各主机间的通信，自动地逐步建立起来的。&lt;/li&gt;
&lt;li&gt;另外，交换机也使用生成树协议STP，来产生能够连通全网但不产生环路的通信路径。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;仅使用交换机（而不使用集线器）的以太网就是交换式以太网。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="351-以太网交换机"&gt;3.5.1 以太网交换机
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;以太网&lt;strong&gt;交换机&lt;/strong&gt;（以下简称交换机）本质上就是一个多接口的网桥：
&lt;ul&gt;
&lt;li&gt;交换机自学习和转发帧的流程与网桥是相同的。&lt;/li&gt;
&lt;li&gt;另外，交换机也使用生成树协议STP，来产生能够连通全网但不产生环路的通信路径。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;交换机的每个接口可以连接&lt;strong&gt;计算机&lt;/strong&gt;，也可以连接&lt;strong&gt;集线器&lt;/strong&gt;或另一个&lt;strong&gt;交换机&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;当交换机的&lt;strong&gt;接口与计算机或交换机连接&lt;/strong&gt;时，可以工作在&lt;strong&gt;全双工方式&lt;/strong&gt;，并能在自身内部同时连通多对接口，使每一对相互通信的计算机都能像独占传输媒体那样，无碰撞地传输数据，这样就&lt;strong&gt;不需要使用CSMA/CD协议&lt;/strong&gt;了。&lt;/li&gt;
&lt;li&gt;当交换机的接口连接的是集线器时，该接口就&lt;strong&gt;只能使用CSMA/CD协议并只能工作在半双工方式&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;现在的交换机和计算机中的网卡都能自动识别上述两种情况，并自动切换到相应的工作方式。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-27-145017.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;主机间的通信&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;交换机1的操作&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;交换机2的操作&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;A $\rightarrow$ B&lt;/td&gt;
					&lt;td&gt;登记 转发（盲目）&lt;/td&gt;
					&lt;td&gt;登记 转发（盲目）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;H $\rightarrow$ A&lt;/td&gt;
					&lt;td&gt;登记 转发（明确）&lt;/td&gt;
					&lt;td&gt;登记 转发（明确）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;E $\rightarrow$ X&lt;/td&gt;
					&lt;td&gt;登记 转发（盲目）&lt;/td&gt;
					&lt;td&gt;登记 转发（盲目）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;X $\rightarrow$ E&lt;/td&gt;
					&lt;td&gt;登记 丢弃&lt;/td&gt;
					&lt;td&gt;收不到&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-27-150438.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;交换机一般都具有多种速率的接口，例如10Mb/s、100Mb/s、1Gb/s甚至10Gb/s的接口，大部分接口支持多速率自适应。&lt;/li&gt;
&lt;li&gt;一般的交换机都采用“&lt;strong&gt;存储转发&lt;/strong&gt;”方式，为了减小交换机的转发时延，某些交换机采用了&lt;strong&gt;直通&lt;/strong&gt;（Cut-Through）交换方式。&lt;/li&gt;
&lt;li&gt;采用&lt;strong&gt;直通交换方式&lt;/strong&gt;的交换机，在接收帧的同时就立即按帧的目的MAC地址决定该帧的转发接口，然后通过其内部&lt;strong&gt;基于硬件的交叉矩阵&lt;/strong&gt;进行转发，而不必把整个帧先缓存后再进行处理。
&lt;ul&gt;
&lt;li&gt;直通交换的&lt;strong&gt;时延非常小&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;直通交换&lt;strong&gt;不检查差错就直接将帧转发出去&lt;/strong&gt;，有可能会将一些无效帧转发给其他主机。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-27-151448.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="352-对比共享式以太网与交换式以太网"&gt;3.5.2 对比共享式以太网与交换式以太网
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;交换机能识别帧的信息，因此信息传输通过交换机本身过滤，可以&lt;strong&gt;精准转发&lt;/strong&gt;。而集线器只工作在物理层，只能全部转发，然后由终端来过滤。对于广播帧也是同理。&lt;/li&gt;
&lt;li&gt;交换机的域中不会出现碰撞现象，交换机能自己&lt;strong&gt;存储转发&lt;/strong&gt;信息。&lt;/li&gt;
&lt;li&gt;通过集线器连接，既扩大了广播域也扩大了碰撞域。通过交换机连接，只扩大广播域而不扩大碰撞域，碰撞域仍保持独立。通过路由器连接，广播域和碰撞域都保持独立。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="36-以太网的mac帧格式"&gt;3.6 以太网的MAC帧格式
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-27-154609.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2 id="37-虚拟局域网-vlan"&gt;3.7 虚拟局域网 VLAN
&lt;/h2&gt;&lt;h3 id="371-虚拟局域网概述"&gt;3.7.1 虚拟局域网概述
&lt;/h3&gt;&lt;h4 id="背景"&gt;背景
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;将多个站点通过一个或多个&lt;strong&gt;以太网交换机&lt;/strong&gt;连接起来就构建出了&lt;strong&gt;交换式以太网&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;交换式以太网中的所有站点都属于&lt;strong&gt;同一个广播域&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;随着交换式以太网规模的扩大，广播域也相应扩大。&lt;strong&gt;巨大的广播域会带来一系列问题&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;广播风暴&lt;/strong&gt; &lt;strong&gt;广播风暴会浪费网络资源和各主机的CPU资源&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;难以管理和维护，带来潜在的安全问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;网络中会频繁出现广播信息
&lt;ul&gt;
&lt;li&gt;TCP/IP协议栈中的很多协议都会使用广播（例如地址解析协议ARP，路由信息协议RIPv1，动态主机配置协议DHCP）&lt;/li&gt;
&lt;li&gt;NetBEUI：Windows下使用的广播型协议&lt;/li&gt;
&lt;li&gt;IPX/SPX：Novell网络的协议栈&lt;/li&gt;
&lt;li&gt;Apple Talk：Apple公司的网络协议栈&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="概述-1"&gt;概述
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;虚拟局域网&lt;/strong&gt;（&lt;strong&gt;Virtual Local Area Network&lt;/strong&gt;，&lt;strong&gt;VLAN&lt;/strong&gt;）是一种将局域网内的站点划分成&lt;strong&gt;与物理位置无关的逻辑组&lt;/strong&gt;的技术，一个逻辑组就是一个VLAN，VLAN中的各站点具有某些共同的应用需求。&lt;/li&gt;
&lt;li&gt;属于同一VLAN的站点之间可以直接进行通信，而不同VLAN中的站点之间不能直接通信。&lt;/li&gt;
&lt;li&gt;网络管理员可对局域网中的各交换机进行配置来建立多个逻辑上独立的VLAN。
&lt;ul&gt;
&lt;li&gt;连接在同一交换机上的多个站点可以属于不同的VLAN，而属于同一VLAN的多个站点可以连接在不同的交换机上。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;虚拟局域网VLAN并不是一种新型网络，它只是局域网能够提供给用户的一种服务。&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="372-虚拟局域网实现机制"&gt;3.7.2 虚拟局域网实现机制
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;虚拟局域网VLAN&lt;/strong&gt;有多种实现技术，最常见的就是&lt;strong&gt;基于以太网交换机的接口来实现VLAN&lt;/strong&gt;。这就需要以太网交换机能够实现以下两个功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;能够处理带有VLAN标记的帧，也就是&lt;strong&gt;IEEE 802.1Q帧&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;交换机的各接口可以支持&lt;strong&gt;不同的接口类型&lt;/strong&gt;，不同接口类型的接口对帧的处理方式有所不同。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="ieee-8021q帧"&gt;IEEE 802.1Q帧
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;IEEE 802.1Q帧也称为Dot One Q帧，它对以太网V2的MAC帧格式进行了扩展：在源地址字段和类型字段之间插入了&lt;strong&gt;4字节的VLAN标签&lt;/strong&gt;（tag）字段。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-27-162829.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;标签协议标识符TPID&lt;/strong&gt;：长度为16比特，其值固定为0x8100，表示该帧是IEEE 802.1Q帧。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优先级PRI&lt;/strong&gt;：长度为3比特，取值范围是0~7，值越大优先级越高。当网络阻塞时，设备优先发送优先级高的802.1Q帧。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;规范格式指示符CFI&lt;/strong&gt;：长度为1比特，取值为0表示MAC地址以规范格式封装，取值为1表示MAC地址以非规范格式封装。对于以太网，CFI的取值为0。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;虚拟局域网标识符VID&lt;/strong&gt;：长度为12比特，取值范围是0~4095，其中0和4095保留不使用。
&lt;ul&gt;
&lt;li&gt;VID是&lt;strong&gt;802.1Q帧所属VLAN的编号&lt;/strong&gt;，设备利用VID来识别帧所属的VLAN。&lt;/li&gt;
&lt;li&gt;广播帧只在同一VLAN内转发，这样就把&lt;strong&gt;广播域限制在了一个VLAN内&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;802.1Q帧一般不由用户主机处理，而是由以太网交换机来处理：
&lt;ul&gt;
&lt;li&gt;当交换机&lt;strong&gt;收到普通的以太网MAC帧&lt;/strong&gt;时，会给其&lt;strong&gt;插入4字节的VLAN标签&lt;/strong&gt;使之成为802.1Q帧，该处理简称为“&lt;strong&gt;打标签&lt;/strong&gt;”。&lt;/li&gt;
&lt;li&gt;当交换机&lt;strong&gt;转发802.1Q帧&lt;/strong&gt;时，&lt;strong&gt;可能会删除其4字节的VLAN标签&lt;/strong&gt;使之成为普通的以太网MAC帧，该处理简称为“&lt;strong&gt;去标签&lt;/strong&gt;”。交换机转发802.1Q帧时也有可能不进行“去标签”处理，是否进行“去标签”处理取决于交换机的接口类型。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="交换机接口类型"&gt;交换机接口类型
&lt;/h4&gt;&lt;h5 id="access-接口"&gt;Access 接口
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;Access接口一般用于&lt;strong&gt;连接用户计算机&lt;/strong&gt;，由于其&lt;strong&gt;只能属于一个VLAN&lt;/strong&gt;，因此Access接口的&lt;strong&gt;PVID值与其所属VLAN的ID相同&lt;/strong&gt;，其默认值为1。&lt;/li&gt;
&lt;li&gt;接收处理
一般只接受“未打标签”的普通以太网MAC帧，根据接收帧的接口的PVID给帧“&lt;strong&gt;打标签&lt;/strong&gt;”，即插入4字节的VLAN标签字段，VLAN标签字段中的VID取值就是接口的PVID值。&lt;/li&gt;
&lt;li&gt;转发处理
若帧中的VID值与接口的PVID值相等，则给帧“&lt;strong&gt;去标签&lt;/strong&gt;”后再进行转发，否则不转发帧。因此，从Access接口转发出的帧，是不带VLAN标签的普通以太网MAC帧。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="truck-接口"&gt;Truck 接口
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;Trunk接口一般用于&lt;strong&gt;交换机之间的互连&lt;/strong&gt;。Trunk接口&lt;strong&gt;可以属于多个VLAN&lt;/strong&gt;，即Trunk接口&lt;strong&gt;可以通过属于不同VLAN的帧&lt;/strong&gt;。Trunk接口的默认PVID值为1，一般不建议用户修改，若互连的Trunk接口的PVID值不相等，则可能出现转发错误。&lt;/li&gt;
&lt;li&gt;接收处理
既&lt;strong&gt;可以接收“未打标签”的普通以太网MAC帧&lt;/strong&gt;，也可以接收“已打标签”的&lt;strong&gt;802.1Q帧&lt;/strong&gt;。若接收到普通以太网MAC帧时，根据接收帧的接口的PVID给帧“&lt;strong&gt;打标签&lt;/strong&gt;”，这与Access接口的处理相同。&lt;/li&gt;
&lt;li&gt;转发处理
对于帧的VID值等于接口的PVID值的802.1Q帧，将其“&lt;strong&gt;去标签&lt;/strong&gt;”&lt;strong&gt;转发&lt;/strong&gt;；对于帧的VID值不等于接口的PVID值802.1Q帧，将其&lt;strong&gt;直接转发&lt;/strong&gt;。因此，从Trunk接口转发出的帧，可能是普通以太网MAC帧，也可能是802.1Q帧。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="38-以太网的发展"&gt;3.8 以太网的发展
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-27-163837.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;都使用&lt;strong&gt;IEEE 802.3的帧格式&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;都遵守&lt;strong&gt;IEEE 802.3的最小帧长和最大帧长&lt;/strong&gt;的规定&lt;/li&gt;
&lt;li&gt;10吉比特以太网（10GE）和40/100吉比特以太网（40GE/100GE）只工作在全双工方式而不存在争用媒体的问题，因此&lt;strong&gt;不需要使用CSMA/CD协议&lt;/strong&gt;，这样传输距离就不再受碰撞检测的限制。&lt;/li&gt;
&lt;li&gt;都有&lt;strong&gt;多种不同的物理层标准&lt;/strong&gt;，10吉比特以太网（10GE）和40/100吉比特以太网（40GE/100GE）还增加了&lt;strong&gt;支持城域网和广域网的物理层标准&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="41-网络层概述"&gt;4.1 网络层概述
&lt;/h2&gt;&lt;h4 id="分组转发和路由选择"&gt;分组转发和路由选择
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;网络层的主要任务就是&lt;strong&gt;将分组从源主机经过多个网络和多段链路传输到目的主机&lt;/strong&gt;，可以将该任务划分为&lt;strong&gt;分组转发&lt;/strong&gt;和&lt;strong&gt;路由选择&lt;/strong&gt;两种重要的功能。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-27-170843.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="网络层向其上层提供的两种服务"&gt;网络层向其上层提供的两种服务
&lt;/h4&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;对比方面&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;虚电路服务&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;数据报服务&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;核心思想&lt;/td&gt;
					&lt;td&gt;可靠通信应当由网络自身来保证&lt;/td&gt;
					&lt;td&gt;可靠通信应当由用户主机来保证&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;连接&lt;/td&gt;
					&lt;td&gt;必须建立网络层连接&lt;/td&gt;
					&lt;td&gt;不需要建立网络层连接&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;目的地址&lt;/td&gt;
					&lt;td&gt;仅在连接建立阶段使用，之后每个分组使用短的虚电路号&lt;/td&gt;
					&lt;td&gt;每个分组都必须携带完整的目的地址&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;分组转发&lt;/td&gt;
					&lt;td&gt;属于同一条虚电路的分组均按同一路由进行转发&lt;/td&gt;
					&lt;td&gt;每个分组可走不同的路由&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;节点故障&lt;/td&gt;
					&lt;td&gt;所有通过出故障的节点的虚电路均不能工作&lt;/td&gt;
					&lt;td&gt;出故障的节点可能会丢失分组，一些路由可能会发生变化&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;分组顺序&lt;/td&gt;
					&lt;td&gt;总是按发送顺序到达目的主机&lt;/td&gt;
					&lt;td&gt;到达目的主机时不一定按发送顺序&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;服务质量&lt;/td&gt;
					&lt;td&gt;可以将通信资源提前分配给每一个虚电路，因此容易实现&lt;/td&gt;
					&lt;td&gt;很难实现&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="42-网际协议-ip"&gt;4.2 网际协议 IP
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;网际协议（Internet Protocol, IP）是TCP/IP体系结构&lt;strong&gt;网际层中的核心协议&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;网际协议IP、传输控制协议TCP、TCP/IP体系结构是由“因特网之父”Robert Kahn和Vint Cerf二人共同研发的，1974年5月发布了TCP/IP第一个版本。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="421-异构网络互连"&gt;4.2.1 异构网络互连
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;网络的拓扑、性能以及所使用的网络协议都&lt;strong&gt;不尽相同&lt;/strong&gt;，这是由用户需求的多样性造成的，没有一种单一的网络能够适应所有用户的需求。&lt;/p&gt;
&lt;p&gt;要将众多的异构型网络都互连起来，并且能够互相通信，则会面临许多需要解决的问题。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不同的网络接入机制&lt;/li&gt;
&lt;li&gt;不同的差错恢复方法&lt;/li&gt;
&lt;li&gt;不同的路由选择技术&lt;/li&gt;
&lt;li&gt;不同的寻址方案&lt;/li&gt;
&lt;li&gt;不同的最大分组长度&lt;/li&gt;
&lt;li&gt;不同的服务（面向连接服务和无连接服务）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当IP网上的主机进行通信时，就好像在一个单个网络上通信一样，它们看不见互连的各网络的具体异构细节。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;网络层都使用相同的IP协议，即所有接入互联网的设备都支持IP协议。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="422-ipv4地址及其编址方法"&gt;4.2.2 IPv4地址及其编址方法
&lt;/h3&gt;&lt;h4 id="概述-2"&gt;概述
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;IPv4地址是给因特网（Internet）上的&lt;strong&gt;每一个主机（或路由器）的每一个接口&lt;/strong&gt;分配的一个在全世界范围内&lt;strong&gt;唯一的32比特的标识符&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;IPv4地址由&lt;strong&gt;因特网名字和数字分配机构&lt;/strong&gt;（Internet Corporation for Assigned Names and Numbers, &lt;strong&gt;ICANN&lt;/strong&gt;）进行分配。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;我国用户可向&lt;strong&gt;亚太网络信息中心&lt;/strong&gt;（Asia Pacific Network Information Center, &lt;strong&gt;APNIC&lt;/strong&gt;）申请IP地址，需要缴纳相应的费用，一般不接受个人申请。&lt;/li&gt;
&lt;li&gt;2011年2月3日，因特网号码分配管理局（Internet Assigned Numbers Authority, IANA）（由ICANN行使职能）宣布，&lt;strong&gt;IPv4地址已经分配完毕&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;我国在2014至2015年也逐步停止了向新用户和应用分配IPv4地址，同时全面开展商用部署IPv6。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;IPv4地址的编址方法经历了三个历史阶段：&lt;strong&gt;分类编址&lt;/strong&gt;-&amp;gt;&lt;strong&gt;划分子网&lt;/strong&gt;-&amp;gt;&lt;strong&gt;无分类编址&lt;/strong&gt;，无分类编址消除了分类编址和划分子网的概念。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="表示方法"&gt;表示方法
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;由于IPv4地址由32比特构成，不方便阅读、记录以及输入等，因此IPv4地址采用&lt;strong&gt;点分十进制表示方法&lt;/strong&gt;以方便用户使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-28-095009.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="分类编址"&gt;分类编址
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;32比特的IPv4地址由网络号和主机号组成：&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;网络号&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;主机号&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;● 标志主机（或路由器）的接口所连接到的&lt;strong&gt;网络&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;● 标志主机（或路由器）的&lt;strong&gt;接口&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;● &lt;strong&gt;同一个网络&lt;/strong&gt;中，&lt;strong&gt;不同&lt;/strong&gt;主机（或路由器）的&lt;strong&gt;接口&lt;/strong&gt;的IPv4地址的&lt;strong&gt;网络号必须相同&lt;/strong&gt;，表示它们属于同一个网络。&lt;/td&gt;
					&lt;td&gt;● &lt;strong&gt;同一个网络&lt;/strong&gt;中，&lt;strong&gt;不同&lt;/strong&gt;主机（或路由器）的&lt;strong&gt;接口&lt;/strong&gt;的IPv4地址的&lt;strong&gt;主机号必须各不相同&lt;/strong&gt;，以便区分各主机（或路由器）的接口。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A类、B类和C类地址都是单播地址，只有单播地址可以分配给网络中的主机（或路由器）的各接口。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;主机号为“全0”的地址是网络地址，不能分配给主机（或路由器）的各接口。&lt;/p&gt;
&lt;p&gt;主机号为“全1”的地址是广播地址，不能分配给主机（或路由器）的各接口。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="各类地址详情"&gt;各类地址详情
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;A类网络数量的$-2$是因为要去掉最小网络号$0$表示&amp;quot;本网络&amp;quot;，最大网络号$127$作为本地环回测试地址。两者都不能指派。&lt;/li&gt;
&lt;li&gt;地址数量的$-2$是因为要去掉主机号全$0$的网络地址和全$1$的广播地址&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;网络类别&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;最小可指派网络号&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;最大可指派网络号&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;可指派网络数量&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;每个网络中最大可分配地址数量&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;不能指派的网络号&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;占总地址空间&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;A&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;126&lt;/td&gt;
					&lt;td&gt;126 ($2^{8-1}-2$)&lt;/td&gt;
					&lt;td&gt;16777214 ($2^{24}-2$)&lt;/td&gt;
					&lt;td&gt;0和127&lt;/td&gt;
					&lt;td&gt;50% ($2^{32-1}/2^{32}$)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;B&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;128.0&lt;/td&gt;
					&lt;td&gt;191.255&lt;/td&gt;
					&lt;td&gt;16384 ($2^{16-2}$)&lt;/td&gt;
					&lt;td&gt;65534 ($2^{16}-2$)&lt;/td&gt;
					&lt;td&gt;无&lt;/td&gt;
					&lt;td&gt;25% ($2^{32-2}/2^{32}$)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;C&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;192.0.0&lt;/td&gt;
					&lt;td&gt;223.255.255&lt;/td&gt;
					&lt;td&gt;2097152 ($2^{24}-3$)&lt;/td&gt;
					&lt;td&gt;254 ($2^{8}-2$)&lt;/td&gt;
					&lt;td&gt;无&lt;/td&gt;
					&lt;td&gt;12.5% ($2^{32-3}/2^{32}$)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;网络类别&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;作用&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;第一个地址&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;最后 一个地址&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;地址数量&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;占总地址空间&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;D&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;多播地址&lt;/td&gt;
					&lt;td&gt;224.0.0.0&lt;/td&gt;
					&lt;td&gt;239.255.255.255&lt;/td&gt;
					&lt;td&gt;268435456 ($2^{28}$)&lt;/td&gt;
					&lt;td&gt;6.25% ($2^{32-4}/2^{32}$)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;E&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;保留&lt;/td&gt;
					&lt;td&gt;240.0.0.0&lt;/td&gt;
					&lt;td&gt;255.255.255.255&lt;/td&gt;
					&lt;td&gt;268435456 ($2^{28}$)&lt;/td&gt;
					&lt;td&gt;6.25% ($2^{32-4}/2^{32}$)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-28-113743.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h5 id="一般不使用的特殊ipv4地址"&gt;一般不使用的特殊IPv4地址
&lt;/h5&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;网络号&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;主机号&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;IP地址&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;作为源地址&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;作为目的地址&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;表示的意思&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0.0.0.0&lt;/td&gt;
					&lt;td&gt;可以&lt;/td&gt;
					&lt;td&gt;不可以&lt;/td&gt;
					&lt;td&gt;在本网络上的本主机（例如，DHCP协议）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;host-id&lt;/td&gt;
					&lt;td&gt;0.host-id&lt;/td&gt;
					&lt;td&gt;可以&lt;/td&gt;
					&lt;td&gt;不可以&lt;/td&gt;
					&lt;td&gt;在本网络上的某台主机host-id&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;全1&lt;/td&gt;
					&lt;td&gt;全1&lt;/td&gt;
					&lt;td&gt;255.255.255.255&lt;/td&gt;
					&lt;td&gt;不可以&lt;/td&gt;
					&lt;td&gt;可以&lt;/td&gt;
					&lt;td&gt;只在本网络上进行广播（各路由器均不转发）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;net-id&lt;/td&gt;
					&lt;td&gt;全1&lt;/td&gt;
					&lt;td&gt;A类：net-id.255.255.255 B类：net-id.255.255 C类：net-id.255&lt;/td&gt;
					&lt;td&gt;不可以&lt;/td&gt;
					&lt;td&gt;可以&lt;/td&gt;
					&lt;td&gt;对网络net-id上的所有主机进行广播&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;127&lt;/td&gt;
					&lt;td&gt;非全0或全1的任何数&lt;/td&gt;
					&lt;td&gt;127.0.0.1~127.255.255.254&lt;/td&gt;
					&lt;td&gt;可以&lt;/td&gt;
					&lt;td&gt;可以&lt;/td&gt;
					&lt;td&gt;用于本地软件环回测试&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-28-113904.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-28-114131.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="划分子网"&gt;划分子网
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;随着更多的中小网络加入因特网，&lt;strong&gt;IPv4分类编址方法不够灵活、容易造成大量IPv4地址资源浪费&lt;/strong&gt;的缺点就暴露出来了。&lt;/p&gt;
&lt;p&gt;为新增网络申请新的网络号存在以下弊端：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;需要等待时间和花费更多的费用&lt;/li&gt;
&lt;li&gt;会增加其他路由器中路由条目的数量&lt;/li&gt;
&lt;li&gt;浪费原有网络号中剩余的大量地址&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="子网掩码"&gt;子网掩码
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;子网掩码&lt;/strong&gt;可以表明分类IPv4地址的主机号部分被借用了几个比特作为子网号。&lt;/p&gt;
&lt;p&gt;与IPv4地址类似，子网掩码也是由&lt;strong&gt;32比特构成&lt;/strong&gt;的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用左起多个&lt;strong&gt;连续的比特1&lt;/strong&gt;对应IPv4地址中的&lt;strong&gt;网络号和子网号&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;之后的多个&lt;strong&gt;连续的比特0&lt;/strong&gt;对应IPv4地址中的&lt;strong&gt;主机号&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;将划分子网的&lt;strong&gt;IPv4地址与相应的子网掩码进行逐比特的逻辑与运算&lt;/strong&gt;，就可得到该IPv4地址所在子网的&lt;strong&gt;网络地址&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;给定一个分类的IPv4地址和其相应的子网掩码，就可得出子网划分的细节：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;划分出的子网数量&lt;/li&gt;
&lt;li&gt;每个子网可分配的地址数量&lt;/li&gt;
&lt;li&gt;每个子网的网络地址和广播地址&lt;/li&gt;
&lt;li&gt;每个子网可分配的最小地址和最大地址&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;默认子网掩码&lt;/strong&gt;是指在未划分子网的情况下使用的子网掩码。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A类：255.0.0.0&lt;/li&gt;
&lt;li&gt;B类：255.255.0.0&lt;/li&gt;
&lt;li&gt;C类：255.255.255.0&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-28-144748.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-28-145204.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="无分类编址"&gt;无分类编址
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;无分类编址结构是包含&lt;strong&gt;网络前缀和主机号&lt;/strong&gt;的两级结构&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;网络前缀&lt;/strong&gt;是不定长的，仅从IPv4地址自身是无法确定其网络前缀和主机号的，需要配合使用32比特的地址掩码。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;无分类编址方法使用的&lt;strong&gt;地址掩码&lt;/strong&gt;与划分子网使用的&lt;strong&gt;子网掩码&lt;/strong&gt;类似，由32比特构成。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用左起多个&lt;strong&gt;连续的比持1&lt;/strong&gt;对应IPv4地址中的&lt;strong&gt;网络前缀&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;之后的多个&lt;strong&gt;连续的比特0&lt;/strong&gt;对应IPv4地址中的&lt;strong&gt;主机号&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;为了简便起见，可以不明确给出配套的地址掩码的点分十进制形式，而是在无分类编址的IPv4地址后面加上斜线“/”，在斜线之后写上网络前缀所占的比特数量（也就是地址掩码中左起连续比特1的数量），这种记法称为&lt;strong&gt;斜线记法&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;比如$128.14.35.7/20$ 代表网络前缀是20比特，主机号是12比特&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="cidr"&gt;CIDR
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;实际上，无分类域间路由选择CIDR是将网络前缀都相同的、连续的多个无分类IPv4地址，组成一个&lt;strong&gt;CIDR地址块&lt;/strong&gt;，只要知道CIDR地址块中的任何一个地址，就可以知道该地址块的以下全部细节：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;地址块中的&lt;strong&gt;最小地址&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;地址块中的&lt;strong&gt;最大地址&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;地址块中的&lt;strong&gt;地址数量&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;地址块中&lt;strong&gt;聚合某类网络&lt;/strong&gt;（A类、B类、C类）的数量&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;地址掩码&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用CIDR的一个好处是，可以根据客户的需要&lt;strong&gt;分配适当大小的CIDR地址块&lt;/strong&gt;，因此可以更加有效地分配IPv4的地址空间。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-28-155034.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="路由聚合"&gt;路由聚合
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;使用CIDR的另一个好处是&lt;strong&gt;路由聚合&lt;/strong&gt;（也称为&lt;strong&gt;构造超网&lt;/strong&gt;）。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-28-155253.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;网络前缀越长，地址块越小，路由越具体&lt;/strong&gt;；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;若路由器查表转发分组时发现有多条路由条目匹配，则选择网络前缀最长的那条路由条目，这称为&lt;strong&gt;最长前缀匹配&lt;/strong&gt;，因为这样的路由更具体。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-28-152545.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-28-155422.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;【2021年 题35】现将一个IP网络划分为3个子网，若其中一个子网是192.168.9.128/26，则下列网络中。不可能是另外两个子网之一的是( )
A. 192.168.9.0/25
B. 192.168.9.0/26
C. 192.168.9.192/26
D. 192.168.9.192/27&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;题干子网的192.168.9.128/26，即主机号用6位来表示，代表地址范围为192.168.9.128~192.168.9.192。&lt;/p&gt;
&lt;p&gt;A选项的192.168.9.0/25代表地址范围为192.168.9.0&lt;del&gt;192.168.9.128，然后和C选项的192.168.9.192/26代表的192.168.9.192&lt;/del&gt;192.168.9.255，加上题干，这三者可以聚合成地址块192.168.9.0/24。&lt;/p&gt;
&lt;p&gt;D选项的192.168.9.192/27代表地址范围为192.168.9.192~192.168.9.223，加上题干，再结合一个192.168.9.224/27，这三者就可聚合成地址块192.168.9.128/25。&lt;/p&gt;
&lt;p&gt;那么按照同样的逻辑，选项B的CIDR和题干结合，可见中间缺少64个地址，但是这三者合成是192.168.9.0~192.168.9.191，这&lt;strong&gt;聚合不成一个完整的网络&lt;/strong&gt;，需要再引入第四个CIDR，和题干要求的三个不符，故答案是B。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="423-ipv4地址的应用规划"&gt;4.2.3 IPv4地址的应用规划
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;IPv4地址的应用规划是指将给定的IPv4地址块（或分类网络）划分成若干个更小的地址块（或子网），并将这些地址块（或子网）分配给互联网中的不同网络，进而可以给各网络中的主机和路由器的接口分配IPv4地址。&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;定长的子网掩码 (Fixed Length Subnet Mask, FLSM)&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;变长的子网掩码 (Variable Length Subnet Mask, VLSM)&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;● 所划分出的每一个子网都&lt;strong&gt;使用同一个子网掩码&lt;/strong&gt;。&lt;/td&gt;
					&lt;td&gt;● 所划分出的每一个子网&lt;strong&gt;可以使用不同的子网掩码&lt;/strong&gt;。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;● 子网划分方式&lt;strong&gt;不灵活&lt;/strong&gt;：只能划分出 $2^n$ 个子网（n是从主机号借用的、用来作为子网号的比特数量）。&lt;/td&gt;
					&lt;td&gt;● 子网划分方式&lt;strong&gt;灵活&lt;/strong&gt;：可以按需分配。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;● 每个子网所分配的IP地址数量相同，容易造成&lt;strong&gt;地址资源的浪费&lt;/strong&gt;。&lt;/td&gt;
					&lt;td&gt;● 每个子网所分配的IP地址数量可以不同，&lt;strong&gt;尽可能减少对地址资源的浪费&lt;/strong&gt;。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id="使用定长子网掩码划分子网"&gt;使用定长子网掩码划分子网
&lt;/h4&gt;&lt;p&gt;【举例】假设申请到的C类网络为218.75.230.0，使用定长的子网掩码给下图所示的小型互联网中的各设备分配IPv4地址。&lt;/p&gt;
&lt;p&gt;应用需求：网络1需要IP地址数量为9，网络2需要IP地址数量为28，网络3需要IP地址数量为15，网络4需要IP地址数量为13，网络5需要IP地址数量为4。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;ul&gt;
&lt;li&gt;
&lt;p&gt;申请到的C类网络地址 &lt;strong&gt;218.75.230&lt;/strong&gt; . &lt;strong&gt;0&lt;/strong&gt; 从主机号借用&lt;strong&gt;3比特&lt;/strong&gt;作为子网号
子网数量：$2^3 = 8$（满足应用需求）
每个子网上的地址数量：$2^{8-3} = 32$（满足应用需求）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;子网掩码 &lt;strong&gt;255.255.255 . 224&lt;/strong&gt; （下图的子网掩码是错误的）
24个连续的比特1对应网络号&lt;br&gt;
&lt;strong&gt;3个连续的比特1表示从主机号借用3个比特作为子网号&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-02-28-172549.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="使用变长子网掩码划分子网"&gt;使用变长子网掩码划分子网
&lt;/h4&gt;&lt;p&gt;【举例】假设申请到的C类网络为218.75.230.0/24，使用变长的子网掩码给下图所示的小型互联网中的各设备分配IPv4地址。&lt;/p&gt;
&lt;p&gt;应用需求：从地址块218.75.230.0/24中取出5个地址块：/30, /28, /28, /28, /27, 按需分配给图中的5个网络。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;在地址块中选取子块的原则&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;每个子块的起点位置不能随便选取，只能选取主机号部分是块大小整数倍的地址作为起点。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;建议先为大的子块选取。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-09-093223.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-09-093533.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="424-ipv4地址与mac地址"&gt;4.2.4 IPv4地址与MAC地址
&lt;/h3&gt;&lt;h4 id="ipv4地址与mac地址的封装位置"&gt;IPv4地址与MAC地址的封装位置
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-09-093821.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="数据报传送过程中ipv4地址与mac地址的变化情况"&gt;数据报传送过程中IPv4地址与MAC地址的变化情况
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;在数据包的传送过程中，数据包的源IP地址和目的IP地址保持不变。&lt;/li&gt;
&lt;li&gt;在数据包的传送过程中，数据包的源MAC地址和目的MAC地址逐链路（或网络）改变。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-09-093841.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="ipv4地址与mac地址的关系"&gt;IPv4地址与MAC地址的关系
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;如果仅使用MAC地址进行通信，则会出现以下主要问题：
&lt;ul&gt;
&lt;li&gt;因特网中的每台路由器的&lt;strong&gt;路由表&lt;/strong&gt;中就必须&lt;strong&gt;记录&lt;/strong&gt;因特网上&lt;strong&gt;所有主机和路由器各接口的MAC地址&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;手工给各路由器配置路由表几乎是不可能完成的任务，即使使用路由协议让路由器通过相互交换路由信息来自动构建路由表，也会因为&lt;strong&gt;路由信息需要包含海量的MAC地址信息而严重占用通信资源&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;包含海量MAC地址的路由信息需要路由器具备极大的存储空间&lt;/strong&gt;，并且会给分组的&lt;strong&gt;查表转发带来非常大的时延&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;因特网的网际层&lt;strong&gt;使用IP地址进行寻址&lt;/strong&gt;，就可使因特网中各&lt;strong&gt;路由器&lt;/strong&gt;的路由表中的路由记录的数量大大减少，因为&lt;strong&gt;只需记录部分网络的网络地址&lt;/strong&gt;，而不是记录每个网络中各通信设备的各接口的MAC地址。
&lt;ul&gt;
&lt;li&gt;路由器收到IP数据报后，根据其首部中的目的IP地址的网络号部分，基于自己的路由表进行查表转发。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;查表转发的结果可以指明IP数据报的下一跳路由器的IP地址，但无法指明该IP地址所对应的MAC地址。因此，在数据链路层封装该IP数据报成为帧时，帧首部中的目的MAC地址字段就无法填写，该问题需要使用网际层中的&lt;strong&gt;地址解析协议ARP&lt;/strong&gt;来解决。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="425-地址解析协议arp"&gt;4.2.5 地址解析协议ARP
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;IP地址要经地址解析协议ARP转化成MAC地址&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;例如有一个由A, B, C三台主机通过交换机组成的网络，A要向B发送一个分组&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A知道B的IP地址，但不知道B的MAC地址，即主机A的&lt;strong&gt;ARP高速缓存表&lt;/strong&gt;没有记录，那么A的数据链路层封装MAC帧时，无法填写目的MAC地址。&lt;/li&gt;
&lt;li&gt;主机A发送&lt;strong&gt;ARP请求报文&lt;/strong&gt;，目的地址是广播地址，内容有主机B的IP地址。交换机通过所有端口将请求报文转发出去。主机收到该广播帧后，交付上层处理。&lt;/li&gt;
&lt;li&gt;主机B再发送&lt;strong&gt;ARP响应报文&lt;/strong&gt;，是&lt;strong&gt;单播报文&lt;/strong&gt;，目的MAC地址为主机A的MAC地址，内容记录了主机B的MAC地址。主机A收到后，将其IP地址和MAC地址对应填到ARP高速缓存表中。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;转发表中的MAC地址与交换机接口号的对应关系记录也要周期性删除，因为这种对应关系并不是永久不变的。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-09-102041.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ARP 协议的相关注意事项：
&lt;ul&gt;
&lt;li&gt;由于 ARP 协议的主要用途是从网际层使用的 IP 地址解析出在数据链路层使用的 MAC 地址。因此，有的教材将 ARP 协议划归在 &lt;strong&gt;网际层&lt;/strong&gt;，而有的教材将 ARP 协议划归在 &lt;strong&gt;数据链路层&lt;/strong&gt;。这两种做法都是可以的。&lt;/li&gt;
&lt;li&gt;除了本节课介绍的 ARP 请求报文和响应报文，&lt;strong&gt;ARP 协议还有其他类型的报文&lt;/strong&gt;，例如用于检查 IP 地址冲突的 “无故 ARP”（Gratuitous ARP）。&lt;/li&gt;
&lt;li&gt;由于 ARP 协议很早就制定出来了（1982 年 11 月），当时并没有考虑网络安全问题。因此，ARP 协议没有安全验证机制，存在 &lt;strong&gt;ARP 欺骗和攻击&lt;/strong&gt; 等问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="426-ip数据报的发送和转发过程"&gt;4.2.6 IP数据报的发送和转发过程
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;主机发送IP数据报
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;判断目的主机是否与自己在同一个网络&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;若在&lt;strong&gt;同一个网络&lt;/strong&gt;，则属于&lt;strong&gt;直接交付&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;若&lt;strong&gt;不在同一个网络&lt;/strong&gt;，则属于&lt;strong&gt;间接交付&lt;/strong&gt;。发送给主机所在网络的&lt;strong&gt;默认网关&lt;/strong&gt;（路由器），由默认网关帮忙转发。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;路由器转发IP数据报&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;基于&lt;strong&gt;IP数据报首部中的目的IP地址&lt;/strong&gt;在路由表中进行查询&lt;/li&gt;
&lt;li&gt;若找到匹配的路由条目，则按该路由条目的指示进行转发；&lt;/li&gt;
&lt;li&gt;否则丢弃该IP数据报，并向发送该IP数据报的源主机发送差错报告。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-09-104601.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="427-ipv4数据报的首部格式"&gt;4.2.7 IPv4数据报的首部格式
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-09-112701.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="首部长度"&gt;首部长度
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;长度为4个比特，该字段的取值&lt;strong&gt;以4字节为单位&lt;/strong&gt;，用来表示IPv4数据报的首部长度。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;最小取值为二进制的0101，即十进制的5，再乘以4字节单位，表示IPv4数据报首部只有20字节固定部分。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;最大取值为二进制的1111，即十进制的15，再乘以4字节单位，表示IPv4数据报首部包含&lt;strong&gt;20字节固定部分和最大40字节可变部分&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;【举例】IPv4数据报首部中的&lt;strong&gt;首部长度字段和总长度字段&lt;/strong&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;___________________________________________________
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;|&lt;/span&gt; IPv4首部（20字节） &lt;span class="p"&gt;|&lt;/span&gt; IPv4数据报的数据载荷（1000字节） &lt;span class="p"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;___________________________________________________
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;总长度：1020字节
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
 &lt;blockquote&gt;
 &lt;ul&gt;
&lt;li&gt;&lt;strong&gt;首部长度字段&lt;/strong&gt;的取值 = $(0101)_2$，以4字节为单位&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;总长度字段&lt;/strong&gt;的取值 = $(0000\ 0011\ 1111\ 1100)_2$，以字节为单位&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;首部长度&lt;/strong&gt; = $(0101)_2 \times 4 = 5 \times 4 =$ 20（字节）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;总长度&lt;/strong&gt; = $(0000\ 0011\ 1111\ 1100)_2 =$ 1020（字节）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据载荷长度&lt;/strong&gt; = 总长度 - 首部长度 = 1020 - 20 = 1000（字节）&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;h4 id="填充"&gt;填充
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;当首部长度（20字节固定部分+可变部分）的长度&lt;strong&gt;不是4字节整数倍&lt;/strong&gt;时，填充相应数量的&lt;strong&gt;全0字节&lt;/strong&gt;，以确保IPv4数据报的首部长度是4字节的整数倍。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="分片"&gt;分片
&lt;/h4&gt;&lt;p&gt;【举例】某个IPv4数据报总长度为3820字节，采用20字节固定首部，根据数据链路层要求，需要将该IPv4数据报分片为长度不超过1420字节的数据报片。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-09-113819.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;总长度&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;标识&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;MF&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;DF&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;片偏移&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;原IPv4数据报&lt;/td&gt;
					&lt;td&gt;20+3800&lt;/td&gt;
					&lt;td&gt;23333&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0 / 8 = 0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;分片数据报1&lt;/td&gt;
					&lt;td&gt;20+1400&lt;/td&gt;
					&lt;td&gt;23333&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0 / 8 = 0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;分片数据报2&lt;/td&gt;
					&lt;td&gt;20+1400&lt;/td&gt;
					&lt;td&gt;23333&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1400 / 8 = 175&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;分片数据报3&lt;/td&gt;
					&lt;td&gt;20+1000&lt;/td&gt;
					&lt;td&gt;23333&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;2800 / 8 = 350&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;【2021年 题36】若路由器向MTU=800B的链路转发一个总长度为1580B的IP数据报（首部长度为20B）时，进行了分片，且每个分片尽可能大，则第2个分片的总长度字段和MF标志位的值分别是（ B ）。&lt;/p&gt;
&lt;p&gt;A. 796，0&lt;/p&gt;
&lt;p&gt;B. 796，1&lt;/p&gt;
&lt;p&gt;C. 800，0&lt;/p&gt;
&lt;p&gt;D. 800，1&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;先尝试以800字节作为一个分片：首部20B，数据载荷780B，第二个分片的片偏移为$780 \div 8=97.5$ 但是片偏移必须是整数。&lt;/p&gt;
&lt;p&gt;数据载荷长度就应取小于800且能整除8的最大数，为776，那么第二个分片的总长度就为$20+776=796$。&lt;/p&gt;
&lt;p&gt;但是这两个数据载荷的容量不够，还有第三个分片，MF标志应该为1。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h5 id="标识"&gt;标识
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;长度为16个比特，属于同一个IPv4数据报的&lt;strong&gt;各分片数据报应该具有相同的标识&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;IP软件会维持一个计数器，每产生一个IPv4数据报，计数器值就加1，并将此值赋给标识字段。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="标志"&gt;标志
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;最低位（More Fragment, &lt;strong&gt;MF&lt;/strong&gt;）
&lt;ul&gt;
&lt;li&gt;MF=1表示本分片&lt;strong&gt;后面还有分片&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;MF=0表示本分片&lt;strong&gt;后面没有分片&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;中间位（Don’t Fragment, &lt;strong&gt;DF&lt;/strong&gt;）
&lt;ul&gt;
&lt;li&gt;DF=1表示&lt;strong&gt;不允许分片&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;DF=0表示&lt;strong&gt;允许分片&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;最高位为保留位，必须设置为0&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="片偏移"&gt;片偏移
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;长度为13个比特，该字段的取值&lt;strong&gt;以8字节为单位&lt;/strong&gt;，用来指出分片IPv4数据报的&lt;strong&gt;数据载荷偏移其在原IPv4数据报的位置有多远&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="生存时间"&gt;生存时间
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;长度为8个比特，最大取值为二进制的$11111111$，即十进制的255。该字段的取值最初以秒为单位。因此，IPv4数据报的最大生存时间最初为255秒。路由器转发IPv4数据报时，将其首部中该字段的值减去该数据报在路由器上所耗费的时间，若结果不为0就转发，否则就丢弃。&lt;/li&gt;
&lt;li&gt;生存时间字段后来改为以“&lt;strong&gt;跳数&lt;/strong&gt;”为单位，&lt;strong&gt;路由器收到待转发的IPv4数据报时，将其首部中的该字段的值减1，若结果不为0就转发，否则就丢弃&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;【举例】生存时间TTL字段的作用 —— &lt;strong&gt;防止被错误路由的IPv4数据报无限制地在因特网中兜圈&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-09-115555.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="协议"&gt;协议
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;长度为8个比特，用来指明IPv4数据报的数据载荷是何种协议数据单元PDU。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;常用的一些协议和相应的协议字段值&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;协议名称&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;ICMP&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;IGMP&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;TCP&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;UDP&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;IPv6&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;OSPF&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;协议字段值&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;6&lt;/td&gt;
					&lt;td&gt;17&lt;/td&gt;
					&lt;td&gt;41&lt;/td&gt;
					&lt;td&gt;89&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="首部检验和"&gt;首部检验和
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;长度为16个比特，用于检测IPv4数据报在传输过程中其&lt;strong&gt;首部是否出现了差错&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;IPv4数据报每经过一个路由器，其首部中的某些字段的值（例如生存时间TTL、标志以及片偏移等）都可能发生变化，因此&lt;strong&gt;路由器都要重新计算一下首部检验和&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-09-133113.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;上述检验和的计算方法不仅用于IP协议，还用于运输层的用户数据报协议UDP和传输控制协议TCP，常被称为&lt;strong&gt;因特网检验和&lt;/strong&gt;（Internet Checksum）。这种检验和的检错性能虽然不如CRC，但更易用软件实现。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="ip地址"&gt;IP地址
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;源IP地址：长度为32个比特，用来填写发送IPv4数据报的源主机的IPv4地址。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;目的IP地址：长度为32个比特，用来填写接收IPv4数据报的目的主机的IPv4地址。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="43-静态路由配置"&gt;4.3 静态路由配置
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;静态路由配置是指用户或网络运维人员使用路由器的相关命令给路由器&lt;strong&gt;人工配置路由表&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;人工配置方式简单、开销小、但&lt;strong&gt;不能及时适应网络状态（流量、拓扑等）的变化&lt;/strong&gt;，一般只在小规模网络中采用。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;进行静态路由配置需要认真考虑和谨慎操作，否则可能出现以下问题：
&lt;ul&gt;
&lt;li&gt;路由条目&lt;strong&gt;配置错误&lt;/strong&gt;，甚至导致出现&lt;strong&gt;路由环路&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;聚合路由条目时可能&lt;strong&gt;引入不存在的网络&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="uploads/posts/computer-network/Screenshot-2026-03-12-103613.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;目的网络&lt;/th&gt;
					&lt;th&gt;下一跳&lt;/th&gt;
					&lt;th&gt;类型&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;0.0.0.0/0&lt;/td&gt;
					&lt;td&gt;10.0.0.2&lt;/td&gt;
					&lt;td&gt;静态&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在默认路由条目中，有目的网络 $0.0.0.0/0$ 其中 $0.0.0.0$ 表示任何网络，而网络前缀 $/0$ 是最短的网络前缀。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;路由器在查找转发表转发IP数据报时，遵循“最长前缀匹配”的原则，因此&lt;strong&gt;默认路由条目的匹配优先级最低&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;目的网络&lt;/th&gt;
					&lt;th&gt;下一跳&lt;/th&gt;
					&lt;th&gt;类型&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;192.168.2.0/24&lt;/td&gt;
					&lt;td&gt;10.0.0.2&lt;/td&gt;
					&lt;td&gt;静态&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;192.168.2.1/32&lt;/td&gt;
					&lt;td&gt;10.0.0.2&lt;/td&gt;
					&lt;td&gt;静态&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="44-因特网的路由选择协议"&gt;4.4 因特网的路由选择协议
&lt;/h2&gt;&lt;h3 id="441-路由选择分类"&gt;4.4.1 路由选择分类
&lt;/h3&gt;&lt;h4 id="静态路由选择"&gt;静态路由选择
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;采用&lt;strong&gt;人工配置&lt;/strong&gt;的方式给路由器添加网络路由、默认路由和特定主机路由等路由条目。&lt;/li&gt;
&lt;li&gt;静态路由选择简单、开销小，但&lt;strong&gt;不能及时适应网络状态（流量、拓扑等）的变化&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;静态路由选择一般只在&lt;strong&gt;小规模网络&lt;/strong&gt;中采用。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="动态路由选择"&gt;动态路由选择
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;路由器通过路由选择协议&lt;strong&gt;自动获取&lt;/strong&gt;路由信息。&lt;/li&gt;
&lt;li&gt;动态路由选择比较复杂、开销比较大，&lt;strong&gt;但能较好地适应网络状态的变化&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;动态路由选择适用于&lt;strong&gt;大规模网络&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="442-分层次的路由选择协议"&gt;4.4.2 分层次的路由选择协议
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;路由选择协议主要特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;自适应：因特网采用&lt;strong&gt;动态路由&lt;/strong&gt;选择，能较好地适应网络状态的变化&lt;/li&gt;
&lt;li&gt;分布式：因特网中的&lt;strong&gt;各路由器&lt;/strong&gt;通过相互间的信息交互，&lt;strong&gt;共同完成路由信息的获取和更新&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;分层次：将整个因特网划分为许多较小的&lt;strong&gt;自治系统&lt;/strong&gt;（Autonomous System，AS）。在自治系统内部和外部采用不同类别的路由选择协议，分别进行路由选择。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;自治系统内部是用内部网关协议IGP，连接自治系统的是外部网关协议EGP&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;外部网关协议EGP和内部网关协议IGP只是路由选择协议的分类名称，&lt;strong&gt;而不是具体的路由选择协议&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;外部网关协议和内部网关协议名称中使用的是“&lt;strong&gt;网关&lt;/strong&gt;”这个名词，是因为在因特网早期的RFC文档中，没有使用“路由器”而使用的是“网关”这一名词。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="443-路由信息协议rip"&gt;4.4.3 路由信息协议RIP
&lt;/h3&gt;&lt;h4 id="基本概念-1"&gt;基本概念
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;路由信息协议（Routing Information Protocol，RIP）是内部网关协议中最先得到广泛使用的协议之一，其相关标准文档为[RFC 1058]。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;RIP要求自治系统AS内的每一个路由器，都要维护从它自己到AS内其他每一个网络的距离记录。这是一组距离，称为&lt;strong&gt;距离向量&lt;/strong&gt;（Distance-Vector，D-V）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;RIP使用&lt;strong&gt;跳数&lt;/strong&gt;（Hop Count）作为度量（Metric）来衡量到达目的网络的&lt;strong&gt;距离&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RIP将路由器&lt;strong&gt;到直连网络&lt;/strong&gt;的&lt;strong&gt;距离定义为1&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;RIP将路由器&lt;strong&gt;到非直连网络&lt;/strong&gt;的&lt;strong&gt;距离定义为所经过的路由器数加1&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;RIP允许一条路径最多只能包含15个路由器，&lt;strong&gt;距离等于16时相当于不可达&lt;/strong&gt;。因此&lt;strong&gt;RIP只适用于小型互联网&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;RIP认为&lt;strong&gt;好的路由&lt;/strong&gt;就是“距离短”的路由，也就是所&lt;strong&gt;通过路由器数量最少的路由&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当到达同一目的网络有多条RIP距离相等的路由时，可以进行&lt;strong&gt;等价负载均衡&lt;/strong&gt;，也就是将通信量均衡地分布到多条等价的路径上。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;RIP具有以下三个重要特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;和谁交换信息：仅和&lt;strong&gt;相邻路由器&lt;/strong&gt;交换信息。&lt;/li&gt;
&lt;li&gt;交换什么信息：路由器自己的&lt;strong&gt;路由表&lt;/strong&gt;。
即本路由器到所在自治系统AS中各网络的最短RIP距离，以及到各网络应经过的下一跳路由器。&lt;/li&gt;
&lt;li&gt;何时交换信息：&lt;strong&gt;周期性交换&lt;/strong&gt;（例如，每个约30秒）。
为了加快RIP的收敛速度，当网络拓扑发生变化时，路由器要及时向相邻路由器通告拓扑变化后的路由信息，这称为触发更新。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="基本工作过程"&gt;基本工作过程
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;路由器刚开始工作时，&lt;strong&gt;只知道自己到直连网络的RIP距离为1&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;每个路由器&lt;strong&gt;仅和相邻路由器周期性地交换并更新路由信息&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;若干次交换和更新后，&lt;strong&gt;每个路由器都知道到达本自治系统AS内各网络的最短距离和下一跳路由器&lt;/strong&gt;，称为&lt;strong&gt;收敛&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="距离向量算法"&gt;距离向量算法
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;RIP路由条目更新规则&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;发现了新网络&lt;/strong&gt;，添加&lt;/li&gt;
&lt;li&gt;到达目的网络，&lt;strong&gt;相同下一跳，最新消息&lt;/strong&gt;，更新&lt;/li&gt;
&lt;li&gt;到达目的网络，&lt;strong&gt;不同下一跳，新路由优势&lt;/strong&gt;，更新&lt;/li&gt;
&lt;li&gt;到达目的网络，&lt;strong&gt;不同下一跳，新路由劣势&lt;/strong&gt;，不更新&lt;/li&gt;
&lt;li&gt;到达目的网络，&lt;strong&gt;不同下一跳，RIP距离相同&lt;/strong&gt;，等价负载均衡&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;除了上述RIP路由条目更新规则，在RIP的距离向量算法中还包含以下一些&lt;strong&gt;时间参数&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;路由器每隔&lt;strong&gt;大约30秒&lt;/strong&gt;向其所有相邻路由器发送路由更新报文。&lt;/li&gt;
&lt;li&gt;若&lt;strong&gt;180秒&lt;/strong&gt;（默认）没有收到某条路由条目的更新报文，则把该路由条目标记为无效（即把RIP距离设置为16，表示不可达），若再过一段时间（如120秒），还没有收到该路由条目的更新报文，则将该路由条目从路由表中删除。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;【2010年 题35】某自治系统内采用RIP协议，若该自治系统的路由器R1收到其邻居路由器R2的距离矢量，距离矢量中包含信息&amp;lt;net1,16&amp;gt;，则能得出的结论是（D）。&lt;/p&gt;
&lt;p&gt;A. R2可以经过R1到达net1，跳数为17&lt;/p&gt;
&lt;p&gt;B. R2可以达到net1，跳数为16&lt;/p&gt;
&lt;p&gt;C. R1可以经过R2到达net1，跳数为17&lt;/p&gt;
&lt;p&gt;D. R1不能经过R2到达net1&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;在RIP协议中，&lt;strong&gt;距离16表明目的网络不可达&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;因此，R2无法到达net1，R1也无法通过R2到达net1。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;【2021年 题37】某网络中的所有路由器均采用距离向量路由算法计算路由。若路由器E与邻居路由器A、B、C和D之间的直接链路距离分别是8，10，12和6，且E收到邻居路由器的距离向量如下表所示，则路由器E更新后的到达目的网络Net1~Net4的距离分别是（D）。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;目的网络&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;A的距离向量&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;B的距离向量&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;C的距离向量&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;D的距离向量&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Net1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;23&lt;/td&gt;
					&lt;td&gt;20&lt;/td&gt;
					&lt;td&gt;22&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Net2&lt;/td&gt;
					&lt;td&gt;12&lt;/td&gt;
					&lt;td&gt;35&lt;/td&gt;
					&lt;td&gt;30&lt;/td&gt;
					&lt;td&gt;28&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Net3&lt;/td&gt;
					&lt;td&gt;24&lt;/td&gt;
					&lt;td&gt;18&lt;/td&gt;
					&lt;td&gt;16&lt;/td&gt;
					&lt;td&gt;36&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Net4&lt;/td&gt;
					&lt;td&gt;36&lt;/td&gt;
					&lt;td&gt;30&lt;/td&gt;
					&lt;td&gt;8&lt;/td&gt;
					&lt;td&gt;24&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A. 9, 10, 12, 6
B. 9, 10, 28, 20
C. 9, 20, 12, 20
D. 9, 20, 28, 20&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;img src="uploads/posts/computer-network/Screenshot-2026-03-12-115749.png" alt="" loading="lazy" /&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="存在的问题"&gt;存在的问题
&lt;/h4&gt;&lt;p&gt;&lt;img src="uploads/posts/computer-network/Screenshot-2026-03-12-133816.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“坏消息传播得慢”的问题又被称为路由环路或&lt;strong&gt;RIP距离无穷计数问题&lt;/strong&gt;。这是距离向量算法的一个固有问题。可以采取以下多种措施&lt;strong&gt;减少&lt;/strong&gt;出现该问题的概率或减小该问题带来的危害：
&lt;ul&gt;
&lt;li&gt;限制&lt;strong&gt;最大RIP距离为15&lt;/strong&gt;（16表示不可达）。&lt;/li&gt;
&lt;li&gt;当路由表发生变化时就立即发送路由更新报文（即“&lt;strong&gt;触发更新&lt;/strong&gt;”），而不仅是周期性发送。&lt;/li&gt;
&lt;li&gt;让路由器记录收到某个特定路由信息的接口，而不让同一路由信息再通过此接口向反方向传送（即“&lt;strong&gt;水平分割&lt;/strong&gt;”）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;使用上述措施仍无法彻底解决问题。因为在距离向量算法中，每个路由器都缺少到目的网络整个路径的完整信息，无法判断所选的路由是否出现了环路。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="版本和相关报文的封装"&gt;版本和相关报文的封装
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;现在较新的RIP版本是1998年11月公布的&lt;strong&gt;RIP2&lt;/strong&gt;[RFC 2453]，已经成为因特网标准协议。与RIP1相比，RIP2可以支持&lt;strong&gt;变长子网掩码和CIDR&lt;/strong&gt;。另外，RIP2还提供&lt;strong&gt;简单的鉴别&lt;/strong&gt;过程并支持&lt;strong&gt;多播&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;RIP相关报文使用运输层的用户数据报协议UDP进行封装，使用的&lt;strong&gt;UDP端口号为520&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;从&lt;strong&gt;RIP报文封装&lt;/strong&gt;的角度看，RIP属于TCP/IP体系结构的&lt;strong&gt;应用层&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;但RIP的核心功能是&lt;strong&gt;路由选择&lt;/strong&gt;，这属于TCP/IP体系结构的&lt;strong&gt;网际层&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="rip的优缺点"&gt;RIP的优缺点
&lt;/h4&gt;&lt;h5 id="优点"&gt;优点
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;实现&lt;strong&gt;简单&lt;/strong&gt;，路由器开销小。&lt;/li&gt;
&lt;li&gt;如果一个路由器发现了RIP距离更短的路由，那么这种更新信息就传播得很快，即“&lt;strong&gt;好消息传播得快&lt;/strong&gt;”。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="缺点"&gt;缺点
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;RIP限制了&lt;strong&gt;最大RIP距离为15&lt;/strong&gt;，这就限制了使用RIP的自治系统AS的规模。&lt;/li&gt;
&lt;li&gt;相邻路由器之间交换的路由信息是路由器中的&lt;strong&gt;完整路由表&lt;/strong&gt;，因而随着网络规模的扩大，开销也随之增大。&lt;/li&gt;
&lt;li&gt;“&lt;strong&gt;坏消息传播得慢&lt;/strong&gt;”，使更新过程的收敛时间过长。因此，对于规模较大的自治系统AS，应当使用OSPF协议。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="444-开放最短路径优先ospf"&gt;4.4.4 开放最短路径优先OSPF
&lt;/h3&gt;&lt;h4 id="基本概念-2"&gt;基本概念
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;开放最短路径优先（Open Shortest Path First，&lt;strong&gt;OSPF&lt;/strong&gt;）协议是为了&lt;strong&gt;克服路由信息协议RIP的缺点&lt;/strong&gt;在1989年开发出来的。
&lt;ul&gt;
&lt;li&gt;“&lt;strong&gt;开放&lt;/strong&gt;”表明OSPF协议不是受某一厂商控制，而是&lt;strong&gt;公开发表&lt;/strong&gt;的。&lt;/li&gt;
&lt;li&gt;“&lt;strong&gt;最短路径优先&lt;/strong&gt;”是因为使用了Dijkstra提出的&lt;strong&gt;最短路径算法&lt;/strong&gt;（Shortest Path First，SPF）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;OSPF是基于链路状态的，而不像RIP是基于距离向量的。&lt;/li&gt;
&lt;li&gt;OSPF基于链路状态并采用最短路径算法计算路由，从算法上保证了不会产生路由环路。&lt;/li&gt;
&lt;li&gt;OSPF不限制网络规模，更新效率高，收敛速度快。&lt;/li&gt;
&lt;li&gt;链路状态（Link State，LS）是指本路由器都和哪些路由器相邻，以及相应链路的“代价（cost）”。
&lt;ul&gt;
&lt;li&gt;“代价”用来表示费用、距离、时延和带宽等，这些都由网络管理人员来决定。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="ospf路由器邻居关系的建立和维护"&gt;OSPF路由器邻居关系的建立和维护
&lt;/h5&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&amp;hellip;&lt;/th&gt;
					&lt;th&gt;目的IP地址&lt;/th&gt;
					&lt;th&gt;协议号&lt;/th&gt;
					&lt;th&gt;&amp;hellip;&lt;/th&gt;
					&lt;th&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;224.0.0.5&lt;/td&gt;
					&lt;td&gt;89&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;OSPF问候分组&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;OSPF相邻路由器之间通过交互&lt;strong&gt;问候（Hello）分组&lt;/strong&gt;来建立和维护&lt;strong&gt;邻居关系&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;问候（Hello）分组封装在&lt;strong&gt;IP数据报&lt;/strong&gt;中，发往&lt;strong&gt;组播地址224.0.0.5&lt;/strong&gt;。IP数据报首部中的&lt;strong&gt;协议号&lt;/strong&gt;字段的取值为&lt;strong&gt;89&lt;/strong&gt;，表明IP数据报的数据载荷为OSPF分组。&lt;/li&gt;
&lt;li&gt;问候（Hello）分组的&lt;strong&gt;发送周期为10秒&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;若&lt;strong&gt;40秒&lt;/strong&gt;未收到来自邻居路由器的问候（Hello）分组，则认为邻居路由器不可达。&lt;/li&gt;
&lt;li&gt;每个路由器都会建立一张&lt;strong&gt;邻居表&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="链路状态"&gt;链路状态
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;使用OSPF的每个路由器都会产生&lt;strong&gt;链路状态通告&lt;/strong&gt;（Link State Advertisement，&lt;strong&gt;LSA&lt;/strong&gt;）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LSA中包含以下两类链路状态信息：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;直连网络&lt;/strong&gt;的链路状态信息&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;邻居路由器&lt;/strong&gt;的链路状态信息&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;链路状态通告LSA被封装在&lt;strong&gt;链路状态更新&lt;/strong&gt;（Link State Update, &lt;strong&gt;LSU&lt;/strong&gt;）分组中，采用&lt;strong&gt;可靠的洪泛法&lt;/strong&gt;（Flooding）进行发送。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;洪泛法的要点是路由器&lt;strong&gt;向自己所有的邻居路由器发送链路状态更新分组&lt;/strong&gt;，收到该分组的各路由器又将该分组转发给自己所有的邻居路由器（但其上游路由器除外），以此类推。&lt;/li&gt;
&lt;li&gt;可靠是指收到链路状态更新分组后要发送确认，&lt;strong&gt;收到重复的更新分组无需再次转发&lt;/strong&gt;，但要发送一次确认。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用OSPF的每一个路由器都有一个&lt;strong&gt;链路状态数据库&lt;/strong&gt;（Link State Database, &lt;strong&gt;LSDB&lt;/strong&gt;），用于&lt;strong&gt;存储链路状态通告LSA&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;通过各路由器洪泛发送封装有各自链路状态通告LSA的链路状态更新分组LSU，各路由器的链路状态数据库LSDB最终将达到一致。&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="基于链路状态数据库进行最短路径优先计算"&gt;基于链路状态数据库进行最短路径优先计算
&lt;/h5&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-12-144642.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="ospf分组类型"&gt;OSPF分组类型
&lt;/h4&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;分组类型&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;功能描述&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;问候 (Hello)&lt;/td&gt;
					&lt;td&gt;用来发现和维护邻居路由器的可达性。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;数据库描述 (Database Description)&lt;/td&gt;
					&lt;td&gt;用来向邻居路由器给出自己的链路状态数据库中的所有链路状态项目的摘要信息。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;链路状态请求 (Link State Request)&lt;/td&gt;
					&lt;td&gt;用来向邻居路由器请求发送某些链路状态项目的详细信息。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;链路状态更新 (Link State Update)&lt;/td&gt;
					&lt;td&gt;路由器使用链路状态更新分组将其链路状态信息进行洪泛发送，即用洪泛法对整个系统更新链路状态。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;链路状态确认 (Link State Acknowledgement)&lt;/td&gt;
					&lt;td&gt;对链路状态更新分组的确认分组。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id="ospf基本工作过程"&gt;OSPF基本工作过程
&lt;/h4&gt;&lt;p&gt;&lt;img src="uploads/posts/computer-network/Screenshot-2026-03-12-144901.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="多点接入网络中的ospf路由器"&gt;多点接入网络中的OSPF路由器
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;为了&lt;strong&gt;减少洪泛发送问候分组和链路状态更新分组的数量&lt;/strong&gt;，OSPF采用以下措施：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;选举&lt;strong&gt;指定路由器&lt;/strong&gt;（Designated Router，DR）和&lt;strong&gt;备用的指定路由器&lt;/strong&gt;（Backup Designated Router，BDR）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;所有的非DR/BDR只与DR/BDR建立邻居关系&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;非DR/BDR之间通过DR/BDR交换信息&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果不引入DR/BDR，也就是所有路由器两两建立关系，总连接数为：
&lt;/p&gt;
$$
 Total = \frac{n(n-1)}{w}
 $$&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;引入DR/BDR后，有 &lt;strong&gt;DRothers&lt;/strong&gt;（非 DR/BDR 路由器）不再两两建立邻接关系，而是仅与 DR 和 BDR 建立关系&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DRothers 与 DR 建立关系&lt;/strong&gt;：除了 DR 自身，剩下的 $n-1$ 台路由器（包括 BDR）都要与 DR 建立关系：连接数：$n-1$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DRothers 与 BDR 建立关系&lt;/strong&gt;：除了 BDR 自身和已经与它有连接的 DR，剩下的 $n-2$ 台 DRothers 需要与 BDR 建立关系：连接数：$n-2$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DR 与 BDR 建立关系&lt;/strong&gt;：它们之间必须同步：连接数：$1$&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="ospf划分区域"&gt;OSPF划分区域
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;采用划分区域的方法，虽然使交换信息的种类增多了，同时也使OSPF协议更加复杂了，但这样做能使每一个区域内部交换路由信息的通信量大大减小，因而使OSPF协议能够用于规模更大的自治系统AS。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-12-150725.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="445-边界网关协议bgp"&gt;4.4.5 边界网关协议BGP
&lt;/h3&gt;&lt;h4 id="基本概念-3"&gt;基本概念
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;边界网关协议（Border Gateway Protocol, &lt;strong&gt;BGP&lt;/strong&gt;）属于外部网关协议EGP这个类别，用于&lt;strong&gt;自治系统AS之间的路由选择协议&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;由于在不同AS内度量路由的“代价”（距离、带宽、费用等）可能不同，因此&lt;strong&gt;对于AS之间的路由选择，使用统一的“代价”作为度量来寻找最佳路由是不行的&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;AS之间的路由选择还必须考虑相关&lt;strong&gt;策略&lt;/strong&gt;，这些策略包括政治、经济、安全等，它们都是由网络管理员对每一个路由器进行设置的。但这些策略并不是自治系统之间的路由选择协议本身。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BGP只能是力求寻找一条能够到达目的网络且比较好的路由（即不能兜圈子），而并非要寻找一条最佳路由&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-12-152501.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在配置BGP时，每个AS的管理员要选择至少一个路由器作为该AS的“&lt;strong&gt;BGP发言人&lt;/strong&gt;”。&lt;/li&gt;
&lt;li&gt;一般来说，两个BGP发言人都是通过一个共享网络连接在一起的，而BGP发言人往往就是&lt;strong&gt;BGP边界路由器&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;使用TCP连接交换路由信息的两个BGP发言人，彼此称为对方的&lt;strong&gt;邻站&lt;/strong&gt;（neighbor）或&lt;strong&gt;对等站&lt;/strong&gt;（peer）。&lt;/li&gt;
&lt;li&gt;BGP发言人除了运行BGP协议外，还必须运行自己所在AS所使用的内部网关协议IGP，例如RIP或OSPF。&lt;/li&gt;
&lt;li&gt;BGP发言人交换网络可达性的信息，&lt;strong&gt;也就是要到达某个网络所要经过的一系列自治系统&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;当BGP发言人相互交换了网络可达性的信息后，各BGP发言人就&lt;strong&gt;根据&lt;/strong&gt;所采用的&lt;strong&gt;策略&lt;/strong&gt;，从收到的路由信息中找出到达各自治系统的较好的路由，也就是构造出树形结构且&lt;strong&gt;不存在环路的自治系统连通图&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;BGP适用于多级结构的因特网。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="bgp-4的四种报文"&gt;BGP-4的四种报文
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;BGP-4是目前使用得最多的版本，在[RFC 4271]中规定了BGP-4的四种报文：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;报文类型&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;功能描述&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;打开 OPEN&lt;/td&gt;
					&lt;td&gt;用来与相邻的另一个BGP发言人建立关系，使通信初始化。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;保活 KEEPALIVE&lt;/td&gt;
					&lt;td&gt;用来周期性地证实邻站的连通性。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;更新 UPDATE&lt;/td&gt;
					&lt;td&gt;用来通告某一条路由的信息，以及列出要撤销的多条路由。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;通知 NOTIFICATION&lt;/td&gt;
					&lt;td&gt;用来发送检测到的差错。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;【2017年 题37】直接封装RIP、OSPF、BGP报文的协议分别是（D）。&lt;/p&gt;
&lt;p&gt;A. TCP、UDP、IP B. TCP、IP、UDP C. UDP、TCP、IP D. UDP、IP、TCP&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-12-153301.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;从实现功能（路由选择）的角度看，这三个路由选择协议都属于网络层。&lt;/p&gt;
&lt;p&gt;从数据包按网络体系结构逐层封装的角度看，RIP和BGP属于应用层，OSPF属于网络层。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="446-路由器的基本工作原理"&gt;4.4.6 路由器的基本工作原理
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;路由器&lt;/strong&gt;被定义为一种具有多个输入/输出端口的&lt;strong&gt;专用计算机&lt;/strong&gt;，其核心任务是&lt;strong&gt;转发分组&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;路由选择部分&lt;/strong&gt;：核心构件是&lt;strong&gt;路由选择处理机&lt;/strong&gt;，其任务是根据所使用的&lt;strong&gt;路由选择协议&lt;/strong&gt;，周期性地与其他路由器进行信息的交换，以便构建和更新路由表。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分组转发部分&lt;/strong&gt;：由一组输入端口、交换结构以及一组输出端口。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-12-155825.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2 id="45-网际控制报文协议icmp"&gt;4.5 网际控制报文协议ICMP
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;为了更有效地转发&lt;strong&gt;IP数据报&lt;/strong&gt;以及提高&lt;strong&gt;IP数据报&lt;/strong&gt;交付成功的机会，TCP/IP体系结构的&lt;strong&gt;网际层&lt;/strong&gt;使用了&lt;strong&gt;网际控制报文协议&lt;/strong&gt; (&lt;strong&gt;I&lt;/strong&gt;nternet &lt;strong&gt;C&lt;/strong&gt;ontrol &lt;strong&gt;M&lt;/strong&gt;essage &lt;strong&gt;P&lt;/strong&gt;rotocol, &lt;strong&gt;ICMP&lt;/strong&gt;) [RFC 792]。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;主机或路由器&lt;/strong&gt;使用ICMP来发送&lt;strong&gt;差错报告报文&lt;/strong&gt;和&lt;strong&gt;询问报文&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ICMP报文被封装在IP数据报中发送&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;以下情况不应发送ICMP差错报告报文：&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;对ICMP差错报告报文不再发送ICMP差错报告报文。&lt;/li&gt;
&lt;li&gt;对第一个分片的IP数据报片的所有后续数据报片都不发送ICMP差错报告报文。&lt;/li&gt;
&lt;li&gt;对具有多播地址的IP数据报都不发送ICMP差错报告报文。&lt;/li&gt;
&lt;li&gt;对具有特殊地址（例如127.0.0.0或0.0.0.0）的IP数据报不发送ICMP差错报告&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ICMP的典型应用&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;分组网间探测PING&lt;/li&gt;
&lt;li&gt;跟踪路由traceroute&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="icmp报文类型"&gt;ICMP报文类型
&lt;/h4&gt;&lt;h5 id="差错报告报文"&gt;差错报告报文
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;终点不可达&lt;/strong&gt;：当&lt;strong&gt;路由器或主机不能交付IP数据报&lt;/strong&gt;时，就向源点发送终点不可达报文。&lt;/p&gt;
&lt;p&gt;&lt;img src="uploads/posts/computer-network/Screenshot-2026-03-13-144937.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;源点抑制&lt;/strong&gt;：&lt;strong&gt;当路由器或主机由于拥塞而丢弃IP数据报时，就向源点发送源点抑制报文&lt;/strong&gt;，使源点知道应当把IP数据报的发送速率放慢&lt;/p&gt;
&lt;p&gt;&lt;img src="uploads/posts/computer-network/Screenshot-2026-03-13-145109.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;时间超过（&lt;strong&gt;超时&lt;/strong&gt;）：当路由器收到&lt;strong&gt;TTL=1的IP数据报&lt;/strong&gt;时，将其&lt;strong&gt;丢弃&lt;/strong&gt;，并向源点发送时间超过报文。另外，&lt;strong&gt;当终点在预先规定的时间内未能收到一个数据报的全部数据报分片时，就把已收到的数据报片都丢弃，也会向源点发送时间超过（超时）报文。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="uploads/posts/computer-network/Screenshot-2026-03-13-145415.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;参数问题&lt;/strong&gt;：当路由器或目的主机收到IP数据报后发现其&lt;strong&gt;首部中有不正确的字段值&lt;/strong&gt;时，就丢弃该数据报，并向源点发送参数问题报文。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-13-145518.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;改变路由（&lt;strong&gt;重定向&lt;/strong&gt;）：路由器把改变路由报文发送给主机，&lt;strong&gt;让主机知道下次应将IP数据报发送给另外的路由器&lt;/strong&gt;，这样可以&lt;strong&gt;通过更好的路由到达目的主机&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="询问报文"&gt;询问报文
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;回送请求和回答：用来测试目的站是否可达以及了解其有关状态。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;时间戳请求和回答：用来进行时钟同步和测量时间。&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="分组网间探测ping"&gt;分组网间探测PING
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;分组网间探测PING用来&lt;strong&gt;测试主机或路由器之间的连通性&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;PING是TCP/IP体系结构的&lt;strong&gt;应用层直接使用网际层ICMP&lt;/strong&gt;的一个例子，它并不使用运输层的TCP或UDP。&lt;/li&gt;
&lt;li&gt;PING应用所&lt;strong&gt;使用的ICMP报文类型为回送请求和回答&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="跟踪路由"&gt;跟踪路由
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;跟踪路由应用 traceroute，用于探测 IP 数据报从源主机到达目的主机要经过哪些路由器。&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;在不同操作系统中，traceroute 应用的命令和实现机制有所不同：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;在 UNIX 版本中&lt;/strong&gt;，具体命令为 “&lt;strong&gt;traceroute&lt;/strong&gt;”，其在运输层使用 &lt;strong&gt;UDP&lt;/strong&gt; 协议，在网络层使用 &lt;strong&gt;ICMP&lt;/strong&gt; 报文类型只有&lt;strong&gt;差错报告报文&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;在 Windows 版本中&lt;/strong&gt;，具体命令为 “&lt;strong&gt;tracert&lt;/strong&gt;”，其应用层直接使用网际层的 &lt;strong&gt;ICMP&lt;/strong&gt; 协议，所使用的 &lt;strong&gt;ICMP&lt;/strong&gt; 报文类型有&lt;strong&gt;回送请求和回答报文&lt;/strong&gt;以及&lt;strong&gt;差错报告报文&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="46-虚拟专用网和网络地址转换"&gt;4.6 虚拟专用网和网络地址转换
&lt;/h2&gt;&lt;h3 id="461-虚拟专用网-vpn"&gt;4.6.1 虚拟专用网 VPN
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;虚拟专用网 (Virtual Private Network, &lt;strong&gt;VPN&lt;/strong&gt;)：&lt;strong&gt;利用公用的因特网&lt;/strong&gt;作为本机构各专用网之间的通信载体，这样形成的网络又称为虚拟专用网。&lt;/li&gt;
&lt;li&gt;给专用网内各主机配置的IP地址应该是该&lt;strong&gt;专用网所在机构可以自行分配的IP地址&lt;/strong&gt;，这类IP地址仅在机构内部有效，称为&lt;strong&gt;专用地址&lt;/strong&gt; (Private Address)，不需要向因特网的管理机构申请。&lt;/li&gt;
&lt;li&gt;[RFC 1918] 规定了以下三个 CIDR 地址块中的地址作为专用地址：
&lt;ul&gt;
&lt;li&gt;10.0.0.0 ~ 10.255.255.255 (CIDR 地址块 10/8)&lt;/li&gt;
&lt;li&gt;172.16.0.0 ~ 172.31.255.255 (CIDR 地址块 172.16/12)&lt;/li&gt;
&lt;li&gt;192.168.0.0 ~ 192.168.255.255 (CIDR 地址块 192.168/16)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;很显然，全世界可能有&lt;strong&gt;很多不同机构的专用网具有相同的专用 IP 地址&lt;/strong&gt;，但这并不会引起麻烦，因为这些专用地址&lt;strong&gt;仅在机构内部使用&lt;/strong&gt;。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-13-151046.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;VPN要保证传输数据的安全性，会将原始的&lt;strong&gt;内部IP数据报进行加密&lt;/strong&gt;，然后再&lt;strong&gt;将其封装成为在因特网上传送的外部IP数据报&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;同一机构内不同部门的内部网络所构成的VPN，又称为&lt;strong&gt;内联网VPN&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;有时，一个机构的虚拟专用网VPN需要某些外部机构（通常是合作伙伴）参加进来，这样的VPN就称为&lt;strong&gt;外联网VPN&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;在外地工作的员工需要访问公司内部的专用网时，只要在任何地点接入因特网，运行驻留在员工PC中的VPN软件，在员工的PC和公司的主机之间建立VPN隧道，就可以访问专用网中的资源，这种虚拟专用网又称为&lt;strong&gt;远程接入VPN&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="462-网络地址转换-nat"&gt;4.6.2 网络地址转换 NAT
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;网络地址转换&lt;/strong&gt;（&lt;strong&gt;Network Address Translation, NAT&lt;/strong&gt;）技术于1994年被提出，用来缓解IPv4地址空间即将耗尽的问题。
&lt;ul&gt;
&lt;li&gt;NAT能&lt;strong&gt;使大量使用内部专用地址的专用网络用户共享少量外部全球地址来访问因特网上的主机和资源&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;这种方法需要在专用网络连接到因特网的路由器上&lt;strong&gt;安装NAT软件&lt;/strong&gt;。装有NAT软件的路由器称为&lt;strong&gt;NAT路由器&lt;/strong&gt;，它&lt;strong&gt;至少要有一个有效的外部全球地址IP$_G$&lt;/strong&gt;。这样，所有使用内部专用地址的主机在和外部因特网通信时，都要在&lt;strong&gt;NAT路由器上将其内部专用地址转换成IP$_G$&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;如果NAT路由器拥有 $n$（$n$ 比较小）个全球IP地址，那么专用网内最多可以同时有 $n$ 台主机接入因特网。若专用网内的主机数量大于 $n$，则需要轮流使用NAT路由器中数量较少的全球IP地址。&lt;/li&gt;
&lt;li&gt;由于目前绝大多数基于TCP/IP协议栈的网络应用，都使用运输层传输控制协议TCP或用户数据报协议UDP，为了&lt;strong&gt;更加有效地利用NAT路由器中的全球IP地址&lt;/strong&gt;，现在常将NAT转换和运输层端口号结合使用。这样就可以使内部专用网中&lt;strong&gt;使用专用地址的大量主机，共用NAT路由器上的1个全球IP地址&lt;/strong&gt;，因而可以同时与因特网中的不同主机进行通信。&lt;/li&gt;
&lt;li&gt;将NAT和运输层端口号结合使用，称为&lt;strong&gt;网络地址与端口号转换&lt;/strong&gt;（Network Address and Port Translation, &lt;strong&gt;NAPT&lt;/strong&gt;）。现在很多家用路由器将家中各种智能设备（手机、平板、笔记本电脑、台式电脑、物联网设备等）接入因特网，这种路由器实际上就是一个&lt;strong&gt;NAPT路由器&lt;/strong&gt;，但往往并不运行路由选择协议。&lt;/li&gt;
&lt;li&gt;尽管NAT（和NAPT）的出现在很大程度上缓解了IPv4地址资源紧张的局面，但&lt;strong&gt;NAT（和NAPT）对网络应用并不完全透明&lt;/strong&gt;，会对某些网络应用产生影响。&lt;/li&gt;
&lt;li&gt;NAT（和NAPT）的一个重要特点就是&lt;strong&gt;通信必须由专用网内部发起&lt;/strong&gt;，因此拥有内部专用地址的主机不能直接充当因特网中的服务器。&lt;/li&gt;
&lt;li&gt;对于目前P2P这类需要外网主机主动与内网主机进行通信的网络应用，在通过NAT时会遇到问题，需要网络应用自身使用一些特殊的&lt;strong&gt;NAT穿透技术&lt;/strong&gt;来解决。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-13-154151.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-13-154305.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2 id="51-运输层概述"&gt;5.1 运输层概述
&lt;/h2&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-13-161205.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h3 id="511-进程间基于网络的通信"&gt;5.1.1 进程间基于网络的通信
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;第2~4章依次介绍了计算机网络体系结构中的物理层、数据链路层和网络层，它们共同解决了将主机通过异构网络互联起来所面临的问题，实现了&lt;strong&gt;主机到主机的通信&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;然而在计算机网络中实际进行&lt;strong&gt;通信的真正实体，是位于通信两端主机中的进程&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;如何为&lt;strong&gt;运行在不同主机上的应用进程提供直接的逻辑通信服务&lt;/strong&gt;，就是运输层的主要任务。运输层协议又称为端到端协议。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-13-160732.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;运输层向应用层实体屏蔽了下面网络核心的细节（例如网络拓扑、所采用的路由选择协议等），它使应用进程看见的就&lt;strong&gt;好像是在两个运输层实体之间有一条端到端的逻辑通信信道&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;根据应用需求的不同，&lt;strong&gt;因特网的运输层&lt;/strong&gt;为应用层提供了两种不同的运输层协议，即&lt;strong&gt;面向连接的TCP和无连接的UDP&lt;/strong&gt;，这两种协议就是本章要讨论的主要内容。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="512-tcpip-运输层中的两个重要协议"&gt;5.1.2 TCP/IP 运输层中的两个重要协议
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-13-161752.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="tcp"&gt;TCP
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;传输控制协议&lt;/strong&gt; (&lt;strong&gt;Transmission Control Protocol, TCP&lt;/strong&gt;) 为其上层提供的是&lt;strong&gt;面向连接的可靠的&lt;/strong&gt;数据传输服务。&lt;/li&gt;
&lt;li&gt;使用TCP通信的双方，在传送数据之前&lt;strong&gt;必须首先建立TCP连接&lt;/strong&gt;（逻辑连接，而非物理连接）。数据传输结束后&lt;strong&gt;必须释放TCP连接&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;TCP为了实现可靠传输，就必须使用很多措施，例如&lt;strong&gt;TCP连接管理、确认机制、超时重传、流量控制以及拥塞控制&lt;/strong&gt;等。&lt;/li&gt;
&lt;li&gt;TCP的&lt;strong&gt;实现复杂&lt;/strong&gt;，TCP报文段的&lt;strong&gt;首部比较大&lt;/strong&gt;，&lt;strong&gt;占用处理机资源比较多&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="udp"&gt;UDP
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;用户数据报协议&lt;/strong&gt; (&lt;strong&gt;User Datagram Protocol, UDP&lt;/strong&gt;) 为其上层提供的是&lt;strong&gt;无连接的不可靠的&lt;/strong&gt;数据传输服务。&lt;/li&gt;
&lt;li&gt;使用UDP通信的双方，在传送数据之前&lt;strong&gt;不需要建立连接&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;UDP不需要实现可靠传输，因此&lt;strong&gt;不需要使用实现可靠传输的各种机制&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;UDP的&lt;strong&gt;实现简单&lt;/strong&gt;，UDP用户数据报的&lt;strong&gt;首部比较小&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="513-运输层端口号复用与分用"&gt;5.1.3 运输层端口号、复用与分用
&lt;/h3&gt;&lt;h4 id="运输层端口号"&gt;运输层端口号
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;运行在计算机上的进程是使用&lt;strong&gt;进程标识符&lt;/strong&gt; (&lt;strong&gt;Process Identification, PID&lt;/strong&gt;) 来标识的。&lt;/li&gt;
&lt;li&gt;然而，因特网上的计算机并不是使用统一的操作系统，而&lt;strong&gt;不同操作系统&lt;/strong&gt; (Windows、Linux、MacOS) &lt;strong&gt;又使用不同格式的进程标识符&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;为了使运行不同操作系统的计算机的应用进程之间能够基于网络进行通信，就必须使用&lt;strong&gt;统一的方法对TCP/IP体系的应用进程进行标识&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;TCP/IP体系结构的运输层使用&lt;strong&gt;端口号&lt;/strong&gt;来标识和区分应用层的不同应用进程。端口号的&lt;strong&gt;长度为16比特&lt;/strong&gt;，取值范围是&lt;strong&gt;0~65535&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-13-164302.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;熟知端口号&lt;/strong&gt;：&lt;strong&gt;由IANA分配给TCP/IP体系结构应用层中最重要的提示应用协议&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;登记端口号&lt;/strong&gt;：&lt;strong&gt;为没有熟知端口号的应用程序使用&lt;/strong&gt;。要使用这类端口号，&lt;strong&gt;必须在IANA进行登记，以防止重复&lt;/strong&gt;。例如，Microsoft RDP微软远程桌面应用程序使用的端口号是&lt;strong&gt;3389&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;短暂端口号&lt;/strong&gt;：&lt;strong&gt;仅在客户端使用&lt;/strong&gt;，由客户进程在运行时&lt;strong&gt;动态选择&lt;/strong&gt;，通信结束后会被系统收回。&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;FTP&lt;/th&gt;
					&lt;th&gt;SMTP&lt;/th&gt;
					&lt;th&gt;DNS&lt;/th&gt;
					&lt;th&gt;DHCP&lt;/th&gt;
					&lt;th&gt;HTTP&lt;/th&gt;
					&lt;th&gt;BGP&lt;/th&gt;
					&lt;th&gt;HTTPS&lt;/th&gt;
					&lt;th&gt;RIP&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;21/20&lt;/td&gt;
					&lt;td&gt;25&lt;/td&gt;
					&lt;td&gt;53&lt;/td&gt;
					&lt;td&gt;67/68&lt;/td&gt;
					&lt;td&gt;80&lt;/td&gt;
					&lt;td&gt;179&lt;/td&gt;
					&lt;td&gt;443&lt;/td&gt;
					&lt;td&gt;520&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;端口号只具有本地意义，即端口号只是为了标识本计算机网络协议栈应用层中的各应用进程。在因特网中，不同计算机中的相同端口号是没有关系的，即相互独立。另外，TCP和UDP端口号之间也是没有关系的。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="发送方的复用和接收方的分用"&gt;发送方的复用和接收方的分用
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-13-165029.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-network/Screenshot-2026-03-13-165124.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="514-udp和tcp的对比"&gt;5.1.4 UDP和TCP的对比
&lt;/h3&gt;</description></item><item><title>群晖NAS代理及Emby配置</title><link>https://ottercoconut.github.io/p/%E7%BE%A4%E6%99%96nas%E4%BB%A3%E7%90%86%E5%8F%8Aemby%E9%85%8D%E7%BD%AE/</link><pubDate>Mon, 16 Feb 2026 11:12:15 +0800</pubDate><guid>https://ottercoconut.github.io/p/%E7%BE%A4%E6%99%96nas%E4%BB%A3%E7%90%86%E5%8F%8Aemby%E9%85%8D%E7%BD%AE/</guid><description>&lt;p&gt;近日笔者在使用群晖NAS的v2rayA时遇到了时间同步不正确导致的无法正常使用的问题，导致emby无法刮削。虽然不知道原因，但也是个老问题了，版本很旧，而且用的是第三方软件市场的docker，现在docker也不能裸连获取了。下面是解决经验：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;重新安装v2rayA&lt;/li&gt;
&lt;li&gt;配置docker版的emby。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;参考网站：&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://v2raya.org/docs/prologue/installation/linux/" target="_blank" rel="noopener"
 &gt;Linux 后备安装方式 - v2rayA&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/XTLS/Xray-core" target="_blank" rel="noopener"
 &gt;XTLS/Xray-core: Xray, Penetrates Everything. Also the best v2ray-core. Where the magic happens. An open platform for various uses.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://v2raya.org/docs/advanced-application/synology-transparent-proxy/" target="_blank" rel="noopener"
 &gt;群晖实现透明代理 - v2rayA&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/sjtuross/syno-iptables" target="_blank" rel="noopener"
 &gt;sjtuross/syno-iptables: Some missing iptables modules for Synology&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://blog.csdn.net/caca_66/article/details/150264099" target="_blank" rel="noopener"
 &gt;群晖 DSM 7.2 为 Container Manager（docker）设置代理_群晖docker设置代理-CSDN博客&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="v2raya"&gt;v2rayA
&lt;/h2&gt;&lt;p&gt;由v2rayA的官方文档可见，群晖并没有特别适配的版本，所以采用通用的二进制文件进行安装。既然裸连也无法从github上拉取文件，我们在电脑上下好传到NAS上。此外，下面的安装内容实则和文档略有不同。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;拷贝v2rayA和xray&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cp v2raya_linux_x64 /usr/local/bin/v2raya
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cp xray /usr/local/bin/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod +x /usr/local/bin/v2raya
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod +x /usr/local/bin/xray
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;拷贝xray自带的GFWList代理规则文件：&lt;code&gt;geoip.dat&lt;/code&gt;和&lt;code&gt;geosite.dat&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /usr/local/share
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir xray
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cp .../g* xray
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;修改&lt;code&gt;service&lt;/code&gt;配置文件&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo vi /etc/systemd/system/v2raya.service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;内容由ChatGPT结合官方文档生成：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;Unit&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;v2rayA Service
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;After&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;network.target
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;Service&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;simple
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;User&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;root
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;Environment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;V2RAYA_CONFIG=/usr/local/etc/v2raya&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;Environment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;V2RAYA_LOG_FILE=/tmp/v2raya.log&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;Environment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;XRAY_LOCATION_ASSET=/usr/local/share/xray&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/local/bin/v2raya --passcheckroot
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;Restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;on-failure
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;LimitNOFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1000000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;Install&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;multi-user.target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;激活v2rayA，根据官方文档，采用服务的形式运行&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl start v2raya
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl status v2raya
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;配置开机自启。理论上这步之后配置完毕，笔者又顺便解决了群晖用不了透明代理的问题&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; v2raya
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl is-enabled v2raya
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;激活透明代理&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;arch&lt;/th&gt;
					&lt;th&gt;kernel&lt;/th&gt;
					&lt;th&gt;iptables version&lt;/th&gt;
					&lt;th&gt;system model&lt;/th&gt;
					&lt;th&gt;platform version&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;apollolake&lt;/td&gt;
					&lt;td&gt;4.4.180+&lt;/td&gt;
					&lt;td&gt;v1.8.3&lt;/td&gt;
					&lt;td&gt;DS918+&lt;/td&gt;
					&lt;td&gt;7.0.1-42218&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;apollolake&lt;/td&gt;
					&lt;td&gt;4.4.59+&lt;/td&gt;
					&lt;td&gt;v1.6.0&lt;/td&gt;
					&lt;td&gt;DS918+&lt;/td&gt;
					&lt;td&gt;6.2.3-25426&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;broadwell&lt;/td&gt;
					&lt;td&gt;3.10.105&lt;/td&gt;
					&lt;td&gt;v1.6.0&lt;/td&gt;
					&lt;td&gt;DS3617xs&lt;/td&gt;
					&lt;td&gt;6.2.3-25426&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;bromolow&lt;/td&gt;
					&lt;td&gt;3.10.105&lt;/td&gt;
					&lt;td&gt;v1.6.0&lt;/td&gt;
					&lt;td&gt;DS3615xs&lt;/td&gt;
					&lt;td&gt;6.2.3-25426&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;geminilake&lt;/td&gt;
					&lt;td&gt;4.4.180+&lt;/td&gt;
					&lt;td&gt;v1.8.3&lt;/td&gt;
					&lt;td&gt;DS920+&lt;/td&gt;
					&lt;td&gt;7.1-42661&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;geminilake&lt;/td&gt;
					&lt;td&gt;4.4.302+&lt;/td&gt;
					&lt;td&gt;v1.8.3&lt;/td&gt;
					&lt;td&gt;DS220+&lt;/td&gt;
					&lt;td&gt;7.2-64570&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;由于群晖系统的原因，先根据型号确定架构，然后从github仓库中下好的模块中选出适配机器的文件（比如笔者的DS224是geminilake）&lt;/p&gt;
&lt;p&gt;上传相应的ko模块至&lt;code&gt;/lib/modules/&lt;/code&gt;，上传相应的so模块至&lt;code&gt;/usr/lib/iptables/&lt;/code&gt;，即可。&lt;/p&gt;
&lt;p&gt;运行&lt;code&gt;sudo -i&lt;/code&gt;之后再运行以下&lt;code&gt;insmod&lt;/code&gt;命令尝试加载ko内核模块。由于模块互相有依赖性，需按一定顺序加载&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insmod /lib/modules/nfnetlink.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insmod /lib/modules/ip_set.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insmod /lib/modules/ip_set_hash_ip.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insmod /lib/modules/xt_set.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insmod /lib/modules/ip_set_hash_net.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insmod /lib/modules/xt_mark.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insmod /lib/modules/xt_connmark.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insmod /lib/modules/xt_comment.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insmod /lib/modules/xt_TPROXY.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insmod /lib/modules/xt_socket.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insmod /lib/modules/iptable_mangle.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insmod /lib/modules/textsearch.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insmod /lib/modules/ts_bm.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insmod /lib/modules/xt_string.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insmod /lib/modules/nf_nat_ipv6.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insmod /lib/modules/nf_nat_masquerade_ipv6.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insmod /lib/modules/ip6t_MASQUERADE.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insmod /lib/modules/ip6table_nat.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insmod /lib/modules/ip6table_raw.ko
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;insmod /lib/modules/ip6table_mangle.ko
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;但是系统重启后，模块需要重新加载，所以用以上内容生成脚本在&lt;code&gt;/usr/local/bin/load_v2raya_mods.sh&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;然后重启v2rayA服务:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl restart v2raya
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="emby"&gt;Emby
&lt;/h2&gt;&lt;p&gt;在配置好v2rayA后，即使采用了改配置文件的办法，emby的流量仍不能成功地通过v2rayA来走，各种修改配置ip后无果，于是自然想到是docker变成本机服务导致的。&lt;/p&gt;
&lt;p&gt;在v2rayA上多次修改配置后，终于发现开启透明代理解决问题，同时也解决了连接不上Docker仓库的问题，但更大的问题是启用透明代理会使外网访问全部失败（亏好内网还能连接）。“透明代理”我想可以理解为“全局代理”。&lt;/p&gt;
&lt;p&gt;Docker(Container Manager)单独设置代理的问题详见前言链接。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;在“映像”中选中emby并运行，在“存储空间设置”中加入媒体库的路径，在“环境”中加入三个环境变量，“网络”中选择&lt;code&gt;host&lt;/code&gt;模式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;HTTP_PROXY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; http://127.0.0.1:20171
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;HTTPS_PROXY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; http://127.0.0.1:20171
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;NO_PROXY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; localhost,127.0.0.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;完成基本设置，安装好之前的动漫相关的插件，刮削成功。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>如何在WSL2上使用本机代理</title><link>https://ottercoconut.github.io/p/%E5%A6%82%E4%BD%95%E5%9C%A8wsl2%E4%B8%8A%E4%BD%BF%E7%94%A8%E6%9C%AC%E6%9C%BA%E4%BB%A3%E7%90%86/</link><pubDate>Fri, 30 Jan 2026 16:31:20 +0800</pubDate><guid>https://ottercoconut.github.io/p/%E5%A6%82%E4%BD%95%E5%9C%A8wsl2%E4%B8%8A%E4%BD%BF%E7%94%A8%E6%9C%AC%E6%9C%BA%E4%BB%A3%E7%90%86/</guid><description>&lt;p&gt;由于近日笔者经常用Python下载各种模型，终要解决困扰已久的wsl2与Windows主机代理不互通的问题。笔者浪费了半个下午后终于搞定，在得力助手Gemini的帮助下，主要步骤如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Windows的&lt;code&gt;.wslconfig&lt;/code&gt;设置&lt;/li&gt;
&lt;li&gt;v2rayN的核心设置&lt;/li&gt;
&lt;li&gt;Windows的防火墙设置&lt;/li&gt;
&lt;li&gt;wsl2的旧设置清理&lt;/li&gt;
&lt;li&gt;wsl2的&lt;code&gt;~/.bashrc&lt;/code&gt;设置&lt;/li&gt;
&lt;li&gt;wsl2的&lt;code&gt;curl -v&lt;/code&gt;测试&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;参考网站：&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://learn.microsoft.com/en-us/windows/wsl/wsl-config" target="_blank" rel="noopener"
 &gt;Advanced settings configuration in WSL | Microsoft Learn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://github.com/2dust/v2rayN/issues/2653" target="_blank" rel="noopener"
 &gt;WSL2 使用 V2RayN 局域网 proxychains 代理方案 · Issue #2653 · 2dust/v2rayN&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://hlog.cc/archives/210/" target="_blank" rel="noopener"
 &gt;记一次用wsl2中共享宿主机的代理-v2rayN - 沉迷于学习，无法自拔^_^&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="wslconfig"&gt;.wslconfig
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;访问Windows下的个人账户文件夹，按下 &lt;code&gt;Win + R&lt;/code&gt;，输入 &lt;code&gt;%UserProfile%&lt;/code&gt; 并回车&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;检查是否有 &lt;code&gt;.wslconfig&lt;/code&gt; 文件。&lt;strong&gt;如果没有，新建一个文本文件并命名为 &lt;code&gt;.wslconfig&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;将以下内容粘贴到&lt;code&gt;.wslconfig&lt;/code&gt;中：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[&lt;/span&gt;wsl2&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 开启镜像网络模式&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;networkingMode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;mirrored
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 自动同步代理设置（可选true/false）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;autoProxy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;需注意的是：&lt;code&gt;autoProxy&lt;/code&gt;这个参数决定了wsl2代理的方式，设置为&lt;code&gt;true&lt;/code&gt;可以不再配置&lt;code&gt;~/.bashrc&lt;/code&gt;，但是问题在于：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;当我们使用&lt;code&gt;env | grep -i proxy&lt;/code&gt;命令，会看到很多奇怪的和网络有关的变量，虽然确实能成功实现代理。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不能在wsl2中开关代理，导致很多流量都通过代理来走&lt;/p&gt;
&lt;p&gt;后面我们将其设置为&lt;code&gt;false&lt;/code&gt;，以便于在wsl2内部可以方便地控制代理的开关，保证wsl2系统的清晰透明。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在Windows终端中输入&lt;code&gt;wsl --shutdown&lt;/code&gt;关闭wsl2&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="v2rayn"&gt;v2rayN
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;在v2rayN（撰文时版本为V7.15.7）的基础设置中，启用“&lt;strong&gt;允许来自局域网的连接&lt;/strong&gt;”以及“为局域网开启新的端口”（可选）&lt;/li&gt;
&lt;li&gt;在v2rayN客户端的主界面左下角能看到&lt;strong&gt;为互联网开放的端口&lt;/strong&gt;，笔者这里是&lt;code&gt;10810&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;这里系统代理是“自动配置系统代理”，路由模式是“绕过(Whitelist)”&lt;/li&gt;
&lt;li&gt;然后选好节点，保持v2rayN的进行&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="firewall"&gt;FireWall
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;在 Windows 搜索框输入“防火墙”，选择 &lt;strong&gt;Windows Defender 防火墙&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;点击 &lt;strong&gt;“允许应用或功能通过 Windows Defender 防火墙”&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;找到或添加 &lt;code&gt;v2rayN.exe&lt;/code&gt; 和其核心程序（如 &lt;code&gt;v2ray.exe&lt;/code&gt; 或 &lt;code&gt;xray.exe&lt;/code&gt;），确保 &lt;strong&gt;专用&lt;/strong&gt; 和 &lt;strong&gt;公用&lt;/strong&gt; 都勾选上。通常路径分别在&lt;code&gt;v2rayN\&lt;/code&gt;和&lt;code&gt;v2rayN\bin\xray&lt;/code&gt;下&lt;/li&gt;
&lt;li&gt;在防火墙高级设置中，新建一个入站规则，允许端口 &lt;code&gt;10810&lt;/code&gt; 的 TCP 流量（与v2rayN相对应）&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="wsl2"&gt;wsl2
&lt;/h2&gt;&lt;h3 id="清理旧设置"&gt;清理旧设置
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 1. 清除旧的、混乱的代理环境变量&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;unset&lt;/span&gt; &lt;span class="n"&gt;http_proxy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;unset&lt;/span&gt; &lt;span class="n"&gt;https_proxy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;unset&lt;/span&gt; &lt;span class="n"&gt;no_proxy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 2. 重新设置正确的代理（指向镜像模式下的本地端口）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="n"&gt;http_proxy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;http://127.0.0.1:10810&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="n"&gt;https_proxy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;http://127.0.0.1:10810&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;确保在第一步已开启镜像网络模式并重启好wsl2。当然这步也不是必须的，因为后面&lt;code&gt;~/.bashrc&lt;/code&gt;会自动处理这些就变量。&lt;/p&gt;
&lt;h3 id="bashrc"&gt;~/.bashrc
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 用其它的编辑器同理&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo vim ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;在与Gemini多次实验后，得出以下内容用于添加到&lt;code&gt;~/.bashrc&lt;/code&gt;底部：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt; proxy_on&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 彻底清理可能残留的变量（防止大小写混用冲突）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;unset&lt;/span&gt; http_proxy https_proxy ALL_PROXY NO_PROXY HTTP_PROXY HTTPS_PROXY all_proxy no_proxy
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 设置你验证成功的端口（既然 10810 测通了，就用 10810）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;hostip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;10810&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;http_proxy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;http://&lt;/span&gt;&lt;span class="nv"&gt;$hostip&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$port&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;https_proxy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;http://&lt;/span&gt;&lt;span class="nv"&gt;$hostip&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$port&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;all_proxy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;socks5://&lt;/span&gt;&lt;span class="nv"&gt;$hostip&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;$port&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 这里的 no_proxy 只保留本地回环&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nv"&gt;no_proxy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;localhost,127.0.0.1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;WSL Proxy: ON (127.0.0.1:10810)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;function&lt;/span&gt; proxy_off&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;unset&lt;/span&gt; http_proxy https_proxy ALL_PROXY NO_PROXY HTTP_PROXY HTTPS_PROXY all_proxy no_proxy
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;WSL Proxy: OFF&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;保存以上内容后，输入：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;然后再：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -I https://www.google.com
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;应该就会出现以下内容，表示连接成功：&lt;/p&gt;
&lt;p&gt;笔者同时也用&lt;code&gt;ping&lt;/code&gt;去测试了一下，虽然不成功，但不影响使用。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;HTTP/1.1 &lt;span class="m"&gt;200&lt;/span&gt; Connection established
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;笔者再次尝试下载模型，果然成功：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;gensim.downloader&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;api&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;wv_from_bin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;glove-wiki-gigaword-200&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="再不成功的解决方案"&gt;再不成功的解决方案
&lt;/h3&gt;&lt;p&gt;最有效的方法的就是在完成了上面步骤后，wsl2中输入：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -v https://www.google.com
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;然后把输出的结果交给AI，它会告诉你的。&lt;/p&gt;</description></item><item><title>CS224N</title><link>https://ottercoconut.github.io/p/cs224n/</link><pubDate>Wed, 28 Jan 2026 14:31:08 +0800</pubDate><guid>https://ottercoconut.github.io/p/cs224n/</guid><description>&lt;h2 id="intro"&gt;Intro
&lt;/h2&gt;&lt;p&gt;本篇是对&lt;a class="link" href="https://web.stanford.edu/class/archive/cs/cs224n/cs224n.1246/" target="_blank" rel="noopener"
 &gt;Stanford CS 224N | Natural Language Processing with Deep Learning (Spring 2024)&lt;/a&gt; 这门课程的学习笔记。关于这门课的知识点，总结如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;词向量、RNN、LSTM、Seq2Seq 模型、机器翻译、注意力机制、Transformer 等等&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="what-is-this-course-about"&gt;What is this course about?
&lt;/h3&gt;&lt;p&gt;Natural language processing (NLP) or computational linguistics is one of the most important technologies of the information age. Applications of NLP are everywhere because people communicate almost everything in language: web search, advertising, emails, customer service, language translation, virtual agents, medical reports, politics, etc. In the 2010s, deep learning (or neural network) approaches obtained very high performance across many different NLP tasks, using single end-to-end neural models that did not require traditional, task-specific feature engineering. In the 2020s amazing further progress was made through the scaling of Large Language Models, such as ChatGPT. In this course, students will gain a thorough introduction to both the basics of Deep Learning for NLP and the latest cutting-edge research on Large Language Models (LLMs). Through lectures, assignments and a final project, students will learn the necessary skills to design, implement, and understand their own neural network models, using the Pytorch framework.&lt;/p&gt;
&lt;h2 id="word-vectors"&gt;Word Vectors
&lt;/h2&gt;&lt;p&gt;$ vector(”King”)- vector(”Man”) + vector(”Woman”) $&lt;/p&gt;
&lt;p&gt;&lt;em&gt;results in a vector that is closest to the vector representation of the word Queen&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="how-do-we-have-usable-meaning-in-a-computer"&gt;How do we have usable meaning in a computer?
&lt;/h3&gt;&lt;p&gt;Slides里介绍了几种方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;WordNet&lt;/li&gt;
&lt;li&gt;one-hot vectors&lt;/li&gt;
&lt;li&gt;word vectors&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;那么前两种都有其现实意义，但也有明显的弊端。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;WordNet，完全靠&lt;code&gt;synonum sets&lt;/code&gt;和&lt;code&gt;hypernyms sets&lt;/code&gt;来确定词汇间的关系、构造复杂、无法及时吸收新词汇&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;one-hot vectors给每个词都设置了&lt;code&gt;symbol&lt;/code&gt;，尽管是用数字表达，但是&lt;strong&gt;相近的词之间在数学上没有联系&lt;/strong&gt;（向量的点积为0）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;那么下面就引出了一句名言：&lt;em&gt;&amp;ldquo;You shall know a word by the company it keeps&amp;rdquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;以及word vectors的思想，将&lt;strong&gt;词汇归一化到一个向量&lt;/strong&gt;中，虽然每个词汇有多个词义，但其分布却近似是其多个词义的平均，并用点积来确定词向量间的相关性。&lt;/p&gt;
&lt;h3 id="word2vec"&gt;Word2vec
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://arxiv.org/pdf/1301.3781" target="_blank" rel="noopener"
 &gt;original word2vec paper&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Word2vec&lt;/code&gt;很好地反映了word vectors的思想，计算中心词和相邻词的相似度，确定其概率分布：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We have a large corpus (“body”) of text: a long list of words&lt;/li&gt;
&lt;li&gt;Every word in a fixed vocabulary is represented by a &lt;strong&gt;vector&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Go through each position t in the text, which has a center word c and context (“outside”) words o&lt;/li&gt;
&lt;li&gt;Use the &lt;strong&gt;similarity of the word vectors for c and o to calculate the probability&lt;/strong&gt; of o given c (or vice versa)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep adjusting the word vectors&lt;/strong&gt; to maximize this probability&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/Word2Vec-1.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="objective-function"&gt;Objective Function
&lt;/h4&gt;&lt;p&gt;那么如何计算其似然程度(Likelihood)呢，For each position = $t=1,......,T$, predict context words within a window of fixed size $m$, given center word $w_t$. Data likelihood :
&lt;/p&gt;
$$
L(\theta) = \prod_{t=1}^{T} \prod_{\substack{-m \le j \le m \\ j \neq 0}} P(w_{t+j} \mid w_t; \theta)
$$&lt;p&gt;
为减小数据复杂程度，及方便计算机处理，优化上公式，对其进行平均负对数似然操作，The objective function $J(\theta)$ is the (average) negative log likelihood:
&lt;/p&gt;
$$
J(\theta) = -\frac{1}{T} \log L(\theta) = -\frac{1}{T} \sum_{t=1}^{T} \sum_{substack{-m \le j \le m \\ j \neq 0}} \log P(w_{t+j} \mid w_t; \theta)
$$&lt;p&gt;
&lt;strong&gt;最小化 $J(\theta)$&lt;/strong&gt; 等价于 &lt;strong&gt;最大化预测准确率&lt;/strong&gt;。&lt;/p&gt;
&lt;h4 id="prediction-function"&gt;Prediction Function
&lt;/h4&gt;$$
P(o \mid c) = \frac{\exp(u_o^T v_c)}{\sum_{w \in V} \exp(u_w^T v_c)}
$$&lt;ol&gt;
&lt;li&gt;$u_o^T v_c$ : 点积越大，代表这两个词在向量空间中的位置越接近，即语义相关性越高。
Dot product compares similarity of o and c. $u^T v = u \cdot v = \sum_{i=1}^{n} u_i v_i$ Larger dot product = larger probability.&lt;/li&gt;
&lt;li&gt;$\exp()$ : 将任何实数映射为&lt;strong&gt;正数&lt;/strong&gt;。由于指数函数的增长特性，它会放大较大点积的影响，使相关性高的词获得更高的权重。&lt;/li&gt;
&lt;li&gt;${\sum_{w \in V} \exp(u_w^T v_c)}$ : 分母是对词汇表$V$中所有可能的词进行求和。这一步确保了所有可能输出的概率之和等于 &lt;strong&gt;1&lt;/strong&gt;，从而构成一个标准的概率分布。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这也是对Softmax Function的应用
&lt;/p&gt;
$$
\text{softmax}(x_i) = \frac{\exp(x_i)}{\sum_{j=1}^{n} \exp(x_j)} = p_i
$$&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Softmax 函数将任意值 $x_i$ 映射为一个概率分布 $p_i$。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;“max”：因为它会&lt;strong&gt;放大&lt;/strong&gt;最大值 $x_i$ 对应的概率，使大的更大。&lt;/li&gt;
&lt;li&gt;“soft”：因为它仍然会给较小的 $x_i$ &lt;strong&gt;分配一些概率&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="to-train-the-model"&gt;To Train the Model
&lt;/h4&gt;&lt;p&gt;To train a model, we gradually adjust parameters to minimize a loss.
&lt;/p&gt;
$$
\theta = \begin{bmatrix} 
v_{aardvark} \\ v_a \\ \vdots \\ v_{zebra} \\ u_{aardvark} \\ u_a \\ \vdots \\ u_{zebra}
\end{bmatrix} \in \mathbb{R}^{2dV}
$$&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;如果词向量维度为 $d$，词汇量为 $V$，则&lt;strong&gt;总参数量&lt;/strong&gt;为 $2dV$。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;每个单词有两个向量，$\theta$ 包含了词汇表中所有单词的两种向量表示（中心词向量 $v$ 和背景词向量 $u$）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;计算所有参数的梯度，以优化模型&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;梯度公式就是对Softmax Function的求偏导，数学过程如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;初始损失函数 (单词对的负对数似然)&lt;/strong&gt;
这是针对一个中心词 $c$ 和一个背景词 $o$ 的基本损失定义：
&lt;/p&gt;
$$
 \text{Loss} = -\log P(o \mid c)
 $$&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;代入Softmax定义展开&lt;/strong&gt;
将 $P(o|c)$ 的公式代入，利用对数性质将除法化为减法：
&lt;/p&gt;
$$
 \text{Loss} = -\log \left( \frac{\exp(u_o^T v_c)}{\sum_{w \in V} \exp(u_w^T v_c)} \right) = -u_o^T v_c + \log \sum_{w \in V} \exp(u_w^T v_c)
 $$&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;第一部分求导&lt;/strong&gt;
对点积项关于中心词向量 $v_c$ 求偏导：
&lt;/p&gt;
$$
 \frac{\partial}{\partial v_c} (u_o^T v_c) = u_o
 $$&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;第二部分求导&lt;/strong&gt;
利用链式法则对 $\log \sum \exp(\dots)$ 形式进行求导：
&lt;/p&gt;
$$
 \frac{\partial}{\partial v_c} \log \sum_{w \in V} \exp(u_w^T v_c) = \frac{1}{\sum_{w \in V} \exp(u_w^T v_c)} \cdot \sum_{x \in V} \left[ \exp(u_x^T v_c) \cdot u_x \right]
 $$&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;转化为概率期望形式&lt;/strong&gt;
将上一步的结果重新组合，提取出原始的概率项 $P(x|c)$：
&lt;/p&gt;
$$
 \sum_{x \in V} \left[ \frac{\exp(u_x^T v_c)}{\sum_{w \in V} \exp(u_w^T v_c)} \right] u_x = \sum_{x \in V} P(x \mid c) u_x
 $$&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;最终梯度公式&lt;/strong&gt;
将两部分合并，得到最终用于更新 $v_c$ 的梯度：
&lt;/p&gt;
$$
 \frac{\partial \text{Loss}}{\partial v_c} = -u_o + \sum_{x \in V} P(x \mid c) u_x
 $$&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="gradient-descent"&gt;Gradient Descent
&lt;/h4&gt;&lt;p&gt;梯度下降更新方程 (矩阵形式)
&lt;/p&gt;
$$
\theta^{new} = \theta^{old} - \alpha \nabla_{\theta} J(\theta)
$$&lt;p&gt;
梯度下降更新方程 (单个参数形式)
&lt;/p&gt;
$$
\theta_j^{new} = \theta_j^{old} - \alpha \frac{\partial}{\partial \theta_j^{old}} J(\theta)
$$&lt;ul&gt;
&lt;li&gt;$\alpha$ (alpha): 步长或学习率（step size / learning rate）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但是实际应用并非上面的方法，而是用&lt;strong&gt;随机梯度下降&lt;/strong&gt;，(Stochastic Gradient Descent, SGD)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;目标函数&lt;/strong&gt; $J(\theta)$ 是语料库中&lt;strong&gt;所有&lt;/strong&gt;窗口的函数。如果每次更新都要计算整个语料库的梯度 $\nabla_{\theta} J(\theta)$，计算成本极其昂贵，在进行单次更新前需要等待极长时间。&lt;/li&gt;
&lt;li&gt;SGD不再计算整个语料库，而是通过&lt;strong&gt;重复采样窗口&lt;/strong&gt;，&lt;strong&gt;每处理一个（或一小批）窗口就更新一次参数。&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="skip-gram-model-with-negative-sampling"&gt;Skip-gram Model with Negative Sampling
&lt;/h4&gt;&lt;p&gt;&lt;a class="link" href="https://proceedings.neurips.cc/paper_files/paper/2013/file/9aa42b31882ec039965f3c4923ce901b-Paper.pdf" target="_blank" rel="noopener"
 &gt;negative sampling paper&lt;/a&gt;
&lt;/p&gt;
$$
P(o\mid c)=\frac{\exp(u_x^T v_c)}{\sum_{w \in V} \exp(u_w^T v_c)}
$$&lt;p&gt;
采用最传统的方法计算概率时，即softmax，它的&lt;strong&gt;分母&lt;/strong&gt;是全部词的叠加，计算量太大&lt;/p&gt;
&lt;p&gt;而Skip-gram Model with Negative Sampling不需计算所有可能的词，而是训练一些逻辑回归，更偏好实际的上下文而非随机的上下文，实际上会选K个负样本，计算量就变为了$O(K)$
&lt;/p&gt;
$$
J_{neg-sample}(u_o, v_c, U) = -\log \sigma(u_o^T v_c) - \sum_{k \in \{K \text{ sampled indices}\}} \log \sigma(-u_k^T v_c)
$$&lt;p&gt;
其中，$\sigma(x)=\frac{1}{1+e^{-x}}$即sigmoid函数，使符合的结果概率接近于1，而不符合的则接近于0&lt;/p&gt;
&lt;p&gt;但这又会导致低频词，如&amp;quot;zebra&amp;quot;的概率过低，而像&amp;quot;the&amp;quot;这样的词则概率较高，所以给公式加上$3/4$次方：
&lt;/p&gt;
$$
P(W)=U(W)^{3/4}/Z
$$&lt;p&gt;
来提高低频词的概率。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="glove"&gt;GloVe
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://nlp.stanford.edu/pubs/glove.pdf" target="_blank" rel="noopener"
 &gt;original GloVe papar&lt;/a&gt; (Global Vectors for Word Representation)&lt;/p&gt;
&lt;h4 id="co-occurrence-martix"&gt;Co-occurrence Martix
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/co-occurrence.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;构建共现矩阵的方法非常简单，首先设定窗口长度，然后对在窗口长度内出现的共现词频率进行计数，一个简单的例子如上图（窗口为1，仅算相邻词）。但是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;词向量&lt;strong&gt;维度&lt;/strong&gt;会随着语料库中词汇的增多而大幅&lt;strong&gt;增加&lt;/strong&gt;，这会导致所需存储空间增大，且矩阵会变得相当&lt;strong&gt;稀疏&lt;/strong&gt;，基于此构建的模型&lt;strong&gt;鲁棒性较差&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;功能词出现频次极高，但没有提供相应的信息；&lt;/li&gt;
&lt;li&gt;没有反映出词距与词相关性之间的联系。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;那么如何进行降维来优化？经典的方法是进行SVD矩阵分解（虽然问了AI也没明白原理，而且Assignment1中用一个&lt;code&gt;sklearn&lt;/code&gt;的函数就解决了）&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/SVD.png" alt="" loading="lazy" /&gt;
&lt;/p&gt;
$$
X = U \Sigma V^T
$$&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;$X$ (共现矩阵)&lt;/strong&gt;：大小为 $|V| \times |V|$（词表大小）。每个元素 $X_{ij}$ 代表词 $i$ 和词 $j$ 在语料库中共同出现的次数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;$U$ 和 $V$ (正交矩阵)&lt;/strong&gt;：它们的列向量是相互正交的单位向量（Orthonormal）。在 NLP 中，$U$ 的每一行通常被视为该词的原始“嵌入”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;$\Sigma$ (对角矩阵)&lt;/strong&gt;：对角线上的值 $\sigma_1, \sigma_2, \dots$ 称为&lt;strong&gt;奇异值&lt;/strong&gt;。它们按从大到小排列，代表了数据在对应维度上的&lt;strong&gt;重要程度（方差/信息量）&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;那么降维便是将从共现矩阵得到的的，长度为$V$的词向量降维成长度为$K$的向量&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;真正编码语义的不是共现概率本身，而是共现概率的比值&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;共现概率的比率可以编码语义成分，我们希望将它们作为线性语义成分捕捉在词向量空间中！&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;&lt;/th&gt;
					&lt;th style="text-align: left"&gt;$x = \text{solid}$&lt;/th&gt;
					&lt;th style="text-align: left"&gt;$x = \text{gas}$&lt;/th&gt;
					&lt;th style="text-align: left"&gt;$x = \text{water}$&lt;/th&gt;
					&lt;th style="text-align: left"&gt;$x = \text{fashion}$&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;$P(x\mid\text{ice})$&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$1.9 \times 10^{-4}$&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$6.6 \times 10^{-5}$&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$3.0 \times 10^{-3}$&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$1.7 \times 10^{-5}$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;$P(x\mid\text{steam})$&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$2.2 \times 10^{-5}$&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$7.8 \times 10^{-4}$&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$2.2 \times 10^{-3}$&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$1.8 \times 10^{-5}$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;$\dfrac{P(x\mid\text{ice})}{P(x\mid\text{steam})}$&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$8.9$&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$8.5 \times 10^{-2}$&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$1.36$&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$0.96$&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id="analogies"&gt;Analogies
&lt;/h4&gt;&lt;p&gt;词向量虽然数学原理上很强大，但是其实际的类比(Analogy)场景却是有不少问题：&lt;/p&gt;
&lt;p&gt;下例可见，是一个$woman+grandfather-man=?$的问题，那么显而易见且最有可能的结果就是&lt;code&gt;grandmother&lt;/code&gt;，那么为何程序给出的另外几个，如&lt;code&gt;granddaughter&lt;/code&gt;, &lt;code&gt;mother&lt;/code&gt;之类，score也几乎一样很高呢？&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Run this cell to answer the analogy -- man : grandfather :: woman : x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;pprint&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wv_from_bin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;most_similar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;positive&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;woman&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;grandfather&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;negative&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;man&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;grandmother&amp;#39;&lt;/span&gt;, 0.7608445286750793&lt;span class="o"&gt;)&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;granddaughter&amp;#39;&lt;/span&gt;, 0.7200808525085449&lt;span class="o"&gt;)&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;daughter&amp;#39;&lt;/span&gt;, 0.7168302536010742&lt;span class="o"&gt;)&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;mother&amp;#39;&lt;/span&gt;, 0.7151536345481873&lt;span class="o"&gt;)&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;niece&amp;#39;&lt;/span&gt;, 0.7005682587623596&lt;span class="o"&gt;)&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;father&amp;#39;&lt;/span&gt;, 0.6659888029098511&lt;span class="o"&gt;)&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;aunt&amp;#39;&lt;/span&gt;, 0.6623409390449524&lt;span class="o"&gt;)&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;grandson&amp;#39;&lt;/span&gt;, 0.6618767976760864&lt;span class="o"&gt;)&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;grandparents&amp;#39;&lt;/span&gt;, 0.644661009311676&lt;span class="o"&gt;)&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;wife&amp;#39;&lt;/span&gt;, 0.6445354223251343&lt;span class="o"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;虽说Assignment里没有标准答案，但是通过AI可以得知：这涉及到“语义聚类”&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;语义的“近邻效应”&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;在向量空间中，逻辑相似的词通常会聚在一起形成一个“簇”。当你计算出 $\vec{w} + \vec{g} - \vec{m}$ 时，你实际上是在空间中定位了一个&lt;strong&gt;坐标点&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;granddaughter&lt;/code&gt; 等同样具有“女性”和“亲属”属性，且在语料库中经常与 &lt;code&gt;grandfather&lt;/code&gt; 或 &lt;code&gt;grandmother&lt;/code&gt; 出现在相似的上下文。在向量维度上，它们在“亲属关系”这个维度上非常接近。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;维度的“重叠性”&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;词向量通常有几百个维度。虽然我们减去了 &lt;code&gt;man&lt;/code&gt; 并加上了 &lt;code&gt;grandfather&lt;/code&gt;，但这并不能完全抹除其他维度的相似性。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;daughter&lt;/code&gt;、&lt;code&gt;mother&lt;/code&gt;、&lt;code&gt;grandmother&lt;/code&gt; 共享了绝大部分维度：[+女性]、[+人类]、[+亲属]。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面的例子，属于&amp;quot;Incorrect Analogy&amp;quot;，我们来看易得答案为&lt;code&gt;socks&lt;/code&gt;，但为何模型忽略了&lt;code&gt;glove&lt;/code&gt;和&lt;code&gt;hand&lt;/code&gt;，而输出了各种&lt;code&gt;square&lt;/code&gt;的名词？显然和&lt;code&gt;foot&lt;/code&gt;“脚”的释义无关，而是“英尺”的释义。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;pprint&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wv_from_bin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;most_similar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;positive&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;foot&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;glove&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;negative&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;hand&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;[(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;45,000-square&amp;#39;&lt;/span&gt;, 0.4922032654285431&lt;span class="o"&gt;)&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;15,000-square&amp;#39;&lt;/span&gt;, 0.4649604558944702&lt;span class="o"&gt;)&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;10,000-square&amp;#39;&lt;/span&gt;, 0.4544755816459656&lt;span class="o"&gt;)&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;6,000-square&amp;#39;&lt;/span&gt;, 0.44975775480270386&lt;span class="o"&gt;)&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;3,500-square&amp;#39;&lt;/span&gt;, 0.444133460521698&lt;span class="o"&gt;)&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;700-square&amp;#39;&lt;/span&gt;, 0.44257497787475586&lt;span class="o"&gt;)&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;50,000-square&amp;#39;&lt;/span&gt;, 0.4356396794319153&lt;span class="o"&gt;)&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;3,000-square&amp;#39;&lt;/span&gt;, 0.43486514687538147&lt;span class="o"&gt;)&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;30,000-square&amp;#39;&lt;/span&gt;, 0.4330596923828125&lt;span class="o"&gt;)&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;footed&amp;#39;&lt;/span&gt;, 0.43236875534057617&lt;span class="o"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;语义多义性&lt;/strong&gt;的干扰
&lt;ul&gt;
&lt;li&gt;上面也提到，&lt;code&gt;foot&lt;/code&gt;也是计量单位”英尺“的英文，和&lt;code&gt;square&lt;/code&gt;组合是合理的&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;训练语料的偏见&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;既然&lt;code&gt;foot&lt;/code&gt;有多个释义，但输出却全是其“英尺”的意思，那么这可能体现了用来训练的语料中多是&lt;code&gt;...square&lt;/code&gt;和&lt;code&gt;foot&lt;/code&gt;相关联&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;词的选择
&lt;ul&gt;
&lt;li&gt;即使输出全是&lt;code&gt;...square&lt;/code&gt;，其score值也不过0.5，这不仅说明模型找不到强相关的词，而且说明了模型很可能没能理解&lt;code&gt;glove&lt;/code&gt;与&lt;code&gt;hand, foot&lt;/code&gt;的联系&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="neural-network"&gt;Neural Network
&lt;/h2&gt;&lt;p&gt;&lt;em&gt;A neural network = running several logistic regressions at the same time.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://cs231n.github.io/neural-networks-1/" target="_blank" rel="noopener"
 &gt;CS231n Deep Learning on Network Architectures&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://cs231n.github.io/optimization-2/" target="_blank" rel="noopener"
 &gt;CS231n Deep Learning for Computer Vision on Backprop&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="structure"&gt;Structure
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/neural-network-1.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/neural-network-2.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="non-linearities"&gt;Non-linearities
&lt;/h3&gt;&lt;p&gt;为什么神经网络需要非线性(Non-linearities)？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;核心观点：神经网络执行函数逼近，例如回归或分类。
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;没有非线性&lt;/strong&gt;：深度神经网络只能执行&lt;strong&gt;线性变换&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多层失效&lt;/strong&gt;：额外的层会被压缩成单个线性变换：$W_1 W_2 x = Wx$（即多层线性层等同于一层）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;有了非线性&lt;/strong&gt;：通过包含非线性的多层结构，网络可以逼近更复杂的函数！&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/neural-network-3.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;左下侧图对&lt;/strong&gt;：左图显示线性分类（只能画直线），无法区分复杂的红绿点分布；右图显示非线性分类（可以画曲线），完美分割了数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;右侧三张波形图&lt;/strong&gt;：展示了随着函数复杂度的增加，只有非线性模型才能拟合这些起伏的蓝点（观测数据）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关于常用的非线性函数，在《智能计算系统》课上均有学习，不多赘述&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/neural-network-4.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="gradients"&gt;Gradients
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://cs231n.stanford.edu/handouts/derivatives.pdf" target="_blank" rel="noopener"
 &gt;derivatives.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;梯度，简单地讲就是对变量的微积分，比如我们有：
&lt;/p&gt;
$$
f(x)=x^3
$$&lt;p&gt;
那么它的梯度就是：
&lt;/p&gt;
$$
\frac{df}{dx}=3x^2
$$&lt;p&gt;
当然，这只是个非常简单的例子，实际上是大规模的&lt;strong&gt;链式法则&lt;/strong&gt;计算，对矩阵(Jacabian Matrix)进行梯度计算。&lt;/p&gt;
&lt;h4 id="chain-rule"&gt;Chain Rule
&lt;/h4&gt;&lt;p&gt;在单变量微积分中，如果 $y = f(u)$ 且 $u = g(x)$，那么：
&lt;/p&gt;
$$
\frac{dy}{dx} = \frac{dy}{du} \cdot \frac{du}{dx}
$$&lt;p&gt;
但在神经网络中，每一层都是一个向量 $\mathbf{h,z} \in \mathbb{R}^n$。当我们将这个逻辑扩展到向量时，乘法就变成了&lt;strong&gt;矩阵乘法&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;对于多个变量，应与&lt;strong&gt;Jacobians矩阵相乘&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;假设有 $\mathbf h= f(z)$ 和 $\mathbf z=Wx+b$ ，下面的这些偏导数就是雅可比矩阵
&lt;/p&gt;
$$
\frac{\partial \mathbf{h}}{\partial \mathbf{x}} = \frac{\partial \mathbf{h}}{\partial \mathbf{z}} \frac{\partial \mathbf{z}}{\partial \mathbf{x}}
$$&lt;h4 id="matrix-calculus"&gt;Matrix Calculus
&lt;/h4&gt;&lt;p&gt;由下式得，矩阵只有对角元素，其余部分均为0：
&lt;/p&gt;
$$
\begin{aligned} \left( \frac{\partial \mathbf{h}}{\partial \mathbf{z}} \right)_{ij} &amp;= \frac{\partial h_i}{\partial z_j} = \frac{\partial}{\partial z_j} f(z_i) \quad &amp;&amp; \text{definition of Jacobian} \\ &amp;= \begin{cases} f'(z_i) &amp; \text{if } i = j \\ 0 &amp; \text{if otherwise} \end{cases} \quad &amp;&amp; \text{regular 1-variable derivative} \end{aligned}
$$$$
\frac{\partial \mathbf h}{\partial \mathbf z} = 
\begin{pmatrix}
f'(z_1) &amp; 0 &amp; \cdots &amp; 0 \\
0 &amp; f'(z_2) &amp; \cdots &amp; 0 \\
\vdots &amp; \vdots &amp; \ddots &amp; \vdots \\
0 &amp; 0 &amp; \cdots &amp; f'(z_n)
\end{pmatrix}
= \operatorname{diag}(f'(\mathbf z))
$$&lt;p&gt;此外，还有一常有的Jacobian：
&lt;/p&gt;
$$
\frac{\partial}{\partial \mathbf{u}}(\mathbf{u}^T \mathbf{h})=\mathbf h^T
$$&lt;p&gt;
假设 $\mathbf{u}$ 和 $\mathbf{h}$ 都是 $n$ 维列向量：
&lt;/p&gt;
$$
\mathbf{u} = \begin{bmatrix} u_1 \\ u_2 \\ \vdots \\ u_n \end{bmatrix}, \quad \mathbf{h} = \begin{bmatrix} h_1 \\ h_2 \\ \vdots \\ h_n \end{bmatrix}
$$&lt;p&gt;
那么它们的内积（也就是括号里的部分）是一个&lt;strong&gt;标量&lt;/strong&gt;：
&lt;/p&gt;
$$
f = \mathbf{u}^T \mathbf{h} = u_1 h_1 + u_2 h_2 + \dots + u_n h_n = \sum_{i=1}^n u_i h_i
$$&lt;p&gt;
我们要对向量 $\mathbf{u}$ 求导。根据 Jacobian Matrix 的定义，我们需要对 $\mathbf{u}$ 中的每一个元素 $u_k$ 分别求导：
&lt;/p&gt;
$$
\frac{\partial f}{\partial u_k} = \frac{\partial}{\partial u_k} (u_1 h_1 + \dots + u_k h_k + \dots + u_n h_n)
$$&lt;p&gt;
由于除了 $u_k h_k$ 这一项外，其他项都不包含 $u_k$，所以它们对 $u_k$ 的导数都是 $0$：
&lt;/p&gt;
$$
\frac{\partial f}{\partial u_k} = h_k
$$&lt;p&gt;
按照 &lt;strong&gt;Jacobian 矩阵的惯例&lt;/strong&gt;，一个标量对一个&lt;strong&gt;列向量&lt;/strong&gt;求导，结果是一个&lt;strong&gt;行向量&lt;/strong&gt;：
&lt;/p&gt;
$$
\frac{\partial f}{\partial \mathbf{u}} = \begin{bmatrix} \frac{\partial f}{\partial u_1} &amp; \frac{\partial f}{\partial u_2} &amp; \dots &amp; \frac{\partial f}{\partial u_n} \end{bmatrix} = \begin{bmatrix} h_1 &amp; h_2 &amp; \dots &amp; h_n \end{bmatrix} = \mathbf{h}^T
$$&lt;h5 id="write-out-the-jacobians"&gt;Write out the Jacobians
&lt;/h5&gt;$$
\begin{aligned} \frac{\partial s}{\partial \mathbf{b}} &amp;= \frac{\partial s}{\partial \mathbf{h}} \frac{\partial \mathbf{h}}{\partial \mathbf{z}} \frac{\partial \mathbf{z}}{\partial \mathbf{b}} \\ &amp;= \mathbf{u}^T \text{diag}(f'(\mathbf{z})) \mathbf{I} \\ &amp;= \mathbf{u}^T \odot f'(\mathbf{z}) \end{aligned}
$$&lt;p&gt;$\odot$ = Hadamard product = element-wise multiplication of 2 vectors to give vector&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;变量&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;神经网络中的含义&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;说明&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;$s$&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;损失函数值 (Loss/Score)&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;最终的标量输出（例如交叉熵损失）。我们要看它随参数如何变化。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;$\mathbf{b}$&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;偏置向量 (Bias)&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;当前层的偏置项，神经网络需要学习的参数之一。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;$\mathbf{z}$&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;净输入 (Logits/Pre-activation)&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;线性组合后的结果，即 $\mathbf{z} = \mathbf{W}\mathbf{x} + \mathbf{b}$。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;$\mathbf{h}$&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;激活值 (Activation/Hidden state)&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;$\mathbf{z}$ 经过非线性激活函数后的输出，即 $\mathbf{h} = f(\mathbf{z})$。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;$\mathbf{u}^T$&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;上游传回的梯度 ($\frac{\partial s}{\partial \mathbf{h}}$)&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;损失函数对当前层输出的导数，它是从更高层“反向传播”回来的信号。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;$f'(\mathbf{z})$&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;激活函数的导数&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;比如 ReLU 或 Sigmoid 的导数。它决定了哪些神经元处于活跃状态。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;$\mathbf{I}$&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;单位矩阵 (Identity Matrix)&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;因为 $\mathbf{z} = \dots + \mathbf{b}$，$\mathbf{z}$ 对 $\mathbf{b}$ 求导的结果是 1（矩阵形式即为单位阵）。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h5 id="re-using-computation"&gt;Re-using Computation
&lt;/h5&gt;&lt;p&gt;误差信号（Upstream Gradient）$\boldsymbol{\delta}$：
&lt;/p&gt;
$$
\boldsymbol{\delta} = \frac{\partial s}{\partial \mathbf{h}} \frac{\partial \mathbf{h}}{\partial \mathbf{z}} = \mathbf{u}^T \circ f'(\mathbf{z})
$$&lt;p&gt;
我们先算出这个值$\boldsymbol{\delta}$ ，可以简化计算：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;对权重矩阵 $W$ 的梯度展开：
&lt;/p&gt;
$$
 \frac{\partial s}{\partial \mathbf{W}} = \boldsymbol{\delta} \frac{\partial \mathbf{z}}{\partial \mathbf{W}}
 $$&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对偏置向量 $\mathbf{b}$ 的梯度简化：
&lt;/p&gt;
$$
 \frac{\partial s}{\partial \mathbf{b}} = \boldsymbol{\delta} \frac{\partial \mathbf{z}}{\partial \mathbf{b}} = \boldsymbol{\delta}
 $$&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id="shape-convention"&gt;Shape Convention
&lt;/h4&gt;&lt;p&gt;假设权重 $\mathbf{W} \in \mathbb{R}^{n \times m}$，输出是一个标量 $s$（损失）。按纯数学定义，$\frac{\partial s}{\partial \mathbf{W}}$ 应该是一个 $1 \times nm$ 的行向量（Jacobian）。但如果使用这种形式，梯度更新公式 $\theta^{new} = \theta^{old} - \alpha \nabla_{\theta} J(\theta)$ 就会因维度不匹配而无法直接相减。&lt;/p&gt;
&lt;p&gt;为了计算方便，我们约定&lt;strong&gt;梯度的形状必须等于参数的形状&lt;/strong&gt;。因此 $\frac{\partial s}{\partial \mathbf{W}}$ 也是一个 $n \times m$ 的矩阵：
&lt;/p&gt;
$$
\frac{\partial s}{\partial \mathbf{W}} = \begin{bmatrix} \frac{\partial s}{\partial W_{11}} &amp; \dots &amp; \frac{\partial s}{\partial W_{1m}} \\ \vdots &amp; \ddots &amp; \vdots \\ \frac{\partial s}{\partial W_{n1}} &amp; \dots &amp; \frac{\partial s}{\partial W_{nm}} \end{bmatrix}
$$$$
\frac{\partial s}{\partial \mathbf{W}} = \boldsymbol{\delta}^T \mathbf{x}^T
$$&lt;p&gt;那么我们究竟应该以什么样的“形状”来呈现导数结果？&lt;/p&gt;
&lt;p&gt;采取始终遵循**形状约定 (Shape Convention)**的方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;做法&lt;/strong&gt;：不拘泥于严格的 Jacobian 定义，而是时刻盯着变量的维度（Dimensions）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;核心技巧&lt;/strong&gt;：通过观察维度来决定何时需要对某个项进行转置，或者调整矩阵相乘的顺序，以确保每一层算出来的梯度形状和该层的参数形状完全一致。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;关于 $\boldsymbol{\delta}$ 的重要结论&lt;/strong&gt;：传导至隐层（Hidden layer）的误差信号 $\boldsymbol{\delta}$，其维度应该与该隐层的神经元数量（即激活值向量的维度）完全相同。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="backpropagation"&gt;Backpropagation
&lt;/h3&gt;&lt;p&gt;按流程逐步计算各函数，从输入得到输出，即是&lt;strong&gt;正向传播(Forward Propagation)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/backpropagation-1.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;对于反向传播中的单个节点，有$downstream\ gradient=upstream\ gradient\times local\ gradient$&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/backpropagation-2.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;对于单节点的多输入，upstream gradient不变，各输入的local gradient不同，但计算公式是不变的&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/backpropagation-3.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;下面举个多输入的实际例子&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/backpropagation-4.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;我们可以在这个基础上，假设输入y的值变为了2.1，那么$a=x+y=3.1$，$b=max(y+z)=y=2.1$，$a\times b=6.51$&lt;/p&gt;
&lt;p&gt;所以，y值变化的0.1导致了结果0.51的变化，那么梯度就是$\frac{\Delta f}{\Delta y}=5.1$&lt;/p&gt;
&lt;h4 id="implementations"&gt;Implementations
&lt;/h4&gt;&lt;p&gt;那么理论上，在已知正向传播的符号和计算的情况下，计算机可以自动得出反向传播的结果。但是在现代框架中，用户需手动设计局部导数的结算，这也比全自动方式提升了系统的运行效率和稳定性。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MultiplyGate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="c1"&gt;# must keep these around!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dz&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;dz&lt;/span&gt; &lt;span class="c1"&gt;# [dz/dx * dL/dz]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;dz&lt;/span&gt; &lt;span class="c1"&gt;# [dz/dy * dL/dz]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dy&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="numeric-gradient-checking"&gt;Numeric Gradient Checking
&lt;/h5&gt;&lt;p&gt;在手动推导和实现反向传播（Backprop）时，这是确保你数学公式没推错、代码没写错的标准验证方法：
&lt;/p&gt;
$$
f'(x) \approx \frac{f(x + h) - f(x - h)}{2h}
$$&lt;ul&gt;
&lt;li&gt;只需要前向传播函数 $f(x)$ 即可计算，不需要任何复杂的数学推导，不容易写错。&lt;/li&gt;
&lt;li&gt;必须对模型的&lt;strong&gt;每一个参数&lt;/strong&gt;分别进行两次前向传播（加 $h$ 和减 $h$），效率很低。&lt;/li&gt;
&lt;li&gt;适合局部测试，不要对整个大型网络做验证，只针对某个特定层或小规模参数（如一个 $3 \times 3$ 的矩阵）进行。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="dependency-parsing"&gt;Dependency Parsing
&lt;/h2&gt;&lt;h3 id="syntactic-structure"&gt;Syntactic Structure
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Phrase structure&lt;/strong&gt; organizes words into nested constituents.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们可以自己定义phrase构成的语法，比如名词短语可以是“&lt;em&gt;限定词 + 形容词 + 名词&lt;/em&gt;”，“&lt;em&gt;限定词 + 名词 + 介词短语&lt;/em&gt;”……介词短语可以是“&lt;em&gt;介词 + 名词&lt;/em&gt;……”&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dependency structure&lt;/strong&gt; shows which words depend on (modify, attach to, or are arguments of) which other words&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;语言中很容易出现歧义(ambiguity)，在英语里有了介词短语，歧义就更多了，举个例子：&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Scientists count whales from space&amp;quot;可以理解为&amp;quot;Scientists [count] [whales from space]&amp;rdquo; 或者 &amp;ldquo;Scientists [count whales] [from space]&amp;rdquo; ……&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/dependency-1.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h3 id="dependency-grammar-and-treebanks"&gt;Dependency Grammar and Treebanks
&lt;/h3&gt;&lt;p&gt;Dependency syntax postulates that syntactic structure consists of relations between
lexical items, normally binary asymmetric relations (“arrows”) called dependencies&lt;/p&gt;
&lt;p&gt;下图是个比较古老的&amp;quot;dependency structure&amp;quot;&lt;/p&gt;
&lt;p&gt;An arrow connects a head (governor, superior, regent) with a dependent (modifier, inferior, subordinate)&lt;/p&gt;
&lt;p&gt;Usually, dependencies form a tree (a connected, acyclic, single-root graph)&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/dependency-2.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="annotated-data"&gt;Annotated Data
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/dependency-3.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;起初，构建语言库（Treebank）似乎比手动编写语法规则要慢得多，且看起来没那么有用。手动标注数据确实是件麻烦的工作，但现在看来，却有很大的优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;复用性(Reusability)：一套标注好的数据可以用来训练多种解析器（Parsers）、词性标注器（POS Taggers）&lt;/li&gt;
&lt;li&gt;覆盖面广(Board coverage)：手动编写规则往往只能覆盖几个直觉上的例子，而标注真实语料可以涵盖语言在现实中的各种复杂用法。&lt;/li&gt;
&lt;li&gt;频率与分布信息(Frequencies and distributional information)：它能告诉机器哪些结构更常见，帮助概率模型做出更准确的判断。&lt;/li&gt;
&lt;li&gt;评估NLP(A way to evaluate NLP systems)：没有这套“标准”，我们就无法衡量一个 AI 模型的准确率（如 LAS/UAS 得分）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;那么关于示例图中的各依存关系的意思，如下：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;缩写&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;意思&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;简单理解&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;nsubj&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;名词主语&lt;/td&gt;
					&lt;td&gt;动作的发出者（如 &lt;strong&gt;I&lt;/strong&gt; think）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;nsubjpass&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;被动主语&lt;/td&gt;
					&lt;td&gt;被动语态里的主语（如 &lt;strong&gt;city&lt;/strong&gt; called）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;ccomp&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;从句&lt;/td&gt;
					&lt;td&gt;动词后面的整个小句子（如 think &lt;strong&gt;&amp;hellip;&lt;/strong&gt;）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;advmod&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;状语修饰&lt;/td&gt;
					&lt;td&gt;修饰动词的程度、疑问等（如 &lt;strong&gt;Why&lt;/strong&gt;）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;amod&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;形容词修饰&lt;/td&gt;
					&lt;td&gt;修饰名词的形容词（如 &lt;strong&gt;famous&lt;/strong&gt; goat）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;compound&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;复合修饰&lt;/td&gt;
					&lt;td&gt;名词修饰名词（如 &lt;strong&gt;goat&lt;/strong&gt; trainer）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;det&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;限定关系&lt;/td&gt;
					&lt;td&gt;指向 a, the, any 等词&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;case&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;介词关系&lt;/td&gt;
					&lt;td&gt;指向 in, at 等介词&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;conj&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;并列关系&lt;/td&gt;
					&lt;td&gt;用 or, and 连接的词（如 trainer or &lt;strong&gt;something&lt;/strong&gt;）&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id="dependency-conditioning-preferences"&gt;Dependency Conditioning Preferences
&lt;/h4&gt;&lt;p&gt;在进行句法分析时，计算机会根据“依存条件偏好（Dependency Conditioning Preferences）”来判断两个词之间是否存在依存关系：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;双词亲和力 (Bilexical affinities)：依存关系（例如 [discussion → issues]）是合理的。&lt;/li&gt;
&lt;li&gt;依存距离 (Dependency distance)：大多数（但并非所有）依存关系发生在邻近的单词之间。&lt;/li&gt;
&lt;li&gt;介入材料 (Intervening material)：依存关系很少跨越中间的动词或标点符号。&lt;/li&gt;
&lt;li&gt;中心词的价态 (Valency of heads)：对于一个中心词（Head）来说，通常在它的哪一侧会有多少个依存词？&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="projectivity"&gt;Projectivity
&lt;/h4&gt;&lt;p&gt;如果一个句子的单词按线性顺序排列，且所有的依存弧（dependency arcs）都画在单词上方时，&lt;strong&gt;没有任何两条弧线发生交叉&lt;/strong&gt;，那么这个解析就是“投影的”。那么互出现了交叉，就是非投影的(non-projectivity)，说明发生了“长距离位移”或结构重叠。&lt;/p&gt;
&lt;p&gt;但是现实中非投影的例子很常见，比如&amp;quot;&lt;em&gt;Who did Bill buy the coffee from yesterday&lt;/em&gt;&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/dependency-4.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h3 id="transition-based-dependency-parser"&gt;Transition-Based Dependency Parser
&lt;/h3&gt;&lt;p&gt;首先，这Transition-Based Dependency Parser分有一个Stack和一个Buffer，和三种操作：&lt;/p&gt;
&lt;p&gt;Start: $\sigma = [ROOT], \beta = w_1, ..., w_n, A = \emptyset$&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Shift: $\sigma, w_i | \beta, A \Rightarrow \sigma | w_i, \beta, A $&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Left-$Arc_r$: $\sigma | w_i | w_j, \beta, A \Rightarrow \sigma | w_j, \beta, A \cup \{r(w_j, w_i)\} $&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Right-$Arc_r$: $\sigma | w_i | w_j, \beta, A \Rightarrow \sigma | w_j, \beta, A \cup \{r(w_i, w_j)\}$&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Finish: $\sigma = [w], \beta = \emptyset$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;σ&lt;/strong&gt;（sigma）表示 &lt;strong&gt;堆栈（stack）&lt;/strong&gt;，存储当前正在处理或等待建立关系的词。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;β&lt;/strong&gt;（beta）表示 &lt;strong&gt;缓冲区（buffer）&lt;/strong&gt;，存储尚未处理的输入词序列。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A&lt;/strong&gt; 表示 &lt;strong&gt;依存弧集合（set of dependency arcs）&lt;/strong&gt;，存储已建立的依存关系。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Left-$Arc_r$ 和 Right-$Arc_r$ 是两种规约模型，用来表明一个词是另一个的依存词，以左或右方向。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;那么下面先来举个例子：Analysis of &amp;ldquo;&lt;em&gt;I ate fish&lt;/em&gt;&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/dependency-5.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Left Arc&lt;/strong&gt;操作 生成了一个由栈顶指向第二个元素的弧，建立了&amp;quot;&lt;code&gt;ate&lt;/code&gt;&amp;ldquo;是中心词，&amp;ldquo;I&amp;quot;依存于&amp;rdquo;&lt;code&gt;ate&lt;/code&gt;&amp;ldquo;的关系。然后将&amp;rdquo;&lt;code&gt;I&lt;/code&gt;&amp;ldquo;移出栈。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shift&lt;/strong&gt;操作 将&amp;rdquo;&lt;code&gt;fish&lt;/code&gt;&amp;ldquo;从缓冲区移入栈中&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Right Arc&lt;/strong&gt;操作 生成了一个由第二个元素指向栈顶元素的弧，建立了&amp;rdquo;&lt;code&gt;ate&lt;/code&gt;&amp;ldquo;是中心词,&amp;quot;&lt;code&gt;fish&lt;/code&gt;&amp;ldquo;依存于&amp;rdquo;&lt;code&gt;ate&lt;/code&gt;&amp;ldquo;的关系。然后将&amp;rdquo;&lt;code&gt;fish&lt;/code&gt;&amp;ldquo;移出栈。&lt;/li&gt;
&lt;li&gt;最后的&lt;strong&gt;Right Arc&lt;/strong&gt;操作 使&amp;rdquo;&lt;code&gt;[root]&lt;/code&gt;&amp;ldquo;指向&amp;rdquo;&lt;code&gt;ate&lt;/code&gt;&amp;quot;，并在&amp;rdquo;&lt;code&gt;ate&lt;/code&gt;&amp;ldquo;出栈后，只剩下根节点，操作完成。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="evaluation-of-dependency-parsing"&gt;Evaluation of Dependency Parsing
&lt;/h4&gt;&lt;p&gt;评价依存分析的指标分为&lt;strong&gt;UAS&lt;/strong&gt;（无标签附件分数）和 &lt;strong&gt;LAS&lt;/strong&gt;（有标签附件分数），下面是一个具体的例子: &amp;ldquo;&lt;em&gt;[ROOT] She saw the video lecture.&lt;/em&gt;&amp;quot;，表中&amp;quot;Gold&amp;quot;是标准答案，&amp;ldquo;Parsed&amp;quot;是分析出的答案：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/dependency-6.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可见，UAS计算的是&lt;code&gt;Head&lt;/code&gt;寻找得是否正确，本例中第三个&amp;quot;the&amp;quot;的依存词和标准不符。&lt;/li&gt;
&lt;li&gt;LAS计算的它们之间的关系类型是否标注正确，即&lt;code&gt;Head&lt;/code&gt;和关系标签(&lt;code&gt;label&lt;/code&gt;)都要一致，本例中只有&amp;quot;She&amp;quot;和&amp;quot;saw&amp;quot;是与标准相符的。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="neural-dependency-parsing"&gt;Neural dependency parsing
&lt;/h3&gt;&lt;p&gt;More than 95% of parsing time is consumed by feature computation&lt;/p&gt;
&lt;p&gt;所以，我们可以用神经网络来加速特征提取，当然其方法还是基于上面的基于转移（Transition-based）的神经依存句法分析器。具体使用了了向量化、非线性等深度学习知识搭建出了第一个基于神经网络的依存分析器(2014年)。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/dependency-7.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2 id="recurrent-neural-networks"&gt;Recurrent Neural Networks
&lt;/h2&gt;&lt;h3 id="language-modeling"&gt;Language Modeling
&lt;/h3&gt;&lt;p&gt;语言模型(Language Modeling) 简单地讲就是输入文本（词），输出概率。
&lt;/p&gt;
$$
\begin{aligned}
P(\boldsymbol{x}^{(1)}, \dots, \boldsymbol{x}^{(T)}) &amp;= P(\boldsymbol{x}^{(1)}) \times P(\boldsymbol{x}^{(2)} | \boldsymbol{x}^{(1)}) \times \dots \times P(\boldsymbol{x}^{(T)} | \boldsymbol{x}^{(T-1)}, \dots, \boldsymbol{x}^{(1)}) \\
&amp;= \prod_{t=1}^{T} \underbrace{P(\boldsymbol{x}^{(t)} | \boldsymbol{x}^{(t-1)}, \dots, \boldsymbol{x}^{(1)})}_{\text{This is what our LM provides}}
\end{aligned}
$$&lt;p&gt;
$P(\boldsymbol{x}^{(1)}, \dots, \boldsymbol{x}^{(T)})$ 表示一整个序列（如一句话）出现的概率，通过将联合概率&lt;strong&gt;分解为一系列条件概率的乘积&lt;/strong&gt;（链式法则），我们可以计算序列的概率。语言模型的核心任务就是根据之前的上下文 $\boldsymbol{x}^{(t-1)}, \dots, \boldsymbol{x}^{(1)}$ 来&lt;strong&gt;预测&lt;/strong&gt;下一个 token $\boldsymbol{x}^{(t)}$ 出现的概率。&lt;/p&gt;
&lt;h3 id="n-gram-language-models"&gt;n-gram Language Models
&lt;/h3&gt;&lt;p&gt;An n-gram is a chunk of n consecutive words. n表示由几个词构成一个单位，即n-gram。为实现n-gram Language Models，步骤如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;首先，做一个&lt;strong&gt;马尔可夫假设&lt;/strong&gt;：第 $t+1$ 个词 $x^{(t+1)}$ 仅取决于其前面的 $n-1$ 个词。
&lt;/p&gt;
$$
 P(x^{(t+1)} | x^{(t)}, \dots, x^{(1)}) = P(x^{(t+1)} | \underbrace{x^{(t)}, \dots, x^{(t-n+2)}}_{n-1 \text{ words}}) \quad \text{(assumption)}
 $$&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;利用条件概率的定义，上述公式可以写为 $n$-gram 与 $(n-1)$-gram 概率的比值：
&lt;/p&gt;
$$
 = \frac{P(x^{(t+1)}, x^{(t)}, \dots, x^{(t-n+2)}) \leftarrow \text{prob of a n-gram}}{P(x^{(t)}, \dots, x^{(t-n+2)}) \leftarrow \text{prob of a (n-1)-gram}} \quad \text{(definition of conditional prob)}
 $$&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过在大型文本语料库中&lt;strong&gt;计数 (Counting)&lt;/strong&gt; 它们来统计词组出现的频率，来近似概率：
&lt;/p&gt;
$$
 \approx \frac{\text{count}(x^{(t+1)}, x^{(t)}, \dots, x^{(t-n+2)})}{\text{count}(x^{(t)}, \dots, x^{(t-n+2)})} \quad \text{(statistical approximation)}
 $$&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;举个例子，假设我们有一个4-gram Language Model，要预测最后一个空可能出现的单词：&lt;/p&gt;
&lt;p&gt;&amp;ldquo;&lt;em&gt;as the proctor started the clock, the students opened their &amp;hellip;&amp;hellip;&lt;/em&gt;&amp;rdquo;&lt;/p&gt;
&lt;p&gt;我们只取最后的三个词组成的短语&amp;rdquo;&lt;em&gt;students opened their&lt;/em&gt;&amp;rdquo;
&lt;/p&gt;
$$
P(w\mid students\ opened\ their)=\frac{count(students\ opened\ their\ w)}{count(students\ opened\ their)}
$$&lt;p&gt;
根据语料库，&amp;quot;&lt;em&gt;students opened their books&lt;/em&gt;&amp;ldquo;可能是出现频率最高的，而更符合语境的&amp;rdquo;&lt;em&gt;&amp;hellip;&amp;hellip;exams&lt;/em&gt;&amp;ldquo;出现频率更低&lt;/p&gt;
&lt;h4 id="problems-with-n-gram-language-models"&gt;Problems with n-gram Language Models
&lt;/h4&gt;&lt;p&gt;当使用计数法计算概率，会面临&lt;strong&gt;稀疏性问题&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;如果词组 &amp;ldquo;students opened their $w$&amp;rdquo; 在训练数据中从未出现过，那么对于任何该词 $w$，其概率都将变为 &lt;strong&gt;0&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;通过为词表中的每个词 $w \in V$ 的计数增加一个极小的数值 $\delta$ (平滑化 Smoothing)解决&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果前缀 &amp;ldquo;students opened their&amp;rdquo; 在训练数据中从未出现过，我们将无法计算任何 $w$ 的概率，因为分母为 0。&lt;/p&gt;
&lt;p&gt;不再考虑完整的前缀，而是退而求其次，仅根据更短的上下文（例如 &amp;ldquo;opened their&amp;rdquo;）进行条件概率计算。(回退 Backoff)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;同时也会面临&lt;strong&gt;存储&lt;/strong&gt;的问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;需要存放语料库中所有n-gram的计数&lt;/li&gt;
&lt;li&gt;若是n需要增加，语料库的size也要大幅增加&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="a-fixed-window-neural-language-model"&gt;A fixed-window neural Language Model
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/RNN-1.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;输入层 (Words / One-hot vectors)&lt;/strong&gt;: 输入为单词的 one-hot 向量 $\boldsymbol{x}^{(1)}, \boldsymbol{x}^{(2)}, \boldsymbol{x}^{(3)}, \boldsymbol{x}^{(4)}$。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;嵌入层 (Concatenated word embeddings)&lt;/strong&gt;: 将单词转换为稠密的向量表示（embeddings），并进行拼接：
&lt;/p&gt;
$$
 \boldsymbol{e} = [\boldsymbol{e}^{(1)}; \boldsymbol{e}^{(2)}; \boldsymbol{e}^{(3)}; \boldsymbol{e}^{(4)}]
 $$&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;隐藏层 (Hidden layer)&lt;/strong&gt;: 通过权重矩阵 $W$ 和偏置 $b_1$ 进行线性变换，并经过激活函数 $f$（通常为 tanh 或 ReLU）：
&lt;/p&gt;
$$
 \boldsymbol{h} = f(W\boldsymbol{e} + \boldsymbol{b}_1)
 $$&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;输出层 (Output distribution)&lt;/strong&gt;: 经过权重矩阵 $U$ 和偏置 $b_2$，最后通过 &lt;strong&gt;softmax&lt;/strong&gt; 函数生成词典 $V$ 上的概率分布 $\hat{\boldsymbol{y}}$：
&lt;/p&gt;
$$
 \hat{\boldsymbol{y}} = \text{softmax}(U\boldsymbol{h} + \boldsymbol{b}_2) \in \mathbb{R}^{|V|}
 $$&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;那么相对于n-gram方法，改进了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;解决稀疏性问题&lt;/strong&gt;：不再依赖精确的计数，通过向量空间的相似性来泛化未见过的词组。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;存储优化&lt;/strong&gt;：不需要存储所有观察到的 $n$-gram 频率，只需存储模型参数。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但是仍有问题没能解决：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;固定窗口限制&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;固定的上下文窗口通常太小。&lt;/li&gt;
&lt;li&gt;扩大窗口会线性导致权重矩阵 $W$ 的参数量激增。&lt;/li&gt;
&lt;li&gt;无论窗口多大，它永远无法捕捉超出该范围的长程依赖。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缺乏对称性&lt;/strong&gt;：输入 $\boldsymbol{x}^{(1)}$ 和 $\boldsymbol{x}^{(2)}$ 与矩阵 $W$ 中完全不同的权重相乘，模型处理每个位置输入的方式没有一致性。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="rnn-language-model"&gt;RNN Language Model
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://karpathy.github.io/2015/05/21/rnn-effectiveness/" target="_blank" rel="noopener"
 &gt;The Unreasonable Effectiveness of Recurrent Neural Networks&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/RNN-2.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;RNN 的优点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可以处理&lt;strong&gt;任意长度&lt;/strong&gt;的输入。&lt;/li&gt;
&lt;li&gt;理论上，第 $t$ 步的计算可以使用&lt;strong&gt;很多步之前&lt;/strong&gt;的信息。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模型大小固定&lt;/strong&gt;：增加输入长度不会增加模型参数量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对称性&lt;/strong&gt;：每一步应用相同的权重，处理输入的方式具有一致性。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;RNN 的缺点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;计算速度慢&lt;/strong&gt;：由于是递归计算，无法并行处理。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;实践难题&lt;/strong&gt;：在实际应用中，很难获取到&lt;strong&gt;很多步之前&lt;/strong&gt;的信息（梯度消失/爆炸问题）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="train-an-rnn-language-modle"&gt;Train an RNN Language Modle
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;获取一个大型文本语料库，它是由单词序列组成的：$\boldsymbol{x}^{(1)}, \dots, \boldsymbol{x}^{(T)}$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;将序列输入 RNN-LM，并为&lt;strong&gt;每一个时间步 $t$&lt;/strong&gt; 计算输出分布 $\hat{\boldsymbol{y}}^{(t)}$。这意味着模型在给定目前为止已见单词的情况下，预测&lt;strong&gt;每一个位置&lt;/strong&gt;上可能出现的单词概率分布。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;模型在每一个步长 $t$ 都会产生一个损失，第 $t$ 步的损失函数是预测概率分布 $\hat{\boldsymbol{y}}^{(t)}$ 与&lt;strong&gt;真实的下一个单词&lt;/strong&gt; $\boldsymbol{y}^{(t)}$（即 $\boldsymbol{x}^{(t+1)}$ 的 one-hot 向量）之间的&lt;strong&gt;交叉熵&lt;/strong&gt;
&lt;/p&gt;
$$
 J^{(t)}(\theta) = CE(\boldsymbol{y}^{(t)}, \hat{\boldsymbol{y}}^{(t)}) = - \sum_{w \in V} \boldsymbol{y}^{(t)}_w \log \hat{\boldsymbol{y}}^{(t)}_w = - \log \hat{\boldsymbol{y}}^{(t)}_{\boldsymbol{x}_{t+1}}
 $$&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;为了获得整个训练集的损失，需要将所有步骤的损失取平均值：
&lt;/p&gt;
$$
 J(\theta) = \frac{1}{T} \sum_{t=1}^{T} J^{(t)}(\theta) = \frac{1}{T} \sum_{t=1}^{T} - \log \hat{\boldsymbol{y}}^{(t)}_{\boldsymbol{x}_{t+1}}
 $$&lt;p&gt;
计算损失应用了&lt;strong&gt;Teacher Forcing&lt;/strong&gt;的概念，即并不使用模型在上一步&lt;strong&gt;实际预测&lt;/strong&gt;出的单词作为下一步的输入，而是直接将语料库中的&lt;strong&gt;真实正确答案&lt;/strong&gt;喂给模型。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一次性计算整个语料库 $\boldsymbol{x}^{(1)}, \dots, \boldsymbol{x}^{(T)}$ 的损失（Loss）和梯度（Gradients）在内存方面是&lt;strong&gt;极其昂贵的&lt;/strong&gt;，所以在实际操作中，我们将序列 $\boldsymbol{x}^{(1)}, \dots, \boldsymbol{x}^{(T)}$ 看作是一个个&lt;strong&gt;句子&lt;/strong&gt;或&lt;strong&gt;文档&lt;/strong&gt;，使用随机梯度下降来对一**小块数据 **计算损失和梯度，并立即进行参数更新&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="backpropagation-for-rnn"&gt;Backpropagation for RNN
&lt;/h4&gt;&lt;p&gt;RNN参数的训练，采用&lt;strong&gt;随时间&lt;/strong&gt;的反向传播，沿着时间步 $i = t, \dots, 0$ 反向传播，并在过程中累加梯度。&lt;/p&gt;
&lt;p&gt;由于 $\boldsymbol{W}_h$ 在每一个时间步都是共享的（相同的权重），因此总梯度是每一个时间步产生的梯度之和。
&lt;/p&gt;
$$
\frac{\partial J^{(t)}}{\partial \boldsymbol{W}_h} = \sum_{i=1}^{t} \left. \frac{\partial J^{(t)}}{\partial \boldsymbol{W}_h} \right|_{(i)} \frac{\partial \boldsymbol{W}_h|_{(i)}}{\partial \boldsymbol{W}_h} = \sum_{i=1}^{t} \left. \frac{\partial J^{(t)}}{\partial \boldsymbol{W}_h} \right|_{(i)}
$$&lt;p&gt;
随着序列增长，完整的反向传播计算量极大，且容易出现梯度消失或爆炸问题。在实际应用中，为了提高训练效率，通常会在约 &lt;strong&gt;20 个时间步&lt;/strong&gt;后进行“截断”。&lt;/p&gt;
&lt;h4 id="exploding-gradient"&gt;Exploding Gradient
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;梯度爆炸&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果 $W_h$ 的特征值（大致可以理解为权重的大小）大于 1。&lt;/li&gt;
&lt;li&gt;随着时间步 $T$ 的增加，梯度会呈&lt;strong&gt;指数级增长&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;模型权重会更新得过大，导致网络变得极不稳定，参数值可能会溢出（变成 NaN），训练崩溃。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果在更新模型参数前，梯度的&lt;strong&gt;范数 (norm)&lt;/strong&gt; 超过了预设的某个&lt;strong&gt;阈值&lt;/strong&gt;，则按比例将其缩小，如果 $\|\hat{\boldsymbol{g}}\| \ge threshold$ ，则进行&lt;strong&gt;梯度裁剪&lt;/strong&gt;，梯度裁剪&lt;strong&gt;让模型更新时保持在&lt;/strong&gt;相同的方向&lt;strong&gt;上，但只迈出&lt;/strong&gt;更小的一步：
&lt;/p&gt;
$$
\hat{\boldsymbol{g}} \leftarrow \frac{threshold}{\|\hat{\boldsymbol{g}}\|} \hat{\boldsymbol{g}}
$$&lt;h4 id="vanishing-gradient"&gt;Vanishing Gradient
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;梯度消失&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果 $W_h$ 的特征值小于 1，或者激活函数（如图中提到的 $f$ 或 tanh）的导数小于 1。&lt;/li&gt;
&lt;li&gt;梯度会随着反向传播的步数增加而&lt;strong&gt;指数级减小&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;这对应了提到的 RNN 缺点：&lt;strong&gt;“在实践中，很难获取到很多步之前的信息”&lt;/strong&gt;。当梯度变得极其微小时，远距离的权重更新几乎停滞，模型“忘记”了长期的上下文。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于 vanilla RNN（基础 RNN）来说，学习如何跨越多个时间步长来&lt;strong&gt;保留信息&lt;/strong&gt;实在是太困难了，因为隐藏状态 $\boldsymbol{h}^{(t)}$ 会被不断地&lt;strong&gt;重写&lt;/strong&gt;：
&lt;/p&gt;
$$
\boldsymbol{h}^{(t)} = \sigma(\boldsymbol{W}_h \boldsymbol{h}^{(t-1)} + \boldsymbol{W}_x \boldsymbol{x}^{(t)} + \boldsymbol{b})
$$&lt;p&gt;
所以，我们引入独立记忆 ，如LSTM。或者建立直接连接，如Attention机制。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="long-short-term-memory"&gt;&lt;strong&gt;Long&lt;/strong&gt; &lt;strong&gt;Short-Term&lt;/strong&gt; Memory
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://colah.github.io/posts/2015-08-Understanding-LSTMs/" target="_blank" rel="noopener"
 &gt;Understanding LSTM Networks &amp;ndash; colah&amp;rsquo;s blog&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;遗忘门 (Forget gate)&lt;/strong&gt;：控制从上一个细胞状态中保留什么以及忘记什么。
&lt;/p&gt;
$$
\boldsymbol{f}^{(t)} = \sigma (\boldsymbol{W}_f \boldsymbol{h}^{(t-1)} + \boldsymbol{U}_f \boldsymbol{x}^{(t)} + \boldsymbol{b}_f)
$$&lt;p&gt;
&lt;strong&gt;输入门 (Input gate)&lt;/strong&gt;：控制新细胞内容的哪些部分被写入到细胞中。
&lt;/p&gt;
$$
\boldsymbol{i}^{(t)} = \sigma (\boldsymbol{W}_i \boldsymbol{h}^{(t-1)} + \boldsymbol{U}_i \boldsymbol{x}^{(t)} + \boldsymbol{b}_i)
$$&lt;p&gt;
&lt;strong&gt;输出门 (Output gate)&lt;/strong&gt;：控制细胞的哪些部分被输出到隐藏状态中。
&lt;/p&gt;
$$
\boldsymbol{o}^{(t)} = \sigma (\boldsymbol{W}_o \boldsymbol{h}^{(t-1)} + \boldsymbol{U}_o \boldsymbol{x}^{(t)} + \boldsymbol{b}_o)
$$&lt;p&gt;
&lt;strong&gt;New cell content&lt;/strong&gt;：这是要被写入细胞的新内容（即我们在之前讨论中提到的“候选内容”）。
&lt;/p&gt;
$$
\tilde{\boldsymbol{c}}^{(t)} = \tanh (\boldsymbol{W}_c \boldsymbol{h}^{(t-1)} + \boldsymbol{U}_c \boldsymbol{x}^{(t)} + \boldsymbol{b}_c)
$$&lt;p&gt;
&lt;strong&gt;Cell state&lt;/strong&gt;：擦除（“忘记”）上一个细胞状态中的某些内容，并写入（“输入”）一些新的细胞内容。
&lt;/p&gt;
$$
\boldsymbol{c}^{(t)} = \boldsymbol{f}^{(t)} \odot \boldsymbol{c}^{(t-1)} + \boldsymbol{i}^{(t)} \odot \tilde{\boldsymbol{c}}^{(t)}
$$&lt;p&gt;
&lt;strong&gt;隐藏状态 (Hidden state)&lt;/strong&gt;：从细胞中读取（“输出”）某些内容。
&lt;/p&gt;
$$
\boldsymbol{h}^{(t)} = \boldsymbol{o}^{(t)} \odot \tanh \boldsymbol{c}^{(t)}
$$&lt;h4 id="step-by-step-lstm-walk-through"&gt;Step-by-Step LSTM Walk Through
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/LSTM3-chain.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在上图中，每条线都承载着一个完整的向量，从一个节点的输出指向其他节点的输入。粉色圆圈代表逐点运算，例如向量加法，而黄色方框代表已学习的神经网络层。合并的线条表示连接，而分叉的线条表示其内容被复制，并将副本发送到不同的位置。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/LSTM3-C-line.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;LSTM 的关键在于单元状态，也就是图中贯穿顶部的水平线。&lt;/p&gt;
&lt;p&gt;单元状态就像一条传送带，它沿着整个链条直线传递，只有一些微小的线性交互。信息很容易原封不动地沿着传送带流动。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LSTM 能够对单元状态进行信息添加或移除，这种操作由称为“门”的结构进行精细调控。&lt;/p&gt;
&lt;p&gt;门是一种选择性地允许信息通过的方式。它们由一个 sigmoid 神经网络层和一个逐点乘法运算组成。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/LSTM3-focus-f.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LSTM 的第一步是决定我们要从细胞状态中丢弃什么信息 。这个决定由一个称为“遗忘门层”的 sigmoid 层来做出 。它接收 $h_{t-1}$ 和 $x_t$，并为细胞状态 $C_{t-1}$ 中的每个数字输出一个介于 0 和 1 之间的数值；1 代表“完全保留”，而 0 代表“彻底丢弃” 。&lt;/li&gt;
&lt;li&gt;让我们回到之前那个尝试根据前面所有单词预测下一个单词的语言模型例子 。在这样一个问题中，细胞状态可能包含了当前主语的性别信息，以便模型能使用正确的代词 。当我们看到一个新的主语时，我们会希望忘记旧主语的性别 。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/LSTM3-focus-i.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;下一步是决定我们要将什么新信息存储在细胞状态中 。这包含两个部分。首先，一个称为“输入门层”的 sigmoid 层决定了我们将更新哪些值；接着，一个 $\tanh$ 层创建了一个包含新候选值的向量 $\tilde{C}_t$，这些值可以被添加到状态中。在下一步里，我们将结合这两个部分来对状态进行更新 。&lt;/li&gt;
&lt;li&gt;在我们的语言模型例子中，我们会希望将新主语的性别添加到细胞状态中，以替换我们正在遗忘的旧性别信息 。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/LSTM3-focus-C.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;现在是时候将旧的细胞状态 $C_{t-1}$ 更新为新的细胞状态 $C_t$ 了。前面的步骤已经决定了要做什么，我们只需要去实际执行它 。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;我们将旧状态乘以 $f_t$，以此来忘掉我们之前决定要忘记的信息 。然后我们加上 $i_t * \tilde{C}_t$。这就是新的候选值，根据我们决定更新每个状态值的程度进行了缩放 。&lt;/p&gt;
&lt;p&gt;在语言模型的例子中，正是在这里，我们实际丢弃了关于旧主语性别的信息，并添加了新信息，就像我们在前面步骤中决定的那样 。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/cs224n/LSTM3-focus-o.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;最后，我们需要决定我们要输出什么 。这个输出将基于我们的细胞状态，但会是一个经过过滤的版本 。&lt;/p&gt;
&lt;p&gt;首先，我们运行一个 sigmoid 层，它决定了我们要输出细胞状态的哪些部分 。然后，我们将细胞状态通过 $\tanh$（将值推到 -1 和 1 之间）并将其乘以 sigmoid 门的输出，这样我们就只输出了我们决定输出的部分 。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;以语言模型为例，由于它刚刚处理了一个主语，接下来可能会倾向于输出与谓语动词相关的信息，以预判后续内容。例如，模型可能会输出该主语是单数还是复数，这样如果接下来出现动词，我们就能知道该以何种形式进行词形变化。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="how-does-lstm-solve-vanishing-gradients"&gt;How does LSTM solve vanishing gradients
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;LSTM 架构使得 RNN 更容易在多个时间步长内保留信息。例如，如果某个单元维度的遗忘门设置为 1，输入门设置为 0，那么该单元的信息将被无限期地保留。&lt;/p&gt;
&lt;p&gt;相比之下，普通的 RNN 更难学习一个循环权重矩阵 $W_h$，以保留隐藏状态中的信息。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;尽管梯度消失/爆炸现象无法避免，但对于长距离依赖关系，模型还可以创建更直接、更线性的直通连接。比如ResNet, DenseNet&amp;hellip;&amp;hellip;都在模块之间、层之间不同程度地创建了直接连接。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="bidirectional-rnns"&gt;Bidirectional RNNs
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;传统的单向 RNN 或 LSTM 存在一个明显的局限：在处理序列时，它只能“向左看”（即只利用过去的历史上下文）。然而，在许多 NLP 任务（如情感分类、命名实体识别或句子整体理解）中，当前词的准确含义往往也依赖于“右侧”（未来）的上下文。&lt;/li&gt;
&lt;li&gt;为了解决这个问题，研究者引入了双向架构（通常使用 LSTM 实现，即 BiLSTM）：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;前向 (Forward) RNN&lt;/strong&gt;：按照从左到右的顺序处理输入序列，计算出一系列隐藏状态 $\overrightarrow{h}_t$。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;后向 (Backward) RNN&lt;/strong&gt;：按照从右到左的逆序处理同一个输入序列，计算出一系列隐藏状态 $\overleftarrow{h}_t$。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;拼接状态 (Concatenated State)&lt;/strong&gt;：在每一个时间步 $t$，将前向和后向的隐藏状态拼接在一起，形成该位置的最终表示 $h_t = [\overrightarrow{h}_t; \overleftarrow{h}_t]$。这样，每个词的特征表示就同时包含了整个句子的左侧和右侧完整信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;双向 LSTM 的特征提取能力非常强大，但它&lt;strong&gt;仅适用于能够一次性获取完整输入序列的任务&lt;/strong&gt;（例如对整段文本进行分类，或翻译时的源句子编码）。它&lt;strong&gt;不能&lt;/strong&gt;用于传统的语言模型（Language Modeling），因为语言模型的本质任务是“预测下一个词”，如果允许模型看到右侧的“未来”信息，就违背了自回归预测的初衷。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="neural-machine-translation"&gt;Neural Machine Translation
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;神经机器翻译是 NLP 深度学习领域的第一个巨大成功。NMT 主要是基于 &lt;strong&gt;Sequence-to-Sequence (Seq2Seq)&lt;/strong&gt; 架构，该架构的核心正是由两个 RNN（通常是 LSTM）组成的：&lt;strong&gt;编码器 (Encoder)&lt;/strong&gt; 和 &lt;strong&gt;解码器 (Decoder)&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;Encoder负责读取源语言句子，但在读取过程中它不产生实际的翻译输出，而是不断更新其隐藏状态。当 Encoder 处理完源句子的最后一个词后，其&lt;strong&gt;最终的隐藏状态&lt;/strong&gt;（Final Hidden State）被视作整个句子的语义浓缩。它充当了一个“信息瓶颈”，因为整个源句子的所有复杂含义都必须被压缩进这一个固定维度的向量中。&lt;/li&gt;
&lt;li&gt;Decodere端的 LSTM 本质上是一个&lt;strong&gt;条件语言模型 (Conditional Language Model)&lt;/strong&gt;，初始隐藏状态不再是随机的或全零的，而是被严格赋值为 Encoder 输出的那个“瓶颈”向量。这意味着 Decoder 的所有生成动作都是&lt;strong&gt;以源句子的语义向量为条件&lt;/strong&gt;展开的。
在每一个时间步，它根据当前的隐藏状态输出概率最高的词，并将该词（Feeding in last word）作为下一步的输入继续循环，直到生成句子结束标记 &lt;code&gt;&amp;lt;EOS&amp;gt;&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Pytorch基础</title><link>https://ottercoconut.github.io/p/pytorch%E5%9F%BA%E7%A1%80/</link><pubDate>Thu, 22 Jan 2026 10:49:28 +0800</pubDate><guid>https://ottercoconut.github.io/p/pytorch%E5%9F%BA%E7%A1%80/</guid><description>&lt;p&gt;本篇是对Pytorch基础使用的学习，主要基于B站小土堆的https://www.bilibili.com/video/BV1hE411t7RN/以及Gemini的帮助，除实践外也包含了一些深度学习模型的原理&lt;/p&gt;
&lt;h2 id="dataset"&gt;Dataset
&lt;/h2&gt;&lt;p&gt;An abstract class representing a &lt;code&gt;Dataset&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;All datasets that represent a map from keys to data samples should subclass it. All subclasses should overwrite &lt;code&gt;__getitem__&lt;/code&gt;, supporting fetching a data sample for a given key. Subclasses could also optionally overwrite &lt;code&gt;__len__&lt;/code&gt;, which is expected to return the size of the dataset by many &lt;code&gt;~torch.utils.data.Sampler&lt;/code&gt; implementations and the default options of &lt;code&gt;~torch.utils.data.DataLoader&lt;/code&gt;. Subclasses could also optionally implement &lt;code&gt;__getitems__&lt;/code&gt;, for speedup batched samples loading. This method accepts list of indices of samples of batch and returns list of samples.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;note&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;~torch.utils.data.DataLoader&lt;/code&gt; by default constructs an index sampler that yields integral indices. To make it work with a map-style dataset with non-integral indices/keys, a custom sampler must be provided.&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;一个表示数据集的抽象类。&lt;/p&gt;
&lt;p&gt;所有实现从键（keys）到数据样本（data samples）映射的数据集都应该继承这个类。所有子类都必须重写 &lt;code&gt;__getitem__&lt;/code&gt; 方法，以支持根据给定的键获取数据样本。子类也可以选择性地重写 &lt;code&gt;__len__&lt;/code&gt; 方法，许多 &lt;code&gt;~torch.utils.data.Sampler&lt;/code&gt; 实现和 &lt;code&gt;~torch.utils.data.DataLoader&lt;/code&gt; 的默认选项都需要通过这个方法返回数据集的大小。子类还可以选择性地实现 &lt;code&gt;__getitems__&lt;/code&gt; 方法，以加速批量样本的加载。此方法接受批处理样本的索引列表，并返回样本列表。&lt;/p&gt;
&lt;p&gt;注意&lt;/p&gt;
&lt;p&gt;默认情况下，&lt;code&gt;~torch.utils.data.DataLoader&lt;/code&gt; 会构造一个生成整数索引的采样器。要让其与非整数索引/键的映射式数据集一起工作，必须提供自定义的采样器。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="自定义dataset"&gt;自定义Dataset
&lt;/h3&gt;&lt;p&gt;那么在实际的使用中，比如有一个数据集（我们拿之前用过的fer2013来举例）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;先定义一个数据类继承&lt;code&gt;Dataset&lt;/code&gt;，定义&lt;code&gt;__init__()&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;torch.utils.data&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Dataset&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Dataset&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;root_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label_dir&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;root_dir&lt;/span&gt; &lt;span class="c1"&gt;# 如 fer2013/test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;label_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;label_dir&lt;/span&gt; &lt;span class="c1"&gt;# 如 angry&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;label_dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 路径合并函数 解决跨系统的文件路径问题&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;img_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 如angry文件夹下，所有图片名的string list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;重写&lt;code&gt;__getitem()&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__getitem__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;img_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;img_path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;img_item_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;label_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;img_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 拼接出具体的某一个图片的路径&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img_item_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;label_dir&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="c1"&gt;# 返回数据集中的一个对象（图片）及其类型&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;重写&lt;code&gt;__len()__&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__len__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;img_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;定义示例&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;root_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;fer2013/train&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;angry_label_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;angry&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;angry_dataset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;angry_label_dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dataset合并&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;disguest_label_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;disguest&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;disgust_dataset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;disguest_label_dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;train_dataset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;angry_dataset&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;disgust_dataset&lt;/span&gt; &lt;span class="c1"&gt;# &amp;#39;+&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="tensorboard"&gt;TensorBoard
&lt;/h2&gt;&lt;h3 id="summarywriter"&gt;SummaryWriter
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;创建日志目录&lt;/li&gt;
&lt;li&gt;初始化&lt;code&gt;Writer&lt;/code&gt;对象&lt;/li&gt;
&lt;li&gt;生成事件文件
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;这个文件才是真正的数据库&lt;/strong&gt;(events.out&amp;hellip;&amp;hellip;)当后续调用 &lt;code&gt;writer.add_scalar&lt;/code&gt; 时，数据并不是直接画在屏幕上，而是被追加写进这个文件里。&lt;/li&gt;
&lt;li&gt;当你执行完相应代码，运行 &lt;code&gt;tensorboard --logdir=logs&lt;/code&gt; 时，TensorBoard 的后端服务器就会去读取这个文件里的内容，并在浏览器里渲染成图表。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;torch.utils.tensorboard&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SummaryWriter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SummaryWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;logs&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 这行代码会在你的项目根目录下创建一个名为&amp;#34;logs&amp;#34;的文件夹&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;需注意，每次实验可以用&lt;strong&gt;不同的文件夹来记录数据&lt;/strong&gt;，比如&lt;code&gt;writer = SummaryWriter(&amp;quot;logs/lr0.01_batch32&amp;quot;)&lt;/code&gt;修改了学习率后&lt;code&gt;writer = SummaryWriter(&amp;quot;logs/lr0.001_batch32&amp;quot;)&lt;/code&gt;&lt;/p&gt;
&lt;h4 id="add_scalar"&gt;add_scalar()
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;绘图函数&lt;code&gt;add_scalar()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_scalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;scalar_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# 对应图像的y轴&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;global_step&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# 对应图像的x轴&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;walltime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;new_style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;double_precision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;​```&lt;/span&gt; &lt;span class="n"&gt;例&lt;/span&gt; &lt;span class="err"&gt;```&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_scalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;y=2x&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="add_image"&gt;add_image()
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;查看图片函数&lt;code&gt;add_image()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;img_tensor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;global_step&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;walltime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dataformats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;CHW&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;要注意参数的类型要求：&lt;code&gt;img_tensor (torch.Tensor, numpy.ndarray, or string/blobname): Image data&lt;/code&gt;，所以要将PIL类型的图片进行转换，比如用&lt;code&gt;numpy&lt;/code&gt;来转换。以及数据的shape要求： Tensor with :math:&lt;code&gt;(1, H, W)&lt;/code&gt;, :math:&lt;code&gt;(H, W)&lt;/code&gt;, :math:&lt;code&gt;(H, W, 3)&lt;/code&gt; is also suitable as long as corresponding &lt;code&gt;dataformats&lt;/code&gt; argument is passed, e.g. &lt;code&gt;CHW&lt;/code&gt;, &lt;code&gt;HWC&lt;/code&gt;, &lt;code&gt;HW&lt;/code&gt;. 即三种图片数据的格式，其&lt;strong&gt;通道数、高度、宽度&lt;/strong&gt;的顺序不同。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;img_array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;图像形状: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;img_array&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;test&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;img_array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;dataformats&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;HW&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 由.shape可得&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="add_graph"&gt;add_graph()
&lt;/h4&gt;&lt;hr&gt;
&lt;h2 id="常见的transforms"&gt;常见的Transforms
&lt;/h2&gt;&lt;p&gt;下面基本都是对图像的处理方法&lt;/p&gt;
&lt;h3 id="totensor"&gt;ToTensor
&lt;/h3&gt;&lt;p&gt;Convert a PIL Image or ndarray to tensor and scale the values accordingly.&lt;/p&gt;
&lt;p&gt;This transform does not support torchscript.&lt;/p&gt;
&lt;p&gt;Converts a PIL Image or numpy.ndarray (H x W x C) in the range [0, 255] to a torch.FloatTensor of shape (C x H x W) in the range [0.0, 1.0] if the PIL Image belongs to one of the modes (L, LA, P, I, F, RGB, YCbCr, RGBA, CMYK, 1) or if the numpy.ndarray has dtype = np.uint8&lt;/p&gt;
&lt;p&gt;In the other cases, tensors are returned without scaling.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;note&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Because the input image is scaled to [0.0, 1.0], this transformation should not be used when transforming target image masks. See the [references](vscode-file://vscode-app/d:/Microsoft VS Code/resources/app/out/vs/code/electron-browser/workbench/workbench.html) for implementing the transforms for image masks.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;将PIL图片转为torch类型&lt;/strong&gt;，如&lt;code&gt;torch.Size([1, 48, 48])&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;trans_totensor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;transforms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToTensor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;img_tensor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;trans_totensor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img_tensor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ToTensor&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;img_tensor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="normalize"&gt;Normalize
&lt;/h3&gt;&lt;p&gt;Normalize a tensor image with mean and standard deviation.&lt;/p&gt;
&lt;p&gt;​ This transform does not support PIL Image.&lt;/p&gt;
&lt;p&gt;​ Given mean: &lt;code&gt;(mean[1],...,mean[n])&lt;/code&gt; and std: &lt;code&gt;(std[1],..,std[n])&lt;/code&gt; for &lt;code&gt;n&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;​ channels, this transform will normalize each channel of the input&lt;/p&gt;
&lt;p&gt;​ &lt;code&gt;torch.*Tensor&lt;/code&gt; i.e.,&lt;/p&gt;
&lt;p&gt;​ &lt;code&gt;output[channel] = (input[channel] - mean[channel]) / std[channel]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;note:&lt;/p&gt;
&lt;p&gt;​ This transform acts out of place, i.e., it does not mutate the input tensor.&lt;/p&gt;
&lt;p&gt;Args:&lt;/p&gt;
&lt;p&gt;​ mean (sequence): Sequence of means for each channel.&lt;/p&gt;
&lt;p&gt;​ std (sequence): Sequence of standard deviations for each channel.&lt;/p&gt;
&lt;p&gt;​ inplace(bool,optional): Bool to make this operation in-place.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Normailize&lt;/code&gt; 的数学原理是：&lt;/li&gt;
&lt;/ul&gt;
$$
output = \frac{input-mean}{std}
$$&lt;ul&gt;
&lt;li&gt;参数&lt;code&gt;mean&lt;/code&gt;影响的是“中心位置”，在&lt;code&gt;ToTensor&lt;/code&gt;之后，像素值在 $[0, 1]$ 之间，中心大约在 $0.5$，如&lt;code&gt;mean = 0.5&lt;/code&gt;，那么减去 $0.5$ 后，数据的中心变成了 $0$。原本 $[0, 1]$ 的范围变成了 $[-0.5, 0.5]$&lt;/li&gt;
&lt;li&gt;参数&lt;code&gt;std&lt;/code&gt;影响的是“缩放幅度”，如&lt;code&gt;std = 0.5&lt;/code&gt;，那么就是将数据范围再除以$0.5$，最终范围从 $[-0.5, 0.5]$ 变成了 $[-1, 1]$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="resize"&gt;Resize
&lt;/h3&gt;&lt;p&gt;Resize the input image to the given size.&lt;/p&gt;
&lt;p&gt;​ If the image is torch Tensor, it is expected&lt;/p&gt;
&lt;p&gt;​ to have [&amp;hellip;, H, W] shape, where &amp;hellip; means a maximum of two leading dimensions&lt;/p&gt;
&lt;p&gt;Args:&lt;/p&gt;
&lt;p&gt;​ size (sequence or int): Desired output size. If size is a sequence like&lt;/p&gt;
&lt;p&gt;​ (h, w), output size will be matched to this. If size is an int,&lt;/p&gt;
&lt;p&gt;​ smaller edge of the image will be matched to this number.&lt;/p&gt;
&lt;p&gt;​ i.e, if height &amp;gt; width, then image will be rescaled to&lt;/p&gt;
&lt;p&gt;​ (size * height / width, size).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;resize()&lt;/code&gt;支持PIL和Tensor两种图片格式，如果是 Tensor，期望形状为 &lt;code&gt;[..., H, W]&lt;/code&gt;。这里的 &lt;code&gt;...&lt;/code&gt; 表示它可以处理 &lt;code&gt;[C, H, W]&lt;/code&gt;（单张图）或 &lt;code&gt;[B, C, H, W]&lt;/code&gt;（一个 Batch 的图）&lt;/li&gt;
&lt;li&gt;参数&lt;code&gt;size&lt;/code&gt;需注意写成序列形式，如&lt;code&gt;resize((512, 512))&lt;/code&gt;，而如果只输入一个参数，如&lt;code&gt;resize(512)&lt;/code&gt;，那么图片短边会变为512，而长边会按比例改变&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;trans_resize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;transforms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Resize&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;224&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;224&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;img_resize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;trans_resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img_resize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="compse"&gt;Compse
&lt;/h3&gt;&lt;p&gt;Composes several transforms together. This transform does not support torchscript.&lt;/p&gt;
&lt;p&gt;​ Please, see the note below.&lt;/p&gt;
&lt;p&gt;Args:&lt;/p&gt;
&lt;p&gt;​ transforms (list of &lt;code&gt;Transform&lt;/code&gt; objects): list of transforms to compose.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;compse()&lt;/code&gt;操作是对各种&lt;code&gt;transforms&lt;/code&gt;操作的流水线&lt;strong&gt;类&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;在深度学习中，图片通常需要经过一系列的固定步骤（比如：缩放 -&amp;gt; 转为 Tensor -&amp;gt; 归一化）。如果不用 &lt;code&gt;Compose&lt;/code&gt;，你每一张图都要手动调用多个函数，代码会非常冗余&lt;/li&gt;
&lt;li&gt;&lt;code&gt;compse()&lt;/code&gt;的参数类型是一个列表，操作是按顺序执行的，所以前一个操作输出的数据类型必须能作为下一个操作的输入。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;torchvision&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;transforms&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 定义训练集的预处理&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;train_transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;transforms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Compose&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;transforms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Resize&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;224&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;224&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="c1"&gt;# VGG16标准输入是224x224&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;transforms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RandomHorizontalFlip&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;# 数据增强：随机水平翻转&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;transforms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToTensor&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;# 归一化到 [0.0, 1.0]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;transforms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Normalize&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="c1"&gt;# 标准化到 [-1.0, 1.0]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;img_tensor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;train_transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="pytorch数据集使用"&gt;Pytorch数据集使用
&lt;/h2&gt;&lt;p&gt;例如，我们要导入视觉学习的数据集，可以直接在程序中进行数据集的下载&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;torchvision&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;train_set&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torchvision&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datasets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CIFAR10&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;./dataset...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;test_set&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torchvision&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datasets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CIFAR10&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;./dataset...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;root&lt;/code&gt;参数表示数据集存放的位置，&lt;code&gt;train&lt;/code&gt;参数表示数据集是否用来训练，&lt;code&gt;download&lt;/code&gt;参数表示是否下载到本地（会生成一个下载链接）&lt;/li&gt;
&lt;li&gt;具体的参数设置，每个数据集都可能有所区别&amp;hellip;&amp;hellip;&lt;/li&gt;
&lt;li&gt;如果是下载完成到本地的数据集，可以将其复制到项目目录的dataset文件夹下，再运行程序即可节省下载的时间&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_set&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 可以看到测试数据集的所有类别&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;test_set&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_set&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="c1"&gt;# 输出测试集第一个元素对应的类别&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="dataloader"&gt;DataLoader
&lt;/h2&gt;&lt;p&gt;Data loader combines a dataset and a sampler, and provides an iterable over the given dataset.&lt;/p&gt;
&lt;p&gt;​ The :class:&lt;code&gt;~torch.utils.data.DataLoader&lt;/code&gt; supports both map-style and&lt;/p&gt;
&lt;p&gt;​ iterable-style datasets with single- or multi-process loading, customizing&lt;/p&gt;
&lt;p&gt;​ loading order and optional automatic batching (collation) and memory pinning.&lt;/p&gt;
&lt;p&gt;在训练模型时，不能一次性把数据集中的大量数据塞进内存。&lt;code&gt;DataLoader&lt;/code&gt;实现了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Batching（批处理）：&lt;/strong&gt; 把图片打包成一组组（Batch）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shuffling（打乱）：&lt;/strong&gt; 每一轮训练（Epoch）开始时随机洗牌，防止模型死记硬背数据顺序。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parallel Computing（并行加载）：&lt;/strong&gt; 利用多核 CPU 提前准备下一批数据，不让 GPU 等待。&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;参数名&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;常用取值&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;作用描述&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;dataset&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;自定义 Dataset&lt;/td&gt;
					&lt;td&gt;必填。告诉 DataLoader 从哪个“仓库”取数据。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;batch_size&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;16, 32, 64&amp;hellip;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;每批装载的数量。&lt;/strong&gt; 越大训练越快，但越占显存。在 FER 表情识别中，32 或 64 是常用数值。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;shuffle&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;True&lt;/code&gt; / &lt;code&gt;False&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;是否打乱顺序。&lt;/strong&gt; 训练集通常设为 &lt;code&gt;True&lt;/code&gt;（增加随机性）；测试集通常设为 &lt;code&gt;False&lt;/code&gt;。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;num_workers&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;0, 2, 4, 8&amp;hellip;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;多进程加载。&lt;/strong&gt; &lt;code&gt;0&lt;/code&gt; 表示只用主进程（慢）。增加数值可以加快读取速度。&lt;strong&gt;建议：&lt;/strong&gt; 设为 CPU 核心数的一半。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;drop_last&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;True&lt;/code&gt; / &lt;code&gt;False&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;丢弃最后多余的数据。&lt;/strong&gt; 比如有 100 张图，&lt;code&gt;batch_size=32&lt;/code&gt;。最后剩 4 张不够一包，设为 &lt;code&gt;True&lt;/code&gt; 就会把这 4 张扔掉，确保每个 Batch 大小一致。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;pin_memory&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;True&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;内存锁页。&lt;/strong&gt; 如果你用 GPU 训练，设为 &lt;code&gt;True&lt;/code&gt; 可以加快数据从内存传输到显存的速度。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;例如，我们用&lt;code&gt;DataLoader&lt;/code&gt;处理CIFAR10中的数据&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;test_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torchvision&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datasets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CIFAR10&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;./dataset&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;torchvision&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transforms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToTensor&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;test_loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DataLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;test_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shuffle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_workers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;drop_last&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;结合循环和&lt;code&gt;tensorboard&lt;/code&gt;，输出每一个&lt;code&gt;epoch&lt;/code&gt;中每一&lt;code&gt;step&lt;/code&gt;用到的图片&lt;/li&gt;
&lt;li&gt;下面代码中&lt;code&gt;step + epoch * len(test_loader)&lt;/code&gt;是使用了全局步长，也可以不这样写，而是把每个&lt;code&gt;epoch&lt;/code&gt;来当作一组&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SummaryWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;dataloader&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;epoch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;test_loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;imgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_images&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;test_data_batch&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;imgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;epoch&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_loader&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="nnmodule"&gt;nn.Module
&lt;/h2&gt;&lt;p&gt;Base class for all neural network modules.&lt;/p&gt;
&lt;p&gt;​ Your models should also subclass this class.&lt;/p&gt;
&lt;p&gt;​ Modules can also contain other Modules, allowing to nest them in a tree structure.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在 PyTorch 中，无论是简单的线性层，还是复杂的 VGG16 或 Transformer，本质上都是一个 &lt;code&gt;nn.Module&lt;/code&gt;。它是所有神经网络模块的&lt;strong&gt;基类&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nn.Module&lt;/code&gt; 支持嵌套，当你对大模型调用 &lt;code&gt;model.to(&amp;quot;cuda&amp;quot;)&lt;/code&gt; 时，PyTorch 会顺着这棵“树”，自动把里面所有的子层都搬到 GPU 上。&lt;/li&gt;
&lt;li&gt;只要在 &lt;code&gt;__init__&lt;/code&gt; 中把一个层赋值给 &lt;code&gt;self.xxx&lt;/code&gt;，PyTorch 就会自动识别出其中的&lt;strong&gt;权重 (Weights)&lt;/strong&gt; 和 &lt;strong&gt;偏置 (Bias)&lt;/strong&gt;，并将它们加入到待优化的参数列表中。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;编写一个&lt;code&gt;nn.Module&lt;/code&gt;子类时，必须重写&lt;code&gt;__init()__&lt;/code&gt;和&lt;code&gt;forward()&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;__init(self)__&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;在这里定义网络层（卷积、池化、全连接等）。&lt;/li&gt;
&lt;li&gt;必须调用 &lt;code&gt;super().__init__()&lt;/code&gt;。这行代码的作用是初始化父类的属性，如果没有它，PyTorch 就没法自动追踪定义的层，模型也就无法训练。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;forward(self, x)&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;定义数据的流向。图片进去后，先过哪一层，再过哪一层。&lt;/li&gt;
&lt;li&gt;不需要手动调用 &lt;code&gt;forward&lt;/code&gt;，只需要运行 &lt;code&gt;model(input)&lt;/code&gt;，PyTorch 会自动触发 &lt;code&gt;forward&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;torch&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;torch&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;myModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;# 简单地将输出 +1 再输出&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="卷积-conv"&gt;卷积 Conv
&lt;/h2&gt;$$
\text{out}(N_i, C_{\text{out}_j}) = \text{bias}(C_{\text{out}_j}) +
 \sum_{k = 0}^{C_{\text{in}} - 1} \text{weight}(C_{\text{out}_j}, k) \star \text{input}(N_i, k)
$$&lt;ul&gt;
&lt;li&gt;卷积动画页面：&lt;a class="link" href="https://github.com/vdumoulin/conv_arithmetic/blob/master/README.md" target="_blank" rel="noopener"
 &gt;conv_arithmetic/README.md at master · vdumoulin/conv_arithmetic&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;参数&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;含义&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;作用&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;in_channels&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;输入通道数&lt;/td&gt;
					&lt;td&gt;彩色图通常为 3 (RGB)，灰度图为 1。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;out_channels&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;输出通道数&lt;/td&gt;
					&lt;td&gt;卷积核的数量。有多少个核，输出就有多少层特征图。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;kernel_size&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;卷积核大小&lt;/td&gt;
					&lt;td&gt;提取特征的“窗口”大小。常用 3 或 5（VGG 常用 3）。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;stride&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;步长&lt;/td&gt;
					&lt;td&gt;窗口滑动的跨度。默认为 1。步长越大，输出图片越小。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;padding&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;填充&lt;/td&gt;
					&lt;td&gt;在图片四周补 0。&lt;code&gt;'same'&lt;/code&gt; 保持大小不变，&lt;code&gt;'valid'&lt;/code&gt; 则不补。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;dilation&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;空洞卷积&lt;/td&gt;
					&lt;td&gt;卷积核点之间的间距。用于扩大感受野（不用增加参数量）。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;bias&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;偏置&lt;/td&gt;
					&lt;td&gt;是否在结果上加一个常数偏移。默认开启。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;卷积的Padding（边界扩充）参数很重要，如果周围不补零，那么卷积会导致图像尺寸越来越小&lt;/li&gt;
&lt;li&gt;形状计算公式：&lt;/li&gt;
&lt;/ul&gt;
$$
H_{out} = \left\lfloor\frac{H_{in} + 2 \times \text{padding}[0] - \text{dilation}[0]
 \times (\text{kernel_size}[0] - 1) - 1}{\text{stride}[0]} + 1\right\rfloor
$$&lt;p&gt;$W_{out}$计算同理&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dataset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torchvision&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datasets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CIFAR10&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;./dataset&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;train&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;torchvision&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transforms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToTensor&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dataloader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DataLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;myModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conv1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Conv2d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in_channels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;out_channels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;kernel_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;stride&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conv1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mymodule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;myModule&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# 模型实例化 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dataloader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;imgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mymodule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# torch.Size([64, 3, 32, 32])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# torch.Size([64, 6, 30, 30]) channel == 6 卷积后，channel数变化，不能直接输出图像&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="最大池化-maxpool"&gt;（最大）池化 MaxPool
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;最大池化的逻辑非常简单：在一个窗口（Kernel）范围内，&lt;strong&gt;只保留最大的那个值&lt;/strong&gt;，剩下的全部扔掉&lt;/li&gt;
&lt;li&gt;既保留输入特征，又减小了数据量，加快训练速度&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;参数&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;独特之处&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;kernel_size&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;窗口大小。常见是 &lt;code&gt;2&lt;/code&gt;（即将 $2 \times 2$ 的区域合并）。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;stride&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;默认值等于 kernel_size&lt;/strong&gt;！这和卷积不同。如果 &lt;code&gt;kernel_size=2&lt;/code&gt;，步长默认就是 &lt;code&gt;2&lt;/code&gt;，这样窗口之间就不会重叠。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;ceil_mode&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;非常重要。&lt;/strong&gt; 默认是 &lt;code&gt;False&lt;/code&gt;（向下取整）。如果设为 &lt;code&gt;True&lt;/code&gt;（向上取整），当窗口超出边界时，只要窗口内有数据，就会保留结果，而不是舍弃。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;padding&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;填充。注意池化填充的是&lt;strong&gt;负无穷（$-\infty$）&lt;/strong&gt;，这样是为了保证填充位不会被选为最大值。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tensor&lt;/span&gt;&lt;span class="p"&gt;([[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reshape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;myMoudle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myMoudle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maxpool1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MaxPool2d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kernel_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ceil_mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; ceil_mode = False 就表示只有当池化核遇到的尺寸是最大尺寸（如3x3）时
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; 才会取其池化的结果，否则相反
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maxpool1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mymoudle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;myMoudle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mymoudle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Size&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;tensor&lt;/span&gt;&lt;span class="p"&gt;([[[[&lt;/span&gt;&lt;span class="mf"&gt;2.&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;3.&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;5.&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.&lt;/span&gt;&lt;span class="p"&gt;]]]],&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="损失函数与反向传播"&gt;损失函数与反向传播
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;损失函数用于计算实际输出与目标之间的差距，为反向传播、更新参数提供一定的依据。在分类任务中，常用交叉熵函数来计算误差，&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;loss_func&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CrossEntropyLoss&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="优化器"&gt;优化器
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://docs.pytorch.org/docs/stable/optim.html" target="_blank" rel="noopener"
 &gt;torch.optim — PyTorch 2.10 documentation&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;示例代码：&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zero_grad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# 梯度清零&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;loss_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 调用损失函数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# 反向传播&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="pytorch实战cifar10"&gt;Pytorch实战：CIFAR10
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;针对CIFAR10图像数据集的简单分类模型实战&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/pytorch/Screenshot_2026-01-26_140919.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;首先了解Sequential，&lt;code&gt;nn.Sequential&lt;/code&gt; 是 &lt;code&gt;nn.Module&lt;/code&gt; 的一个特殊子类，它的作用是&lt;strong&gt;自动完成 &lt;code&gt;forward&lt;/code&gt; 逻辑&lt;/strong&gt;。注意：其中每一个参数都是某层的类，所以要写逗号。Sequential既简化了模型定义，也简化了&lt;code&gt;forward()&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CIFAR10_Simple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CIFAR10_Simple&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conv1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Conv2d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in_channels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out_channels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kernel_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; 参数padding的数值可以从想象图像得到：5x5的卷积核，当中心在图像的(0,0)，那么卷积核是扩展出去2格的。上面是简单判断的方法，实际应该用尺寸计算公式来代入计算（参考“Conv卷积”节内容）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model_s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Sequential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Conv2d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in_channels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out_channels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kernel_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReLU&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MaxPool2d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kernel_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Conv2d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in_channels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out_channels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kernel_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReLU&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MaxPool2d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Conv2d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReLU&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MaxPool2d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Flatten&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Linear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReLU&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Linear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; x = self.conv1(x)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; x = self.maxpool1(x)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; x = self.conv2(x)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; x = self.maxpool2(x)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; x = self.conv3(x)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; x = self.maxpool3(x)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; x = self.flatten(x)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; x = self.linear1(x)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; x = self.linear2(x)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;model_s&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在搭建模型前，先设置&lt;code&gt;DataLoader&lt;/code&gt;处理数据集&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;分别设置好&lt;code&gt;train_data&lt;/code&gt;和&lt;code&gt;test_data&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dataset_transfrom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Compose&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToTensor&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Normalize&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;),(&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;))])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;train_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torchvision&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datasets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CIFAR10&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;./dataset&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dataset_transfrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;test_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torchvision&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datasets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CIFAR10&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;./dataset&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dataset_transfrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;download&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# --------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;train_loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DataLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;train_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shuffle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;drop_last&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;test_loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DataLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;test_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shuffle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;drop_last&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;搭建好模型后，简单测试输出尺寸是否符合要求&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;cifar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CIFAR10_Simple&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cifar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# 同数据集图片尺寸的测试&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cifar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;训练前的基本设置
&lt;ul&gt;
&lt;li&gt;定义&lt;code&gt;TensorBoard&lt;/code&gt;的&lt;code&gt;writer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;设置&lt;code&gt;device&lt;/code&gt;调用显卡加速训练&lt;/li&gt;
&lt;li&gt;实例化训练模型&lt;/li&gt;
&lt;li&gt;定义损失函数&lt;/li&gt;
&lt;li&gt;设置优化器&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SummaryWriter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;./logs&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_graph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cifar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;cuda&amp;#34;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cuda&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_available&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;cpu&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CIFAR10_Simple&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;loss_func&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CrossEntropyLoss&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# 交叉熵损失函数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;optim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;optim&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SGD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cifar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 学习率&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;训练部分
&lt;ul&gt;
&lt;li&gt;优化器的定式代码&lt;/li&gt;
&lt;li&gt;记录训练损失&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;total_step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;epoch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# --- 训练部分 ---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;train_loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;imgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;loss_func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;optim&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zero_grad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;optim&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 记录训练损失&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_scalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Train_Loss&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;total_step&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;total_step&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;评估部分
&lt;ul&gt;
&lt;li&gt;每个epoch执行一次&lt;/li&gt;
&lt;li&gt;&lt;code&gt;with torch.no_grad()&lt;/code&gt;：关闭梯度记录&lt;/li&gt;
&lt;li&gt;统计性能指标&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;total_test_loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;total_accuracy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;no_grad&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="c1"&gt;# 测试时不需要计算梯度，节省性能&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;test_loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;imgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;imgs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;imgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;imgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 计算总损失&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;loss_func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;total_test_loss&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 计算准确率：argmax(1) 找到概率最大的类别索引&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;accuracy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;total_accuracy&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;accuracy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;可视化&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 输出到 TensorBoard&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_scalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Test_Loss&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total_test_loss&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_loader&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;epoch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_scalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Test_Accuracy&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total_accuracy&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;epoch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Epoch &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;epoch&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; 结束，准确率: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;total_accuracy&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item><item><title>数据挖掘</title><link>https://ottercoconut.github.io/p/%E6%95%B0%E6%8D%AE%E6%8C%96%E6%8E%98/</link><pubDate>Sun, 23 Nov 2025 21:42:00 +0800</pubDate><guid>https://ottercoconut.github.io/p/%E6%95%B0%E6%8D%AE%E6%8C%96%E6%8E%98/</guid><description>&lt;h3 id="数据挖掘复习"&gt;数据挖掘复习
&lt;/h3&gt;&lt;p&gt;内容来自PPT及最后课上画的重点信息&lt;/p&gt;
&lt;h4 id="复习题ppt"&gt;复习题PPT
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;数据挖掘中的关联规则挖掘主要用来发现数据项之间的什么关系？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;关联规则挖掘主要用来发现数据项之间的频繁共存或隐含的关联关系。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;聚类分析中，K-means算法的K值表示什么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在K-means聚类算法中，K值表示用户期望将数据集划分成的簇的数量。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;决策树有哪些算法？主要根据什么标准选择特征进行划分，并分析各标准的不足之处。&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;算法&lt;/th&gt;
					&lt;th&gt;标准&lt;/th&gt;
					&lt;th&gt;不足&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;ID3&lt;/td&gt;
					&lt;td&gt;信息增益&lt;/td&gt;
					&lt;td&gt;强烈偏好多值特征，容易过拟合&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;C4.5&lt;/td&gt;
					&lt;td&gt;信息增益率&lt;/td&gt;
					&lt;td&gt;计算更复杂，可能偏好少值特征&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;CART&lt;/td&gt;
					&lt;td&gt;基尼指数&lt;/td&gt;
					&lt;td&gt;对多值特征有轻微偏好，倾向于不平衡分裂&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;给定一个简单的文本分类训练集，用于判断邮件是否为“垃圾邮件(Spam)”。词典包含以下5个词语：&lt;/strong&gt;
&lt;code&gt;[&amp;quot;deal&amp;quot;, &amp;quot;money&amp;quot;, &amp;quot;urgent&amp;quot;, &amp;quot;meeting&amp;quot;, &amp;quot;free&amp;quot;]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;训练数据：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;垃圾邮件 (Spam, S)&lt;/strong&gt;：
&lt;ol&gt;
&lt;li&gt;&amp;ldquo;deal free money&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;urgent free deal&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;money urgent free&amp;rdquo;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;非垃圾邮件 (Ham, H)&lt;/strong&gt;：
&lt;ol&gt;
&lt;li&gt;&amp;ldquo;meeting deal&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;urgent meeting&amp;rdquo;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;待分类的新邮件内容为：&lt;/strong&gt;
&amp;ldquo;free urgent meeting&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;任务要求：&lt;/strong&gt;
使用多项式朴素贝叶斯模型（应用拉普拉斯平滑，其中平滑参数 λ=1&lt;em&gt;λ&lt;/em&gt;=1）对该邮件进行分类。请按步骤完成以下计算：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;计算先验概率 P(Spam)&lt;em&gt;P&lt;/em&gt;(&lt;em&gt;Spam&lt;/em&gt;) 和 P(Ham)&lt;em&gt;P&lt;/em&gt;(&lt;em&gt;Ham&lt;/em&gt;)。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;文档总数：
$N_{\text{doc}} = 3 + 2 = 5$&lt;/p&gt;
&lt;p&gt;$P(S) = \frac{3}{5} = 0.6$&lt;br&gt;
$P(H) = \frac{2}{5} = 0.4$&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;先验概率结果：&lt;/strong&gt;&lt;br&gt;
$P(S) = 0.6, \quad P(H) = 0.4$&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;计算每个词语在 Spam 和 Ham 类别下的类条件概率。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;词典大小 $|V| = 5$&lt;/p&gt;
&lt;p&gt;Spam:&lt;/p&gt;
&lt;p&gt;deal: 2, money: 2, urgent: 2, meeting: 0, free: 3&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;总词数：$2+2+2+0+3 = 9$&lt;/li&gt;
&lt;li&gt;分母：$9 + 5 = 14$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$P(\text{deal}|S) = \frac{2+1}{14} = \frac{3}{14}$&lt;br&gt;
$P(\text{money}|S) = \frac{2+1}{14} = \frac{3}{14}$&lt;br&gt;
$P(\text{urgent}|S) = \frac{2+1}{14} = \frac{3}{14}$&lt;br&gt;
$P(\text{meeting}|S) = \frac{0+1}{14} = \frac{1}{14}$&lt;br&gt;
$P(\text{free}|S) = \frac{3+1}{14} = \frac{4}{14}$&lt;/p&gt;
&lt;p&gt;Ham:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;deal: 1, money: 0, urgent: 1, meeting: 2, free: 0&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;总词数：$1+0+1+2+0 = 4$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;分母：$4 + 5 = 9$&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$P(\text{deal}|H) = \frac{1+1}{9} = \frac{2}{9}$&lt;br&gt;
$P(\text{money}|H) = \frac{0+1}{9} = \frac{1}{9}$&lt;br&gt;
$P(\text{urgent}|H) = \frac{1+1}{9} = \frac{2}{9}$&lt;br&gt;
$P(\text{meeting}|H) = \frac{2+1}{9} = \frac{3}{9}$&lt;br&gt;
$P(\text{free}|H) = \frac{0+1}{9} = \frac{1}{9}$&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;将新邮件 “free urgent meeting” 表示为词频向量。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;free urgent meeting&amp;quot;的词频向量（按词典顺序：deal, money, urgent, meeting, free）：&lt;br&gt;
$[0, 0, 1, 1, 1]$&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;计算该邮件属于 Spam 和 Ham 的后验概率。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Spam:&lt;/p&gt;
&lt;p&gt;$P(S|d) \propto P(S) \times P(\text{urgent}|S) \times P(\text{meeting}|S) \times P(\text{free}|S)$&lt;br&gt;
$= 0.6 \times \frac{3}{14} \times \frac{1}{14} \times \frac{4}{14}$&lt;br&gt;
$= 0.6 \times \frac{12}{2744} \approx 0.002624$&lt;/p&gt;
&lt;p&gt;Ham:&lt;/p&gt;
&lt;p&gt;$P(H|d) \propto P(H) \times P(\text{urgent}|H) \times P(\text{meeting}|H) \times P(\text{free}|H)$&lt;br&gt;
$= 0.4 \times \frac{2}{9} \times \frac{3}{9} \times \frac{1}{9}$&lt;br&gt;
$= 0.4 \times \frac{6}{729} \approx 0.003292$&lt;/p&gt;
&lt;p&gt;归一化:&lt;/p&gt;
&lt;p&gt;$P(S|d) = \frac{0.002624}{0.002624 + 0.003292} \approx 0.444$&lt;br&gt;
$P(H|d) = \frac{0.003292}{0.002624 + 0.003292} \approx 0.556$&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;根据后验概率判断其最终类别。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;由于 $P(H|d) &gt; P(S|d)$，新邮件被分类为：&lt;/p&gt;
&lt;p&gt;$\boxed{Ham}$&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="214-属性的类型"&gt;2.1.4 属性的类型
&lt;/h4&gt;&lt;p&gt;标称、序数、区间、比率&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;属性类型&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;描述&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;例子&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;操作&lt;/strong&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;分类 (定性)&lt;/td&gt;
					&lt;td&gt;标称&lt;/td&gt;
					&lt;td&gt;标称属性的值仅仅只是不同的名字，即标称值只提供足够的信息以区分对象（=，≠）&lt;/td&gt;
					&lt;td&gt;邮政编码，雇员ID号，性别&lt;/td&gt;
					&lt;td&gt;众数、熵、列联相关，卡方检验&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;序数&lt;/td&gt;
					&lt;td&gt;序数属性的值提供足够的信息确定对象的序（&amp;lt;&amp;gt;）&lt;/td&gt;
					&lt;td&gt;矿石硬度{好，一般}、成绩等级、街道号码&lt;/td&gt;
					&lt;td&gt;中值、百分位、秩相关、游程检验、符号检验&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;数值 (定量)&lt;/td&gt;
					&lt;td&gt;区间&lt;/td&gt;
					&lt;td&gt;对于区间属性，值之间的差是有意义的，即存在测量单位（+，-）&lt;/td&gt;
					&lt;td&gt;日历日期、摄氏或华氏温度&lt;/td&gt;
					&lt;td&gt;均值、标准差、皮尔逊相关系数，t和F检验&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;比率&lt;/td&gt;
					&lt;td&gt;对于比率属性，差和比率都是有意义的（+，-，*，/）&lt;/td&gt;
					&lt;td&gt;绝对温度、货币量、计数、年龄、质量、长度、电流&lt;/td&gt;
					&lt;td&gt;几何平均、调和平均、百分比变差&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id="221-中心化趋势"&gt;2.2.1 中心化趋势
&lt;/h4&gt;&lt;p&gt;均值、中位数和众数&lt;/p&gt;
&lt;p&gt;$Mean-mode = 3 * (mean - median)$&lt;/p&gt;
&lt;h4 id="222-四分位极差"&gt;2.2.2 四分位极差
&lt;/h4&gt;&lt;p&gt;第一个四分位数，即第25百分位上的数据 $(n-1)/4$ （仅对于第一个四分位数，若是第三个四分位数还要乘3）&lt;/p&gt;
&lt;p&gt;若n为偶数 需要$+0.25\times (d_{n+1}-d_n)$ （仅对于第一个四分位数，若是第三个四分位数就是0.75）&lt;/p&gt;
&lt;h4 id="244-数值属性的近邻性度量"&gt;&lt;strong&gt;2.4.4&lt;/strong&gt; 数值属性的近邻性度量
&lt;/h4&gt;&lt;p&gt;两个 $p$ 维变量 $x_1 = \{x_{11}, x_{12}, \ldots, x_{1p}\}$ 和 $x_2 = \{x_{21}, x_{22}, \ldots, x_{2p}\}$ 间的闵可夫斯基距离定义为：&lt;/p&gt;
$$
d(i,j) = \sqrt[q]{|x_{i1} - x_{j1}|^q + |x_{i2} - x_{j2}|^q + \cdots + |x_{ip} - x_{jp}|^q}
$$&lt;p&gt;当 $q=1$ 时，表示曼哈顿距离：&lt;/p&gt;
$$
d(i,j) = |x_{i1} - x_{j1}| + |x_{i2} - x_{j2}| + \cdots + |x_{ip} - x_{jp}|
$$&lt;p&gt;当 $q=2$ 时，表示欧式距离：&lt;/p&gt;
$$
d(i,j) = \sqrt{|x_{i1} - x_{j1}|^2 + |x_{i2} - x_{j2}|^2 + \cdots + |x_{ip} - x_{jp}|^2}
$$&lt;p&gt;当 $q \to \infty$ 时，表示切比雪夫距离：&lt;/p&gt;
$$
d(i,j) = \lim_{q \to \infty} \left( \sum_{k=1}^p |x_{ik} - x_{jk}|^q \right)^{\frac{1}{q}} = \max_{1 \le k \le p} |x_{ik} - x_{jk}|
$$&lt;p&gt;
n欧几里得和曼哈顿距离满足以下数学性质&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;正定性：距离是一个非负数 d(i,j)&amp;gt;0, 如果i≠j d(i,i)=0&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对称性：d(i,j)=d(j,i)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;三角不等式&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="248-余弦相似度"&gt;2.4.8 余弦相似度
&lt;/h4&gt;&lt;p&gt;余弦相似度可以用来比较文档的相似性&lt;/p&gt;
$$
s(x, y) = \frac{x^T y}{\|x\|_2 \|y\|_2} \quad x = [1, 1, 0, 0] \quad y = [0, 1, 1, 0]
$$$$
s(x, y) = \frac{0 + 1 + 0 + 0}{\sqrt{2} \sqrt{2}} = 0.5
$$&lt;h4 id="32-数据预处理"&gt;3.2 数据预处理
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;数据清理&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;填写缺失值，平滑噪声数据、识别或删除离群点，并解决不一致问题&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据集成&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;整个多个数据库，多维数据集或文件&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据缩减&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;降维、数据压缩、Numerosity Reduction&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据转换和数据离散化&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;正常化&lt;/li&gt;
&lt;li&gt;生成概念层次结构&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="321-如何处理缺失数据"&gt;3.2.1 如何处理缺失数据
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;忽略元组
&lt;ul&gt;
&lt;li&gt;当类标号缺失时，监督学习&lt;/li&gt;
&lt;li&gt;当每个属性缺失值比例较大时&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;手动填写缺失值，工作量较大&lt;/li&gt;
&lt;li&gt;自动填写
&lt;ul&gt;
&lt;li&gt;使用一个全局的常数&lt;/li&gt;
&lt;li&gt;使用属性的平均值填充空缺值
&lt;ul&gt;
&lt;li&gt;属性全局平均值&lt;/li&gt;
&lt;li&gt;同一类数据对象的属性平均值&lt;/li&gt;
&lt;li&gt;最有可能的值：基于贝叶斯公式或决策树推理，回归、最近邻策略&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="324-相关分析"&gt;3.2.4 相关分析
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/data-mining/Screenshot_2025-11-22_152834.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="327-数据规约策略"&gt;3.2.7 数据规约策略
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;为什么进行数据规约 data reduction?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;由于数据仓库可以存储TB级别的数据，因此在一个完整的数据集上运行时，复杂的数据分析可能需要很长的时间。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通常，在数据预处理时需要对数据进行规约&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;用较小的数据替换原数据&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;常见数据规约策略&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;降维&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;降数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据压缩&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="328-特征降维"&gt;3.2.8 特征降维
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;PCA (Principal Component Analysis) 主成分分析方法&lt;/li&gt;
&lt;li&gt;非负矩阵分解 (NMF)&lt;/li&gt;
&lt;li&gt;线性判别分析 (Linear Discriminant Analysis ,LDA)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;特征选择&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;从原始特征集合中选择一个代表性的特征子集&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;单特征重要性评估&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;基于模型的特征重要性评估&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="3211-规范化"&gt;3.2.11 规范化
&lt;/h4&gt;&lt;p&gt;最小-最大规范化（Min-Max Normalization）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;某属性 $A$ 从区间 $[\min_A, \max_A]$ 规范化到 $[new_{\min_A}, new_{\max_A}]$

$$
 v' = \frac{v - \min_A}{\max_A - \min_A} (new_{\max_A} - new_{\min_A}) + new_{\min_A}
 $$&lt;/li&gt;
&lt;li&gt;例子：将收入从 $12000$ 到 $98000$ 区间规范化到 $[0,1]$ 之间，$73600$ 规范后的值为？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Z-分数规范化（Z-score Normalization）
&lt;/p&gt;
$$
 v' = \frac{v - \mu_A}{\sigma_A}
$$&lt;ul&gt;
&lt;li&gt;例子：属性 $A$ 的均值 $\mu_A = 54000$，标准差 $\sigma_A = 16000$，$73600$ 规范后的值为？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;小数定标规范化&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;移动小数点的位置，移动位数依赖于属性 $A$ 的最大值，公式如下

$$
 v' = \frac{v}{10^j}
 $$&lt;/li&gt;
&lt;li&gt;$j$ 为使 $\max(|v'|) &lt; 1$ 的最小整数&lt;/li&gt;
&lt;li&gt;例如：一组数据的最小值 $12000$，最大值为 $98000$，$j$ 值为 $5$

$$
 [12000, 98000] \rightarrow [0.12, 0.98]
 $$&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="432-决策树构建"&gt;4.3.2 决策树构建
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;决策树(Decision Tree) ：从训练数据中学习得出一个树状结构的模型，它是一种以树状结构(包括二叉树和多叉树)形式来表达的预测分析模型&lt;/li&gt;
&lt;li&gt;决策树是一种有监督学习的算法、属于判别模型&lt;/li&gt;
&lt;li&gt;决策树又称为判定树，是数据挖掘技术中一种重要的分类与回归方法&lt;/li&gt;
&lt;li&gt;决策树有两种:分类树和回归树&lt;/li&gt;
&lt;li&gt;决策树学习通常包含3个步骤: 特征选择,决策树的生成,决策树的剪枝&lt;/li&gt;
&lt;li&gt;常用的方法：ID3, C4.5, CART&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="45-knn算法"&gt;4.5 KNN算法
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;k近邻法(k-Nearest Neighbor, kNN)是一种比较成熟也是最简单的机器学习算法，可以用于基本的&lt;strong&gt;分类与回归&lt;/strong&gt;方法。&lt;/li&gt;
&lt;li&gt;算法的主要思路: 如果一个样本在特征空间中与𝑘个实例最为相似(即特征空间中最邻近)，那么这𝑘 个实例中大多数属于哪个类别，则该样本也属于这个类别。&lt;/li&gt;
&lt;li&gt;𝑘近邻算法三要素: 𝑘值选择，距离度量，决策规则&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="knn与k-means的区别"&gt;KNN与K-Means的区别
&lt;/h5&gt;&lt;p&gt;K-NN是监督学习中的一种分类算法，类别是已知的，通过对已知分类的数据进行训练和学习，找到这些不同类的特征，再对未分类的数据进行分类。&lt;/p&gt;
&lt;p&gt;K-Means是非监督学习中一种聚类算法，事先不知道数据会分为几类，通过聚类分析将数据聚合成几个群体。聚类不需要对数据进行训练和学习。&lt;/p&gt;
&lt;h5 id="有监督学习和无监督学习"&gt;有监督学习和无监督学习
&lt;/h5&gt;&lt;p&gt;有监督学习是一种机器学习方法，其中使用标记数据进行训练。每个输入数据都有对应的输出标签，模型通过学习这些输入与输出之间的关系来进行预测。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;特点&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;需要大量的标记数据。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;训练过程有明确的目标，模型可以通过反馈不断调整。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;常见算法包括线性回归、逻辑回归、支持向量机（SVM）、决策树等。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;适用于分类和回归问题，例如图像识别、语音识别和金融预测等。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;无监督学习是一种机器学习方法，其中使用未标记的数据进行训练。模型从输入数据中自动发现模式和结构，而不依赖于任何标签。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特点&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;不需要标记数据，适合处理大量未标记的数据。&lt;/li&gt;
&lt;li&gt;训练过程没有明确的目标，模型通过数据的内在结构进行学习。&lt;/li&gt;
&lt;li&gt;常见算法包括聚类（如K均值）、关联规则学习（如Apriori算法）等。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;应用场景&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;适用于数据聚类、市场细分、异常检测等。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="53-基于密度的聚类方法"&gt;5.3 基于密度的聚类方法
&lt;/h4&gt;&lt;p&gt;DBSCAN算法描述&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;输入：包含 $n$ 个对象的数据库，半径 $\varepsilon$ (Eps)，最少数目 MinPts&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;输出：所有生成的簇，达到密度要求&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Repeat&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从数据中抽取一个未处理过的点&lt;/li&gt;
&lt;li&gt;If 抽出的点是核心点 Then 找出所有从该点密度可达的对象，形成一个簇&lt;/li&gt;
&lt;li&gt;Else 抽出的点是边缘点（非核心对象），跳出本次循环，寻找下一点&lt;/li&gt;
&lt;li&gt;EndIf&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Until 所有点被处理&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;核心对象:如果对象的ε-领域至少包含最小数目MinPts个对象，则称该对象为核心对象&lt;/p&gt;
&lt;p&gt;边界点(Border point)的&amp;quot;Eps&amp;rdquo;(ε) 领域有少于MinPts个对象，但它的领域中有核心对象&lt;/p&gt;
&lt;h4 id="61-混淆矩阵"&gt;6.1 混淆矩阵
&lt;/h4&gt;&lt;p&gt;混淆矩阵(Confusion Matrix)&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;实际类 \ 预测类&lt;/th&gt;
					&lt;th&gt;Class=Yes&lt;/th&gt;
					&lt;th&gt;Class=No&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Class=Yes&lt;/td&gt;
					&lt;td&gt;a (TP)&lt;/td&gt;
					&lt;td&gt;b (FN)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Class=No&lt;/td&gt;
					&lt;td&gt;c (FP)&lt;/td&gt;
					&lt;td&gt;d (TN)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;$a+d$ 表示所有样本中被正确分类的样本数量&lt;/li&gt;
&lt;li&gt;$b+c$ 表示所有样本中被错误分类的样本数量&lt;/li&gt;
&lt;li&gt;$a+b+c+d$ 表示样本总数&lt;/li&gt;
&lt;li&gt;准确率&lt;/li&gt;
&lt;/ul&gt;
$$
Accuracy = \frac{a+d}{a+b+c+d} = \frac{TP+TN}{TP+TN+FP+FN}
$$&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;召回率（查全率，recall）&lt;/p&gt;
$$
 recall = \frac{TP}{TP+FN}
 $$&lt;ul&gt;
&lt;li&gt;表示样本中的正例被正确预测的比例，即有多少正例样本被预测正确了&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;精确率（查准率，precision）&lt;/p&gt;
$$
 precision = \frac{TP}{TP+FP}
 $$&lt;ul&gt;
&lt;li&gt;表示预测的正例中被正确预测的比例，即预测为正例样本中有多少是真的正例&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="65-过拟合和欠拟合"&gt;6.5 过拟合和欠拟合
&lt;/h4&gt;&lt;p&gt;导致过拟合的原因：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;噪声：训练集中存在大量噪声数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;缺乏代表性样本：训练集规模较小，训练模型过于复杂&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="71-集成学习的优势"&gt;7.1 集成学习的优势
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;能够有效降低预测误差&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;假设一个集成分类器包含3个单分类器，其中每个分类器的错误率为40%. C表示预测正确，I表示预测错误，Probability表示最终预测结果概率，总的组合数为23=8种&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;模型的误差率为：0.096+0.096+0.096+0.064=35.2%&amp;lt;40%&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;设模型数量为 $m$，模型的错误率为 $r$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通用的误差计算公式为：
&lt;/p&gt;
$$
 p(error) = \sum_{i=(m+1)/2}^{m} C_{m}^{i} r^{i}(1-r)^{m-i}
 $$&lt;ul&gt;
&lt;li&gt;$m$ 个模型中有超一半分类错误时→最终结果错误，$i$ 从 $(m+1)/2$ 到 $m$&lt;/li&gt;
&lt;li&gt;随机从 $m$ 中选择 $i$ 个，其余 $m-i$ 个分类正确&lt;/li&gt;
&lt;li&gt;下图为 $r=0.4$ 时误差率和模型规模的关系图&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>TOEFL学习经验</title><link>https://ottercoconut.github.io/p/toefl%E5%AD%A6%E4%B9%A0%E7%BB%8F%E9%AA%8C/</link><pubDate>Sun, 02 Nov 2025 15:54:54 +0800</pubDate><guid>https://ottercoconut.github.io/p/toefl%E5%AD%A6%E4%B9%A0%E7%BB%8F%E9%AA%8C/</guid><description>&lt;p&gt;注：2026年1月后，托福进行了改革，旧的题型不再具有参考价值，故删减部分内容。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;考试时长大幅缩短&lt;/strong&gt;：总时长约1.5–2小时，流程更紧凑高效。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;自适应测试&lt;/strong&gt;：Reading和Listening采用多阶段自适应设计，根据考生前一阶段表现实时调整后续难度，测试更精准。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;全新评分体系&lt;/strong&gt;：改为&lt;strong&gt;1–6分制&lt;/strong&gt;（0.5为增量），总分取四部分平均，直接对应CEFR语言能力框架（如5分≈C1）。过渡期2年内，成绩单同时显示可比的0–120总分，便于新旧对比。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;内容与题型全面更新&lt;/strong&gt;：四大板块均引入更实用、贴近学术与日常生活的新任务类型，减少冷门偏题，强调真实沟通能力。&lt;/p&gt;
&lt;h2 id="toefl"&gt;TOEFL
&lt;/h2&gt;&lt;h3 id="reading"&gt;Reading
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;模块数量&lt;/strong&gt;：&lt;strong&gt;2个模块&lt;/strong&gt;（Module 1 + Module 2）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;总题量&lt;/strong&gt;：&lt;strong&gt;约45–50题&lt;/strong&gt;（48题左右）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;总时长&lt;/strong&gt;：&lt;strong&gt;约30分钟&lt;/strong&gt;（整个Reading部分）&lt;/p&gt;
&lt;p&gt;自适应方式：多阶段自适应（MST）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;模块一（Routing Module）&lt;/strong&gt;：所有考生难度基本相同（路由模块），题量较多。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模块二&lt;/strong&gt;：根据模块一的表现路由到&lt;strong&gt;较高难度&lt;/strong&gt;或&lt;strong&gt;较低难度&lt;/strong&gt;版本，题量较少，进入较难的模块二则代表高分数。&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;模块&lt;/th&gt;
					&lt;th&gt;常见题量&lt;/th&gt;
					&lt;th&gt;建议时间分配&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;模块一&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;25–30题&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;18–22分钟&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;决定你最终能拿到的分数上限&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;模块二&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;15–20题&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;8–12分钟&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;根据模块一表现分流，题量减少&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;总计&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;45–50题&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;约30分钟&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;会同时存在计分题和不计分题，但考生无法得知&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;三种题型在阅读中通常按以下顺序出现：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Complete the Words（语境填词）——占比最高
&lt;ul&gt;
&lt;li&gt;多个短段落（每个段落约10个空）&lt;/li&gt;
&lt;li&gt;做题速度相对快，熟悉后每题平均15–25秒&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Read in Daily Life（日常阅读）
&lt;ul&gt;
&lt;li&gt;短文本（邮件、通知、聊天记录等）&lt;/li&gt;
&lt;li&gt;每篇题量少（通常2–3题）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Read an Academic Passage（学术阅读）
&lt;ul&gt;
&lt;li&gt;学术短文&lt;/li&gt;
&lt;li&gt;每篇题量也较少（约5题）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;根据做模拟题的情况来看，&amp;ldquo;Complete the Words&amp;rdquo; 部分是最难的，反而学术阅读比之前简单一些。&lt;/p&gt;
&lt;h2 id="toefl-before-2026-jan"&gt;TOEFL (before 2026 Jan.)
&lt;/h2&gt;&lt;h3 id="reading-1"&gt;Reading
&lt;/h3&gt;&lt;h4 id="tpo6"&gt;TPO6
&lt;/h4&gt;&lt;p&gt;1.Which of the sentences below best expresses the essential information in the highlighted sentence in the passage? Incorrect choices change the meaning in important ways or leave out essential information.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;Only the last of these was suited at all to the continuous operating of machines&lt;/strong&gt;, and although waterpower abounded in Lancashire and Scotland and ran grain mills as well as textile mills, &lt;strong&gt;it had one great disadvantage: streams flowed where nature intended them to, and water-driven factories had to be located on their banks&lt;/strong&gt;, whether or not the location was desirable for other reasons.&lt;/p&gt;
&lt;p&gt;第一句确定了主系表的结构，主语&amp;quot;last of these&amp;quot;对应了前一句话的&amp;quot;running water&amp;quot;，省略掉 &amp;ldquo;although&amp;quot;和&amp;quot;whether&amp;quot;引导的从句，即得出核心大意。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;4.The word &amp;ldquo;exploited&amp;rdquo; in the passage is closest in meaning to ()&lt;/p&gt;
&lt;p&gt;A. utilized&lt;/p&gt;
&lt;p&gt;B. recognized&lt;/p&gt;
&lt;p&gt;C. examined&lt;/p&gt;
&lt;p&gt;D. fully understood&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;The source had long been known but not &lt;strong&gt;exploited&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;exploit&amp;quot;译为“利用;开发;发挥”，&amp;ldquo;utilize&amp;quot;译为“使用;利用;应用”&lt;/p&gt;
&lt;p&gt;结合上下文来看，本段将介绍一种新的能源。第二段之后便开始介绍蒸汽机的起源，&amp;ldquo;early in the century&amp;quot;也对应了&amp;quot;had long been known&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;7.The phrase &amp;ldquo;grew accustomed to&amp;rdquo; in the passage is closest in meaning to ()&lt;/p&gt;
&lt;p&gt;A. began to prefer&lt;/p&gt;
&lt;p&gt;B. wanted to have&lt;/p&gt;
&lt;p&gt;C. became used to&lt;/p&gt;
&lt;p&gt;D. insisted on&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Coal gas rivaled smoky oil lamps and flickering candles, and early in the new century, well-to-do Londoners &lt;strong&gt;grew accustomed to&lt;/strong&gt; gaslit houses and even streets.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;accustomed&amp;quot;译为“习惯的;适应了的”&lt;/p&gt;
&lt;p&gt;原文说煤气胜过了油灯和蜡烛，因此易在A和C间犹豫，网站的解释是”前面已经提到了胜过，不必在用prefer比较“，AI的解释是”A选项有明显的情感倾向“，我认为关键在连词&amp;quot;and&amp;rdquo;，即”同时/并且，Londoners grew accustomed to gaslit houses &amp;hellip; “，若连词换成&amp;quot;so&amp;quot;可能结果不同。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;10.The Industrial Revolution would not have been possible without a new source of power that was efficient, movable, and continuously available.An introductory sentence for a brief summary of the passage is provided below &amp;hellip;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;第一段：在蒸汽机等发明前只有三种&amp;quot;sources of power&amp;rdquo;，其中&amp;quot;running water&amp;quot;适合机器持续运转但仍有“季节性”的缺点。&lt;/p&gt;
&lt;p&gt;第二段：”大气压机“的原理，及浪费能源和效率低的不足之处，之后是对它原理的改进。&lt;/p&gt;
&lt;p&gt;第三段：瓦特蒸汽机，导致了&amp;quot;possible deeper and deeper mining&amp;rdquo;, &amp;ldquo;new form of nighttime illumination&amp;rdquo;, &amp;ldquo;motive force of the Industrial Revolution&amp;rdquo;&lt;/p&gt;
&lt;p&gt;第四段：蒸汽机在19世纪的扩大使用，主要讨论了交通方面，水运的局限以及解决运输问题的火车的发明。&lt;/p&gt;

 &lt;/blockquote&gt;

 &lt;blockquote&gt;
 &lt;p&gt;本题的三个错误选项，我认为是与文章主题的偏差问题，即并没反映题干&lt;/p&gt;
&lt;p&gt;A: This &amp;ldquo;atmospheric engine,&amp;rdquo; invented by Thomas Savery and vastly improved by his partner, Thomas Newcomen &amp;hellip;&lt;/p&gt;
&lt;p&gt;D,E: 和&amp;quot;The Industrial Revolution would not have been possible without a new source of power that was efficient, movable, and continuously available.&amp;ldquo;关系不大，即和蒸汽机关系不大，D依据第三段，E依据第四段第一句。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;14.The word &amp;ldquo;meticulously&amp;rdquo; in the passage is closest in meaning to ()&lt;/p&gt;
&lt;p&gt;A. carefully&lt;/p&gt;
&lt;p&gt;B. quickly&lt;/p&gt;
&lt;p&gt;C. frequently&lt;/p&gt;
&lt;p&gt;D. obviously&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Smith used mail coaches to travel as much as 10,000 miles per year. In 1815 he published the first modern geological map, &amp;ldquo;A Map of the Strata of England and Wales with a Part of Scotland,&amp;rdquo; a map so &lt;strong&gt;meticulously&lt;/strong&gt; researched that it can still be used today.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;meticulously&amp;quot;译为”细致的,小心翼翼的“&lt;/p&gt;
&lt;p&gt;从&amp;quot;it can still be used today&amp;quot;明显能看出和A近意&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;15.Which of the sentences below best expresses the essential information in the highlighted sentence in the passage? Incorrect choices change the meaning in important ways or leave out essential information.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;But as more and more accumulations of strata &lt;strong&gt;were cataloged&lt;/strong&gt; in more and more places, &lt;strong&gt;it became clear&lt;/strong&gt; that the sequences of rocks sometimes differed from region to region and that &lt;strong&gt;no&lt;/strong&gt; rock type was ever going to become a reliable time marker throughout the world.&lt;/p&gt;
&lt;p&gt;忽略掉&amp;quot;but&amp;quot;引导的从句，主语为&amp;quot;it&amp;quot;替代的&amp;quot;that&amp;quot;引导的两个从句，&amp;ldquo;that&amp;hellip;and that&amp;hellip;&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;17.The word &amp;ldquo;endured&amp;rdquo; in the passage is closest in meaning to ()&lt;/p&gt;
&lt;p&gt;A. vanished&lt;/p&gt;
&lt;p&gt;B. developed&lt;/p&gt;
&lt;p&gt;C. varied&lt;/p&gt;
&lt;p&gt;D. survived&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Some fossils &lt;strong&gt;endured&lt;/strong&gt; through so many millions of years that they appear in many strata, but others occur only in a few strata, and a few species had their births and extinctions within one particular stratum.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;endure&amp;quot;译为“忍耐,忍受”，根据原句的&amp;quot;so&amp;hellip;that&amp;hellip;&amp;ldquo;易得D，A的&amp;quot;vanish&amp;quot;译为“消失,灭绝”&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;20.William Smith’s contributions to geology have increased our knowledge of the Earth’s history. An introductory sentence for a brief summary of the passage is provided below &amp;hellip;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;A选项依据在第一段，Smith出身于&amp;quot;poor family&amp;rdquo;&lt;/p&gt;
&lt;p&gt;D选项&amp;quot;Smith was named “the father of English geology” for his maps rather than for his other contributions to the field.&amp;rdquo; 和第三段第一句&amp;quot;not only&amp;hellip;but also&amp;hellip;&amp;ldquo;矛盾。&lt;/p&gt;
&lt;p&gt;E选项依据在第四段的第二句，只体现出了&amp;quot;Particularly in the younger strata, the rocks were often so similar that he had trouble distinguishing the strata &amp;hellip;&amp;rdquo; 而且&amp;quot;Cuvier&amp;quot;只出现在最后一段。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;TPO6应该是国庆假期后刚开始做的模拟，做了两遍，再回看细节题都很简单，只有第一篇的六选三有点说法了。对于六选三这种题，大部分还是凭感觉或是找明显错误，第二篇是错误非常明显的那种。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="tpo7"&gt;TPO7
&lt;/h4&gt;&lt;p&gt;2.Which of the following is NOT mentioned in paragraph 1 as a change that occurred in the fauna of the Mediterranean?&lt;/p&gt;
&lt;p&gt;A. Most invertebrate species disappeared during a wave of extinctions.&lt;/p&gt;
&lt;p&gt;B. A few hardy species wiped out many of the Mediterranean’s invertebrates.&lt;/p&gt;
&lt;p&gt;C. Some invertebrates migrated to the Atlantic Ocean.&lt;/p&gt;
&lt;p&gt;D. New species of fauna populated the Mediterranean when the old migrants returned.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;A对应&amp;quot;Most of the older organisms were nearly wiped out&amp;hellip;&amp;rdquo;&lt;/p&gt;
&lt;p&gt;B偷换意思，原文为&amp;quot;a few hardy species survived&amp;quot;而不是&amp;quot;hardy species&amp;quot;&amp;ldquo;wipe out&amp;quot;&amp;ldquo;invertebrates&amp;rdquo;&lt;/p&gt;
&lt;p&gt;C对应&amp;quot;A few managed to migrate into the Atlantic.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;D对应&amp;quot;Somewhat later, the migrants returned, bringing new species with them.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;3.What does the author imply by saying &amp;ldquo;Not a single pebble was found that might have indicated that the pebbles came from the nearby continent&amp;rdquo;?&lt;/p&gt;
&lt;p&gt;A. The most obvious explanation for the origin of the pebbles was not supported by the evidence.&lt;/p&gt;
&lt;p&gt;B. The geologists did not find as many pebbles as they expected.&lt;/p&gt;
&lt;p&gt;C. The geologists were looking for a particular kind of pebble.&lt;/p&gt;
&lt;p&gt;D. The different pebbles could not have come from only one source.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;原句的前面讲了这个样本的组成，后面则先是指出样本中的成分来自沙漠，之后对&amp;quot;Mediterranean(地中海)&amp;ldquo;的挖掘，说明了地中海以前不是海。&lt;/p&gt;
&lt;p&gt;而再看选项，需要对应到前一段的最后句&amp;quot;Were they salt domes such as are &lt;strong&gt;common along the United States Gulf Coast&lt;/strong&gt;, and if so, why should there have been so much solid crystalline salt beneath &lt;strong&gt;the floor of the Mediterranean&lt;/strong&gt;?&amp;quot;“它们是像美国墨西哥湾沿岸常见的盐丘吗？如果是的话，为什么地中海海底会有如此多的固体结晶盐？”&lt;/p&gt;
&lt;p&gt;这也就解释了正确答案A的&amp;quot;The most obvious explanation for the origin&amp;quot;的来源，那么我选的D选项实则没有道理，&amp;ldquo;not have come from one source&amp;quot;并不能证明它来自多个地点，也可能是一个不同的地点。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;4.Select the TWO answer choices from paragraph 3 that identify materials discovered in the deepest part of the Mediterranean basin. To receive credit, you must select TWO answers.&lt;/p&gt;
&lt;p&gt;A. Volcanic rock fragments&lt;/p&gt;
&lt;p&gt;B. Thin silt layers&lt;/p&gt;
&lt;p&gt;C. Soft, deep-sea mud&lt;/p&gt;
&lt;p&gt;D. Crystalline salt&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;对应第三段最后两句&amp;quot;As they drilled into the central and deepest part of the Mediterranean basin, the scientists took &lt;strong&gt;solid, shiny, crystalline salt&lt;/strong&gt; from the core barrel. Interbedded with &lt;strong&gt;the salt were thin layers&lt;/strong&gt; of what appeared to be windblown silt.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;而不能被本段的第二句欺骗，因为题干的&amp;quot;the deepest part of the Mediterranean basin&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;7.Which of the sentences below best expresses the essential information in the highlighted sentence in the passage? Incorrect choices change the meaning in important ways or leave out essential information.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;As a result of crustal adjustments and faulting, &lt;strong&gt;the Strait of Gibraltar&lt;/strong&gt;, where the Mediterranean now connects to the Atlantic, &lt;strong&gt;opened&lt;/strong&gt;, and &lt;strong&gt;water cascaded&lt;/strong&gt; spectacularly back into the Mediterranean.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;11.Which of the sentences below best expresses the essential information in the highlighted sentence in the passage? Incorrect choices change the meaning in important ways or leave out essential information.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Like the stones of a Roman wall, which were held together both by the regularity of the design and by that peculiarly powerful Roman cement, so the various &lt;strong&gt;parts of the Roman realm were bonded&lt;/strong&gt; into a massive, monolithic entity by physical, organizational, and psychological controls.&lt;/p&gt;
&lt;p&gt;用了&amp;quot;just as A, so B&amp;quot;的类比句型，核心在于罗马怎么样，而非前面用于类比的罗马城墙如何。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;15.Paragraph 3 suggests which of the following about the people of Latium?&lt;/p&gt;
&lt;p&gt;A. Their economy was based on trade relations with other settlements.&lt;/p&gt;
&lt;p&gt;B. They held different values than the people of Rome.&lt;/p&gt;
&lt;p&gt;C. Agriculture played a significant role in their society.&lt;/p&gt;
&lt;p&gt;D. They possessed unusual knowledge of animal instincts.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;本段第三句&amp;rdquo;&amp;hellip;that created the habits and skills of landed settlement, landed property, landed economy, landed administration, and a land-based society. &amp;quot;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;18.Which of the following statements about leading Roman soldiers and statesmen is supported by paragraphs 5 and 6?&lt;/p&gt;
&lt;p&gt;A. They could read and write the Greek language.&lt;/p&gt;
&lt;p&gt;B. They frequently wrote poetry and plays.&lt;/p&gt;
&lt;p&gt;C. They focused their writing on military matters.&lt;/p&gt;
&lt;p&gt;D. They wrote according to the philosophical laws of the Greeks.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;It was absolutely accepted that an educated Roman should be fluent in Greek.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;误选D的时候，觉得A的&amp;quot;educated Roman&amp;quot;和题干的&amp;quot;Roman soldiers&amp;quot;相悖，但剩下的选项都没有提及&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;TPO7错了很多细节题，反而到6选3没有错，回看一下一般都是将原文信息换个有点相近的，但剩下的选项则是没有出现，就如第二篇的细节题。第一篇的细节题要把握上下文，如第3题是跨段落的问题，且意思略晦涩，第一次读未能注意&amp;quot;United States Gulf Coast&amp;quot;，以及第4题，需通读整段。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="tpo11"&gt;TPO11
&lt;/h4&gt;&lt;p&gt;6.According to paragraph 3, why were certain areas of a stone statue left uncarved?&lt;/p&gt;
&lt;p&gt;A. To prevent damage by providing physical stability&lt;/p&gt;
&lt;p&gt;B. To emphasize that the material was as important as the figure itself&lt;/p&gt;
&lt;p&gt;C. To emphasize that the figure was not meant to be a real human being&lt;/p&gt;
&lt;p&gt;D. To provide another artist with the chance to finish the carving&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;left uncarved&amp;quot;对应到本段的第二句话末尾&amp;rdquo;&amp;hellip;was not normally cut away.&amp;ldquo;问题出在&amp;quot;figures&amp;quot;在这里翻译为了“雕像”，导致我忽略了这个答案句&amp;rdquo;&amp;hellip;this protected the figures against breakage&amp;hellip;&amp;ldquo;后面有一生词&amp;quot;pillar&amp;quot;译为&amp;quot;起支撑作用的背柱&amp;rdquo;。这是古埃及、古希腊等文明雕像中常见的结构，一根连接在雕像背部的石柱。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;9.Look at the four squares that indicate where the following sentence could be added to the passage.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In fact, it is the action and not the figure itself that is important.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Apart from statues representing deities, kings, and named members of the elite that can be called formal, there is another group of three-dimensional representations that depicts generic figures, frequently servants, from the nonelite population. [ ] The function of these is quite different. [ ] Many are made to be put in the tombs of the elite in order to serve the tomb owners in the afterlife.[ ] Unlike formal statues that are limited to static poses of standing, sitting, and kneeling, these figures depict a wide range of actions, such as grinding grain, baking bread, producing pots, and making music, and they are shown in appropriate poses, bending and squatting as they carry out their tasks.[ ]&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;答案是放在最后一空，&amp;ldquo;action&amp;quot;对应了最后一句的&amp;quot;actions,such as&amp;hellip;&amp;rdquo;&lt;/p&gt;
&lt;p&gt;其次是&amp;quot;In fact&amp;quot;要表达转折，但是第三空的前一句和下面的句子并无转折意&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;16.The experiment described in paragraph 5 caused Kramer to conclude that birds possess a biological clock because&lt;/p&gt;
&lt;p&gt;A. when birds navigate they are able to compensate for the changing position of the Sun in the sky&lt;/p&gt;
&lt;p&gt;B. birds’ innate bearings keep them oriented in a direction that is within 15 degrees of the Sun’s direction&lt;/p&gt;
&lt;p&gt;C. birds’ migration is triggered by natural environmental cues, such as the position of the Sun&lt;/p&gt;
&lt;p&gt;D. birds shift their direction at a rate of 15 degrees per hour whether the Sun is visible or not&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;题干对应段落最后一句的&amp;quot;This meant that some sort of biological clock was operating–and a very precise clock at that.&amp;ldquo;而前一句&amp;quot;In other words, they were able to compensate for the Sun’s movement. &amp;quot;&lt;/p&gt;
&lt;p&gt;难点在于这段话略晦涩难懂，是通过人造太阳和天然太阳的对比，以及鸟类15°的&amp;quot;compensate&amp;rdquo;(补偿)飞行，也突出了其生物钟的存在&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;19.Look at the four squares that indicate where the following sentence could be added to the passage.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;He arranged the feed boxes at various positions on a compass.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So, in another set of experiments, Kramer put identical food boxes around the cage, with food in only one of the boxes.[ ] The boxes were stationary, and the one containing food was always at the same point of the compass.[ ] However, its position with respect to the surroundings could be changed by revolving either the inner cage containing the birds or the outer walls, which served as the background. [ ] As long as the birds could see the Sun, no matter how their surroundings were altered, they went directly to the correct food box.[ ] Whether the box appeared in front of the right wall or the left wall, they showed no signs of confusion.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;答案是放第一个空，可能这题不能想的太复杂，把人名和&amp;quot;He&amp;quot;一对应即可，&amp;quot; arranged the feed boxes&amp;quot;对应了后面开始将&amp;quot;boxes&amp;quot;的属性&amp;hellip;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;TPO11算是罕见的错了2个填句子题，问题出在词汇量的问题，读着读着生词量多了就昏了，导致内在逻辑也没能理解，如第一篇的雕像和第二篇的鸟。6选3因为pad的浏览器问题没有做，就当跳过了吧。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="tpo12"&gt;TPO12
&lt;/h4&gt;&lt;p&gt;3.Which of the sentences below best expresses the essential information in the highlighted sentence in the passage? Incorrect choices change the meaning in important ways or leave out essential information.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Most &lt;strong&gt;engravings&lt;/strong&gt;, for example, &lt;strong&gt;are best lit from the left&lt;/strong&gt;, as befits the work of right-handed artists, who generally prefer to &lt;strong&gt;have the light source on the left&lt;/strong&gt; so that the shadow of their hand does not fall on the tip of the engraving tool or brush.&lt;/p&gt;
&lt;p&gt;这句话的重点在于“左边的光源”，&amp;ldquo;befits the work of right-handed artists&amp;quot;&amp;ldquo;so that &amp;hellip;&amp;ldquo;表明了为什么右撇子艺术家用左边光源。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;4.All of the following are mentioned in paragraphs 1 and 2 as evidence of right-handedness in art and artists EXCEPT&lt;/p&gt;
&lt;p&gt;A. the ideal source of lighting for most engravings&lt;/p&gt;
&lt;p&gt;B. the fact that a left hand stenciled palm upward might look like a right hand&lt;/p&gt;
&lt;p&gt;C. the prevalence of outlines of left hands&lt;/p&gt;
&lt;p&gt;D. figures in prehistoric art holding objects with the right hand&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;A,D选项在第二段分别有体现，C若是知道&amp;quot;stencil&amp;quot;和&amp;quot;outline&amp;quot;的近义关系也不容易选错，&amp;ldquo;stencil&amp;quot;是印记，&amp;ldquo;outline&amp;quot;是外形、轮廓，在文章中都表示“手印”。&lt;/p&gt;
&lt;p&gt;B选项比较神奇，第一段第4句确实有相同的内容&amp;quot;One also has to make the assumption that hands were stenciled palm downward—a left hand stenciled palm upward might of course look as if it were a right hand.&amp;ldquo;但重点在&amp;quot;make a assumption that&amp;hellip;&amp;ldquo;是”&lt;strong&gt;假定所有手都是掌心向下印的&lt;/strong&gt;“，破折号后的内容并非&amp;quot;fact&amp;quot;而是&lt;strong&gt;解释了前面为什么要&lt;/strong&gt;&amp;ldquo;make a assumption that&amp;hellip;&amp;quot;。如果不结合文章，那么手掌向上的左手(即用手背)产生的印记易被误以为成右手，就不会是题干的&amp;quot;evidence of right-handedness&amp;rdquo;。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;6.In paragraph 5, why does the author mention the Ice Age rope found in the French cave of Lascaux?&lt;/p&gt;
&lt;p&gt;A. As an example of an item on which the marks of wear imply that it was used by a right handed person&lt;/p&gt;
&lt;p&gt;B. Because tressing is an activity that is easier for a right-handed person than for a left-handed person&lt;/p&gt;
&lt;p&gt;C. Because the cave of Lascaux is the site where researchers have found several prehistoric tools made for right-handed people&lt;/p&gt;
&lt;p&gt;D. As an example of an item whose construction shows that it was made by a right-handed person&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Tools themselves can be revealing. Long-handed Neolithic spoons of yew wood preserved in Alpine villages dating to 3000 B.C. have survived; the signs of rubbing on their left side indicate that their users were right-handed. The late Ice Age rope found in the French cave of Lascaux &lt;strong&gt;consists of fibers spiraling to the right, and was therefore tressed by a right-hander.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;直白的词汇量问题，一句话三个生词&amp;quot;fibers&amp;quot;&amp;ldquo;spiraling&amp;quot;&amp;ldquo;tressed&amp;quot;分别表示“纤维”“螺旋”“缕”，这句话也就是说“绳子(纤维)是右螺旋编织的”，即D选项。&lt;/p&gt;
&lt;p&gt;A选项的内容是对前面的例子的概括，而不是题干这个。此外A选项的核心是指&amp;quot;marks imply that it was used by &amp;hellip;&amp;ldquo;其中&amp;quot;used&amp;quot;就和D的&amp;quot;made&amp;quot;形成对比了。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;TPO12的这篇大致就是词汇量不足，比如“手掌”的&amp;quot;palm&amp;rdquo;，以及第4题还是挺有逻辑的。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="tpo15"&gt;TPO15
&lt;/h4&gt;&lt;p&gt;4.The word &amp;ldquo;bulk&amp;rdquo; in the passage is closest in meaning to&lt;/p&gt;
&lt;p&gt;A. strength&lt;/p&gt;
&lt;p&gt;B. effort&lt;/p&gt;
&lt;p&gt;C. activity&lt;/p&gt;
&lt;p&gt;D. mass&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;An adult leatherback is twice the size of the biggest cheloniid sea turtles and will therefore take longer to cool off. Maintaining a high body temperature through sheer &lt;strong&gt;bulk&lt;/strong&gt; is called gigantothermy. It works for elephants, for whales, and, perhaps, it worked for many of the larger dinosaurs.&lt;/p&gt;
&lt;p&gt;首先，&amp;ldquo;sheer&amp;quot;的意思在这里是“完全的，彻底的”，其它意思还有“陡峭的”，其实翻译后看四个选项都不太对，虽说得先了解&amp;quot;mass&amp;quot;是可以做名词表示“大量，大批”的，那么结合上下文，不难得出。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;15.Which of the sentences below best expresses the essential information in the highlighted sentence in the passage? Incorrect choices change the meaning in important ways or leave out essential information.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;American paleontologists&lt;/strong&gt; David Raup and John Sepkoski, who have studied extinction rates in a number of fossil groups, &lt;strong&gt;suggest&lt;/strong&gt; that episodes of increased extinction have recurred periodically, approximately &lt;strong&gt;every 26 million years&lt;/strong&gt; since the mid-Cretaceous period.&lt;/p&gt;
&lt;p&gt;核心在于&amp;quot;every 26 million years&amp;quot;除了A选项外都错误表达了时间（但忘了我为什么会错）。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h4 id="tpo56"&gt;TPO56
&lt;/h4&gt;&lt;p&gt;R2Q7.According to paragraph 4, what was the response to criticisms of representative government in England?&lt;/p&gt;
&lt;p&gt;A. Efforts were made to make the system better&lt;/p&gt;
&lt;p&gt;B. Criticisms of the system were completely ignored.&lt;/p&gt;
&lt;p&gt;C. An explanation was created to defend the system&lt;/p&gt;
&lt;p&gt;D. Critics of the system were widely viewed as unpatriotic.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;hellip; Few could meet the test. A number of English people thought the situation and said so. &lt;strong&gt;But nothing was done to improve it&lt;/strong&gt;; &lt;strong&gt;in fact&lt;/strong&gt;, &lt;strong&gt;a theory was devised to justify it&lt;/strong&gt;. A member of the House of Commons, it was said, represented not the people who chose him but the whole country, and he was not responsible for any particular constituency. Not all Englishmen could vote for representatives, but all were virtually represented by every member of the Commons.&lt;/p&gt;
&lt;p&gt;将原文翻译，“但是，没有采取任何措施来改进它；事实上，&lt;strong&gt;有人设计出一种理论来为其辩护&lt;/strong&gt;。”和选项C是一个意思，&amp;ldquo;justify&amp;quot;&amp;ldquo;defend&amp;quot;都是辩护的意思。错选B时看到前半句就选了，而忽略了重要的&amp;quot;In fact&amp;rdquo;。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h4 id="tpo57"&gt;TPO57
&lt;/h4&gt;&lt;p&gt;R1Q2.The word &amp;ldquo;annihilated&amp;rdquo; in the passage is closest in meaning to&lt;/p&gt;
&lt;p&gt;A. unaffected&lt;/p&gt;
&lt;p&gt;B. strengthened&lt;/p&gt;
&lt;p&gt;C. quickly weakened&lt;/p&gt;
&lt;p&gt;D. completely eliminated&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;应选&amp;quot;D&amp;rdquo;“彻底消除”，回到原文，&amp;ldquo;In 1912, he &lt;strong&gt;compared&lt;/strong&gt; how effective the sprays were in different parts &amp;hellip; &amp;ldquo;要在不同的地区进行杀虫剂的对比，后文指出在&amp;quot;Washington&amp;quot;完全消除，而在&amp;quot;Clarkston&amp;quot;就不行。紧接着&amp;quot;On the other hand, the Clarkston scales were &lt;strong&gt;annihilated&lt;/strong&gt; by a different pesticide made from fuel oil, &lt;strong&gt;just as the insects in other parts of Washington were&lt;/strong&gt;.&amp;ldquo;显然是D。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;R1Q6.Why does the author mention &amp;ldquo;draining standing water or breeding resistant strains of crops&amp;rdquo; ?&lt;/p&gt;
&lt;p&gt;A. To contrast the cost of DDT with the cost of old-fashioned ways of controlling pests&lt;/p&gt;
&lt;p&gt;B. To present evidence that European agricultural activity had declined before 1941&lt;/p&gt;
&lt;p&gt;C. To provide examples of &lt;strong&gt;farming practices&lt;/strong&gt; that &lt;strong&gt;were abandoned&lt;/strong&gt; &lt;strong&gt;due to&lt;/strong&gt; the success of &lt;strong&gt;DDT&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;D. To indicate that certain farming practices were never explored because DDT was so effective&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Between 1941 and 1976, 4.5 million tons of DDT were produced &lt;strong&gt;DDT&lt;/strong&gt; was &lt;strong&gt;so&lt;/strong&gt; powerful and cheap &lt;strong&gt;that&lt;/strong&gt; farmers &lt;strong&gt;gave up old-fashioned ways&lt;/strong&gt; of controlling pests, such as draining standing water or breeding resistant strains of crops.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;R2Q4.The word &amp;ldquo;intangible&amp;rdquo; in the passage is closest in meaning to&lt;/p&gt;
&lt;p&gt;A. nonmaterial&lt;/p&gt;
&lt;p&gt;B. independent&lt;/p&gt;
&lt;p&gt;C. powerful&lt;/p&gt;
&lt;p&gt;D. insignificant&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Spallanzani showed that nutrient fluids heated after being sealed in a flask did not develop microbial growth. Needham responded by claiming the &lt;strong&gt;&amp;ldquo;vital force&amp;rdquo;&lt;/strong&gt; necessary for spontaneous generation had been destroyed by the heat and was kept out of the flasks by the seals.&lt;/p&gt;
&lt;p&gt;This &lt;strong&gt;intangible &amp;ldquo;vital force&amp;rdquo;&lt;/strong&gt; was given all the more credence shortly after Spallanzani&amp;rsquo;s experiment, when Laurent Lavoisier showed the importance of oxygen to life. Spallanzani&amp;rsquo;s observations were criticized on the grounds that there was not enough oxygen in the sealed flasks to support microbial life.&lt;/p&gt;
&lt;p&gt;第一段，根据Needham的说法，这种“生命力”是“自发发生”所必需的。他认为，Spallanzani的实验之所以失败，是因为加热&lt;em&gt;破坏&lt;/em&gt;了这种“生命力”，并且密封的瓶塞将其&lt;em&gt;阻挡&lt;/em&gt;在了烧瓶之外。从这里我们可以推断，Needham所认为的“生命力”是一种&lt;strong&gt;非物质的、看不见摸不着的存在&lt;/strong&gt;。它不像灰尘或微生物那样是实体，而是一种可以被“阻挡”或“破坏”的“力量”或“原理”。&lt;/p&gt;
&lt;p&gt;第二段，批评者认为，Spallanzani的密封烧瓶中&lt;em&gt;没有足够的氧气&lt;/em&gt;来支持微生物生命。这实际上是为“生命力”无法起作用提供了一个&lt;em&gt;科学的、物质上的解释&lt;/em&gt;（缺氧），从而间接支持了Needham的“生命力”理论（虽然是以一种新的方式）。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;R2Q8.According to paragraphs 7 and 8, Pasteur&amp;rsquo;s experiment involving flasks with S-shaped necks proved that&lt;/p&gt;
&lt;p&gt;A. air does not cause microorganisms to arise spontaneously from nonliving matter&lt;/p&gt;
&lt;p&gt;B. microorganisms require access to nutrient fluids in order to arise spontaneously&lt;/p&gt;
&lt;p&gt;C. the temperature of liquids has no effect on the presence or absence of microorganisms&lt;/p&gt;
&lt;p&gt;D. microorganisms in the air cannot travel long distances&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Pasteur next placed broth in open-ended long-necked flasks and bent the necks into &lt;strong&gt;S-shaped curves&lt;/strong&gt;. The contents of these flasks were then boiled and cooled. The broth in the flasks did &lt;strong&gt;not decay and showed no signs of life&lt;/strong&gt;, even after months. Pasteur’s unique design &lt;strong&gt;allowed air to pass into the flask&lt;/strong&gt;, &lt;strong&gt;but the curved neck trapped any airborne microorganisms that might have contaminated the broth&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;最后一句回答了本题“&lt;strong&gt;巴斯德这一独特的设计使得空气能够进入烧瓶，而弯曲的瓶颈则截留了所有可能污染肉汤的空气中微生物。&lt;/strong&gt;”&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h4 id="tpo58"&gt;TPO58
&lt;/h4&gt;&lt;p&gt;R2Q3.Which of the following can be inferred about pinyon pines from paragraph 2 ?&lt;/p&gt;
&lt;p&gt;A. Seed predators other than pinyon jays feed on pinyon seeds&lt;/p&gt;
&lt;p&gt;B. Pinyon jays must eat many pinyon seeds to obtain adequate nutrition&lt;/p&gt;
&lt;p&gt;C. Seeds located in the interior regions of pinyon pines are particularly attractive to pinyon jays.&lt;/p&gt;
&lt;p&gt;D. Pinyon pines signal jays to eat only those seeds that are unable to grow.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;At first glance, the relationship between pinyon pine trees and the pinyon jay does not appear to be one of coevolution. Pinyon pines produce cones and seeds that attract seed predators, &lt;strong&gt;especially the pinyon jay&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;暗示 pinyon jay 是最主要或者最典型的种子捕食者，但并没有说它是唯一的种子捕食者&lt;/p&gt;
&lt;p&gt;Cones are positioned upward and outward on the tree, so the seeds inside are &lt;strong&gt;in plain sight of the jays&lt;/strong&gt;, essentially inviting them to partake Pinyon seeds are unusually large, and each seed is high in energy.&lt;/p&gt;
&lt;p&gt;并无证据表明attractive&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;R2Q4.According to paragraph 2, all the following are characteristics of pinyon pine seeds that make them attractive to seed predators EXCEPT:&lt;/p&gt;
&lt;p&gt;A. The seeds are highly visible&lt;/p&gt;
&lt;p&gt;B. The seeds contain a large amount of energy&lt;/p&gt;
&lt;p&gt;C. The seeds pass unharmed through the predator&amp;rsquo;s alimentary system&lt;/p&gt;
&lt;p&gt;D. The seed coat is thin.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;In many plants&lt;/strong&gt;, an indigestible seed coat permits the seed to pass unharmed through the bird’s alimentary system.&lt;/p&gt;
&lt;p&gt;显然C选项对应的不是pinyon pine seeds而是其它植物&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;R2Q5.The word &amp;ldquo;providing&amp;rdquo; in the passage is closest in meaning to&lt;/p&gt;
&lt;p&gt;A. Once&lt;/p&gt;
&lt;p&gt;B. since&lt;/p&gt;
&lt;p&gt;C. whenever&lt;/p&gt;
&lt;p&gt;D. if&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;首先看providing的原义：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;to give someone something that they need&lt;/li&gt;
&lt;li&gt;(of a law or decision) to say that something must happen if particular conditions exist&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;然后结合文章：This is a useful behavior for the jays, &lt;strong&gt;providing&lt;/strong&gt; they can retrieve some of the buried seeds during winter, and good for the trees, as the unretrieved seeds are ready to germinate.&lt;/p&gt;
&lt;p&gt;逻辑上，作者不是说“因为 jay 能在冬天找回种子，所以这对 jay 是好的行为”，而是说“这种行为对 jay 是好的，条件是它们冬天能找回一些”。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;R2Q6.The phrase &amp;ldquo;so many seeds&amp;rdquo; in the passage refers to
A. a number of seeds greater than jays can eat immediately
B. a number of seeds greater than jays can bury immediately
C. the number of seeds produced by one tree
D. the number of seeds that jays in a region need to eat&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Still, for the jays to bury any seeds, there must be an abundance of seeds &lt;strong&gt;far beyond the jays’ immediate needs&lt;/strong&gt;. One tree could never produce &lt;strong&gt;so many seeds&lt;/strong&gt;, but if all the pinyons in a region produced heavy seed crops at once, they would indeed &amp;ldquo;flood the market&amp;rdquo; with vastly more pinyon seeds than the local population of jays could consume.&lt;/p&gt;
&lt;p&gt;选项 &lt;strong&gt;B&lt;/strong&gt;：种子数量大于松鸦能立即埋藏的数量 —— 这里逻辑不对，因为“埋藏”本身就发生在种子充裕时，而“so many seeds”指的是充裕到超出当前食用需求，而不是超出它们“能埋”的物理能力。原文强调的是吃不完才埋，不是埋不完。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h4 id="20250525"&gt;20250525
&lt;/h4&gt;&lt;p&gt;R1Q6.Paragraph 4 suggests which of the following about the possibility of tapping methane hydrate deposits through drilling?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. Underwater oil and gas fields might get in the way of drilling.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B. Drilling vessels currently in existence cannot reach methane hydrate deposits.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;C. Hot water or steam that is pumped into deposits will reduce the amount of methane that can be extracted.&lt;/li&gt;
&lt;li&gt;D. Such drilling would have to be supported by government agencies because oil companies believe it to be too costly.&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Para.4&lt;/p&gt;
&lt;p&gt;Like conventional natural gas, the layers of methane hydrate could also be tapped by drilling. Several oil companies and government agencies are actively researching the possibility of such an endeavor. &lt;strong&gt;Because the deposits are far deeper than most underwater oil and gas fields, special deep water drilling vessels would have to be constructed.&lt;/strong&gt; Nevertheless, drilling is at least a possible option, although the methane ice is under so much pressure, the challenge is akin to bursting a balloon and trying to capture all the escaping gas. One potential solution would be to expel the methane by pumping hot water or steam into the deposit through one drill hole and extracting the expelled methane through another. But once recovered, the methane would still have to be brought ashore, and this would pose an additional challenge.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;甲烷水合物矿床位于比常规海底油气田 &lt;strong&gt;更深&lt;/strong&gt; 的位置。&lt;/li&gt;
&lt;li&gt;必须建造 &lt;strong&gt;特殊的深水钻井船&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;目前的钻井船（most underwater oil and gas fields 所用的船）&lt;strong&gt;不能达到&lt;/strong&gt; 这个深度。&lt;/li&gt;
&lt;/ol&gt;

 &lt;/blockquote&gt;
&lt;p&gt;R1Q9.Look at the squares that indicate where the following sentence can be added to the passage.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Moreover, many methane hydrate deposits are located close to high-population areas, where energy demands greatest.&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;And it has been found in enormous quantities, off the east coast of the United States near the Carolinas, for example, the United States Geological Survey, a scientific agency that studies natural resources, has discovered two deposits of methane hydrate, each covering about 3,139 square kilometers. ()Together they are estimated to contain over 37 trillion cubic meters of methane gas, or more than 50 times the amount of natural gas consumed in the United States in 2012. **(√)**Is methane hydrate the fuel of the future? ()The sheer volume and richness of methane hydrate deposits make them a strong candidate for development as an energy resource. However, the challenges are enormous.()&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Moreover通常用来连接两个同类性质的论点&lt;/li&gt;
&lt;li&gt;显然第一个空后的&amp;quot;together&amp;quot;代指前句内容，不应将句子填这&lt;/li&gt;
&lt;li&gt;第二个空前说明了这种资源的储量很大，填入句是指资源的位置好&lt;/li&gt;
&lt;/ol&gt;

 &lt;/blockquote&gt;
&lt;p&gt;R2Q2.According to paragraph 1, many scholars believe that iron smelting in Africa first began when the technique was&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A. brought by Phoenicians who settled on the North African coast&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;B. discovered by the Berbers around 1,000 B.C.E&lt;/li&gt;
&lt;li&gt;C. brought back from Phoenicia by seafaring African merchants&lt;/li&gt;
&lt;li&gt;D. discovered in Carthage in modern Tunisia around 800 B.C.E&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Many scholars believe that the secret of iron smelting (the process of extracting the iron from the rock that contains it) came with &lt;strong&gt;Phoenician merchants&lt;/strong&gt;. The Phoenicians living on the shores of the Mediterranean were smelting iron by 1,000 B.C.E. They were a seafaring people whose square-rigged ships sailed along the North African coast, where they &lt;strong&gt;established settlements&lt;/strong&gt; that became colonies.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;虽说文章确实提到&amp;quot;merchant&amp;rdquo;，但我们要注意&amp;quot;Phoenician merchants&amp;quot;和&amp;quot;African merchants&amp;quot;的区别&lt;/li&gt;
&lt;li&gt;再结合后文可知，Phoenician确实定居北非&lt;/li&gt;
&lt;/ol&gt;

 &lt;/blockquote&gt;
&lt;p&gt;R2Q4.The word &amp;ldquo;distinct&amp;rdquo; in the passage is closest in meaning to&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. permanent.&lt;/li&gt;
&lt;li&gt;B. basic.&lt;/li&gt;
&lt;li&gt;C. &lt;strong&gt;clear.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;D. fair.&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;ol&gt;
&lt;li&gt;在知道&amp;quot;distinct&amp;quot;原义为“明显的、清晰的”的情况下无需分析，但我错记成了“遥远的”（应为&amp;quot;distant&amp;rdquo;）&lt;/li&gt;
&lt;li&gt;文中生词，&amp;ldquo;division of labor&amp;rdquo;，在社会学和经济学中，&lt;strong&gt;division of labor&lt;/strong&gt; 指的是社会成员不再“每个人都做同样的事”，而是有了专门的职业划分。&lt;/li&gt;
&lt;/ol&gt;

 &lt;/blockquote&gt;
&lt;h4 id="20251206"&gt;20251206
&lt;/h4&gt;&lt;p&gt;R1Q2.According to paragraph 2, silk fibers have which of the following functions during the metamorphosis of silk moths?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. They provide a source of energy during the process&lt;/li&gt;
&lt;li&gt;B. They provide protein for the development of wings&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;C. They provide defense from threats.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;D. They speed up biochemical processes.&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;The cocoon is both a receptacle for this complex biochemical process and a means of protecting the defenseless insect from the environment and predators while it is metamorphosing. &lt;strong&gt;The silk fibers render the cocoon less palatable while also making it more difficult for would-be predators to get at the tasty protein-rich prize inside.&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;R1Q8.Paragraph 4 suggests which of the following about juvenile hormones?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. They lead to aggressive behavior in humans, wolves, and other mammals.&lt;/li&gt;
&lt;li&gt;B. They are formed during the synthesis of silk.&lt;/li&gt;
&lt;li&gt;C. They help spiders synthesize silk.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;D. They do not interfere with silk making by silkworms.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;It is equally fortuitous that at least some silkworms are even capable of coevolving with humans in a way that led to the animal partnership that we call domestication.&lt;/strong&gt; In the case of silkworms, &lt;strong&gt;it led to silk farming&lt;/strong&gt;, a practice first developed by the Chinese, who established a lucrative transcontinental silk trade near the end of the first millennium B.C.E. Domestication is always a two-way street in which another species must have the inherent capacity to tolerate and cooperate with humans. Silkworms&amp;rsquo; ability to tolerate domestication becomes evident if we compare them to spiders. Spiders actually produce a superior silken fiber, yet modern attempts at domesticating spiders have largely failed because they are very territorial creatures and will often eat one another if forced to live in close proximity. Indeed, spiders&amp;rsquo; need to make silk as adults—rather than just during a larval stage as with silkworms—may explain why they do not coexist well with other members of their own species. &lt;strong&gt;As is the case with mammals like wolves and humans, in many insects social behaviors are linked to juvenile hormones that make them more cooperative than aggressive.However, in spiders these juvenile hormones just happen to interfere with the biochemical synthesis of silk.&lt;/strong&gt; So for spiders to enjoy the many adaptive advantages that come from a lifetime of silk making, it appears they had to give up the many potential benefits of social cooperation.&lt;/p&gt;
&lt;p&gt;选项A由倒数第三局解释，选项C由倒数第二句的&amp;quot;interfere with&amp;quot;解释，意思是“干扰&amp;hellip;&amp;hellip;”而我却将其当作选C的论证了。&lt;/p&gt;
&lt;p&gt;既然家蚕既能表现出合作行为（意味着它们体内有起作用的幼年激素），又能成功大量造丝（silk farming），那么根据对比推论，&lt;strong&gt;家蚕体内的这种激素肯定没有干扰到它们的造丝过程&lt;/strong&gt;。与倒数第二句蜘蛛被干扰造丝形成对比。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;R2Q2.According to paragraph 1, radiocarbon dating is now the preferred method for determining the age of ancient biological specimens for all of the following reasons EXCEPT:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. It can be used to date specimens that are tens of thousands of years old.&lt;/li&gt;
&lt;li&gt;B. It is considered scientifically reliable.&lt;/li&gt;
&lt;li&gt;C. It can be used to date all materials that have radiocarbon.&lt;/li&gt;
&lt;li&gt;D. It can be used to determine whether organic acids have seeped into materials being tested.&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Because all living things contain carbon, artifacts and organic remains from archaeological sites can often be dated by comparing the proportion of carbon-14 (radiocarbon) remaining in them (or in the location where they were found) to the proportion of non-radiocarbon (carbon-12 and carbon-13) in them, a method called radiocarbon dating. This technique is based on the fact that the amount of carbon-12 and carbon-13 stays constant in organisms, while the amount of carbon-14 declines at a steady rate once the organism dies. When an animal or plant dies, it stops exchanging gases with the atmosphere and its carbon-14 begins to decrease. Thus the amount of carbon-14 remaining indicates how long ago an organism died. Radiocarbon is the preferred method for dating the sites of the earliest Americans. Its range reaches back 50,000 years, which is the period of interest, and its reliability is well attested since variations in atmospheric carbon levels over time have been well studied and can readily be adjusted for in age calculations. &lt;strong&gt;Moreover, the technique can be applied to any material that incorporates radiocarbon, such as bone, wood, charcoal (burned wood), and even soils, the last by virtue of the organic acids that seep into them.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;ldquo;by virtue of&amp;quot;的意思是“由于”，即把“酸的渗入”当作一个&lt;strong&gt;前提条件&lt;/strong&gt;，使得土壤具备了被检测的资格；而选项 D 把碳定年当作了&lt;strong&gt;检测手段&lt;/strong&gt;，去检测酸是否存在。这两者逻辑关系是颠倒的。碳定年的目的是&lt;strong&gt;测年份&lt;/strong&gt;，而不是测酸的渗入过程。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id="listening"&gt;Listening
&lt;/h3&gt;&lt;h4 id="tpo6-1"&gt;TPO6
&lt;/h4&gt;&lt;p&gt;C1Q3.What does the woman imply about the small print on the career fair posters and flyers?&lt;/p&gt;
&lt;p&gt;A. The information in the small print was incomplete.&lt;/p&gt;
&lt;p&gt;B. The print was smaller than she expected it to be.&lt;/p&gt;
&lt;p&gt;C. The information the small print contains will be updated.&lt;/p&gt;
&lt;p&gt;D. The information in the small print will be presented in a more noticeable way.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;对应原文&amp;quot;I mean, they all say where and when the fair is… just not who should attend.&lt;/p&gt;
&lt;p&gt;FEMALE EMPLOYEE: Actually, they do. But it’s in the &lt;strong&gt;small print&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;We should probably &lt;strong&gt;make that part easier to read&lt;/strong&gt;, shouldn&amp;rsquo;t we?&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll make a note of that right now.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;学生未能注意到&amp;quot;fair posters and flyers&amp;quot;上的小字，而不是没有相关的信息，所以不能选C而应该选D&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;C1Q4.What does the woman say is a good way for the student to prepare for speaking to companies’ representatives? Click on 2 answers.&lt;/p&gt;
&lt;p&gt;A. Take some business classes&lt;/p&gt;
&lt;p&gt;B. Familiarize himself with certain businesses beforehand&lt;/p&gt;
&lt;p&gt;C. Have questions ready to ask the representatives&lt;/p&gt;
&lt;p&gt;D. Talk to people who work for accounting firms&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;在学生提到&amp;quot;I was wondering if there’s anything you’d recommend that I do to prepare.&amp;ldquo;后，老师问完&amp;quot;I was wondering if there’s anything you’d recommend that I do to prepare.&amp;ldquo;后的&amp;quot;Well, I suggest that you get on the computer and learn more about the accounting companies, in particular, that will be attending.&lt;/p&gt;
&lt;p&gt;You can learn a lot about companies from their Internet Web sites.&lt;/p&gt;
&lt;p&gt;Then prepare a list of questions.&lt;/p&gt;
&lt;p&gt;MALE STUDENT: Questions… hmm. So in a way I’ll be interviewing them?&lt;/p&gt;
&lt;p&gt;FEMALE EMPLOYEE: That&amp;rsquo;s one way of looking at it.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;也就分别对应了B和C选项内容。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;C1Q5.Why does the student say this: &amp;ldquo;It looks like I&amp;rsquo;ve got some works to do.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;A. To acknowledge that he cannot go to this year’s career fair&lt;/p&gt;
&lt;p&gt;B. To acknowledge the amount of preparation he will have&lt;/p&gt;
&lt;p&gt;C. To indicate that he has school work he must complete before the career fair&lt;/p&gt;
&lt;p&gt;D. To indicate that he needs to go to his job now&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;原句在材料末尾，是在学生老师的建议并弄清楚了应该着手准备的事项后说的&lt;/p&gt;
&lt;p&gt;结合经验，即是C，最贴合原文主题的选项&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L1Q1.What is the main purpose of the talk?&lt;/p&gt;
&lt;p&gt;A. To show what happens after an economy has experienced a boom-and-bust cycle&lt;/p&gt;
&lt;p&gt;B. To illustrate the conditions needed to produce a boom-and-bust cycle&lt;/p&gt;
&lt;p&gt;C. To demonstrate how boom-and-bust cycles have changed over time&lt;/p&gt;
&lt;p&gt;D. To explain why the boom-and-bust cycle is not a frequent historical occurrence&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;本材料通过“郁金香(tulip)”的例子解释了&amp;rdquo;&lt;strong&gt;boom and bust&lt;/strong&gt;&amp;quot;，A和D明显有错，而C的观点只是被提到，但材料具体地只讲了一次&amp;quot;boom and bust&amp;quot;的例子。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L1Q6.The professor mentions the practice of trading promissory notes in the Netherlands in the 1630s. What does this practice explain? Click on 2 answers.&lt;/p&gt;
&lt;p&gt;A. Why tulips replaced gold as a form of currency&lt;/p&gt;
&lt;p&gt;B. Why buyers were no longer interested in owning actual tulips&lt;/p&gt;
&lt;p&gt;C. Why borrowing in the Netherlands increased on a significant scale&lt;/p&gt;
&lt;p&gt;D. Why the middle class in the Netherlands expanded in size&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;材料从&amp;quot;In other words, tulips were literally worth their weight in gold.&amp;ldquo;开始，后面就是&amp;rdquo; promissory notes&amp;quot;的相关内容，在&amp;quot;But that didn’t matter to the owner of the note. The owner &lt;strong&gt;only cared about having that piece of paper&lt;/strong&gt; so it could be traded later at a profit. &lt;strong&gt;And people were borrowing&lt;/strong&gt;, mortgaging their homes in many cases to obtain those bits of paper because they were sure they’d find an easy way to make money.&amp;ldquo;反映了B和C的内容。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L2Q1.What topics related to the Nightcap Oak does the professor mainly discuss? Click on 2 answers.&lt;/p&gt;
&lt;p&gt;A. Factors that relate to the size of the area in which it grows&lt;/p&gt;
&lt;p&gt;B. The size of its population over the last few centuries&lt;/p&gt;
&lt;p&gt;C. Whether anything can be done to ensure its survival&lt;/p&gt;
&lt;p&gt;D. Why it did not change much over the last one hundred million years&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;主题问题，材料前段就提到了其数量&amp;quot;two hundred&amp;rdquo;&lt;/p&gt;
&lt;p&gt;文章之后的讨论就是&amp;quot;factors to reproduce&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L2Q2.According to the professor, what led scientists to characterize the Nightcap Oak as primitive?&lt;/p&gt;
&lt;p&gt;A. It has no evolutionary connection to other trees growing in Australia today.&lt;/p&gt;
&lt;p&gt;B. It has an inefficient reproductive system.&lt;/p&gt;
&lt;p&gt;C. Its flowers are located at the bases of the leaves.&lt;/p&gt;
&lt;p&gt;D. It is similar to some ancient fossils.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;定位到材料&amp;quot;Uh we found &lt;strong&gt;fossils that old that bear a remarkable resemblance to the tree&lt;/strong&gt;.&amp;ldquo;&amp;ldquo;So, it&amp;rsquo;s a &lt;strong&gt;primitive tree&lt;/strong&gt;,a&amp;hellip; a living fossil, you might say.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;错选的A和材料表达的意思相反&amp;quot;And&amp;hellip; it—it’s probably a kind of tree from which other trees that grow in Australia today evolved.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L2Q3.What point does the professor make about the Nightcap Oak’s habitat?&lt;/p&gt;
&lt;p&gt;A. It is stable despite its limited size.&lt;/p&gt;
&lt;p&gt;B. Unlike the habitats of many plants, it is expanding.&lt;/p&gt;
&lt;p&gt;C. Its recent changes have left the Nightcap Oak struggling to adapt.&lt;/p&gt;
&lt;p&gt;D. Its size is much larger than the area where the Nightcap Oak grows.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;Uh, of course, you might think there might not be many areas where the tree could spread into, er … because … um … well, it’s very specialized in terms of the habitat. But, that’s not really the case here. Um … &lt;strong&gt;the suitable habitat, that is, the actual rainforest&lt;/strong&gt; is &lt;strong&gt;much larger than&lt;/strong&gt; the few hectares where the Nightcap Oak grows.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;在学生回答完问题后，教授的转折解释了&amp;quot;habitat&amp;rdquo;，并在后面解释了&amp;quot;the Nightcap Oak&amp;quot;种子的问题。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;这开头的对话错的有些多，且两篇材料的&amp;quot;Why does the student(teacher) say this&amp;hellip;&amp;ldquo;都有错，我认为随着做的题目增多，用意题和阅读是一个逻辑，大概率都在这句话的前文有提示。&lt;/p&gt;
&lt;p&gt;Lecture1讲的内容比较有趣，且一开始做的时候几乎没听懂，但题目做的还行，主要是说了“郁金香经济”的问题。&lt;/p&gt;
&lt;p&gt;Lecture2是个经典生物&amp;quot;habitat&amp;quot;类型的题，后面这种类型错的也不少，以本篇举例，重要的信息都在听力的“停顿”或者是“转折”上有所体现，且错的都是细节，只有多听了。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="tpo8"&gt;TPO8
&lt;/h4&gt;&lt;p&gt;C1Q1.Why does the man mention his classmates?&lt;/p&gt;
&lt;p&gt;A. To explain how he obtained information about field research&lt;/p&gt;
&lt;p&gt;B. To point out that many students like to do field research&lt;/p&gt;
&lt;p&gt;C. To show that it is difficult to get intermediate-level credits&lt;/p&gt;
&lt;p&gt;D. To emphasize his motivation to do field research in two of his courses&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;My chair person told me that if I did independent field research in addition to the assigned work in each course; they would count as intermediate level courses. My classmates, um, some of my classmates, &lt;strong&gt;did this for an easy way to meet their intermediate course requirement&lt;/strong&gt;, &lt;strong&gt;but I did it to get the kind of depth in those topics I was going for.&lt;/strong&gt;&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L1Q1.What is the main purpose of the lecture?&lt;/p&gt;
&lt;p&gt;A. To compare active habitat selection with passive habitat selection&lt;/p&gt;
&lt;p&gt;B. To show that most habitat preferences in animals are learned&lt;/p&gt;
&lt;p&gt;C. To compare the habitat requirements of several bird species&lt;/p&gt;
&lt;p&gt;D. To examine the consequences of habitat selection by animals&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;不知道为什么错选，明显是D&lt;/p&gt;
&lt;p&gt;&amp;ldquo;With active habitat selection, an organism is able to physically select where to live and breed, and because an animal’s breeding habitat is so important&amp;hellip;&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L1Q3.What does the professor illustrate with the example of the blue warbler?&lt;/p&gt;
&lt;p&gt;A. The relationship between human activity and habitat loss&lt;/p&gt;
&lt;p&gt;B. The relationship between habitat and reproductive success&lt;/p&gt;
&lt;p&gt;C. The advantages of habitats with low vegetation density&lt;/p&gt;
&lt;p&gt;D. The reproductive advantage that young warblers have over older warblers&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;首先错选的C，&amp;ldquo;so they&amp;rsquo;re pretty close to the ground but these warblers also nest in forests that have low shrub density.&amp;ldquo;虽然提到了&amp;quot;density&amp;quot;但和vegetation无关，&amp;ldquo;density&amp;quot;译为“密度”。&lt;/p&gt;
&lt;p&gt;关于正确选项B，&amp;rdquo;**And the choice of habitat seems to affect reproductive success.**Because the older, more experienced birds, who nest in the high-density shrub areas, &lt;strong&gt;have significantly more offspring than those in low-density areas&lt;/strong&gt;. Which suggests that the choice of where to nest does have an impact on the number of chicks they have.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;通过讲&amp;quot;blue warbler&amp;quot;的&amp;quot;younger warbler&amp;quot;和&amp;quot;older warbler&amp;quot;选择栖息地的密度不同，体现了栖息地对&amp;quot;offspring&amp;quot;译为“幼崽”的影响。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L1Q4.Why does the professor mention the population density of blackcaps in two different habitats?&lt;/p&gt;
&lt;p&gt;A. To explain the similar reproductive rates in the two habitats&lt;/p&gt;
&lt;p&gt;B. To explain the relation between a species’ population density and its nesting behavior&lt;/p&gt;
&lt;p&gt;C. To illustrate the advantages of a preferred habitat over a secondary habitat&lt;/p&gt;
&lt;p&gt;D. To illustrate the possible impact of making a poor habitat selection&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;首先要注意题干的&amp;quot;population density&amp;rdquo;，然后注意本题的重点在&amp;quot;blackcap&amp;quot;的前半部分，而非下一题所需的后半部分，即不选D。&amp;ldquo;Studies have been done on the &lt;strong&gt;reproductive success rates&lt;/strong&gt; for the birds in both areas and the results showed—surprisingly—&lt;strong&gt;that the reproductive success was essentially the same in both areas&lt;/strong&gt;—the preferred and the second choice habitat.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;C选项则和材料相反，B无关。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;TPO8和TPO6都主要错在了生物题材的Lecture上，但TPO8的生物部分更加有逻辑且复杂一些，讲了几种鸟。至于对话题的错因和TPO6一样。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="tpo9"&gt;TPO9
&lt;/h4&gt;&lt;p&gt;C1Q3.The woman mentions a research study of milk packaging. What was the finding of the study?&lt;/p&gt;
&lt;p&gt;A. Plastic containers may change the flavor of milk.&lt;/p&gt;
&lt;p&gt;B. Light may negatively affect the quality of milk.&lt;/p&gt;
&lt;p&gt;C. People prefer to buy milk in see-through containers.&lt;/p&gt;
&lt;p&gt;D. Opaque containers are effective in protecting milk from bacteria.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;对应材料&amp;quot;Yeah, and I read a study that showed &lt;strong&gt;how light can give milk a funny flavor&lt;/strong&gt; and decrease its nutritional value.&amp;ldquo;这句话语速很快且&amp;quot;light&amp;quot;不是很好听出来，容易错选成后面出现的&amp;quot;Well, consumers like being able to visually examine the color of the milk.&amp;ldquo;相关的选项C，但这和研究无关。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L2Q2.According to the professor, what are two features of shrubs that allow them to grow well in Arctic regions? Click on 2 answers.&lt;/p&gt;
&lt;p&gt;A. They have roots that can penetrate permafrost.&lt;/p&gt;
&lt;p&gt;B. Their height allows them to absorb more sunlight.&lt;/p&gt;
&lt;p&gt;C. They absorb nutrients from the soil efficiently.&lt;/p&gt;
&lt;p&gt;D. They have a shallow root system.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;首先，在女学生提出了永冻层之后，老师开始解释&amp;quot;shrub&amp;quot;的特性，及它的根不会很深，也就排除了A选项，选择了D。在男学生提出问题后，就是对&amp;quot;shrub&amp;quot;为什么在夏季成长的更好，以及选C的原因：&amp;ldquo;Well, it may be biological processes that occur in the soil in the winter that cause increased shrub growth in the summer. And, here’s how: there are microbes, microscopic organisms that live in the soil.&lt;/p&gt;
&lt;p&gt;These &lt;strong&gt;microbes enable the soil to have more nitrogen, which plants need to live&lt;/strong&gt;, and they remain quite active during the winter.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;这段语速较慢且有停顿，算是比较好听出来&amp;quot;nitrogen&amp;quot;来对应&amp;quot;nutrients&amp;rdquo;。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L2Q3.What is one reason for the increase in shrub growth in Arctic Alaska?&lt;/p&gt;
&lt;p&gt;A. Decreases in grass and moss growth have altered the balance of nutrients in the soil.&lt;/p&gt;
&lt;p&gt;B. Increases in ground temperature have led to increased microbial activity.&lt;/p&gt;
&lt;p&gt;C. Increases in average winter temperatures have made permafrost permeable to water.&lt;/p&gt;
&lt;p&gt;D. Increases in snowfall have provided more water for shrubs.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;原因同L2Q2的C选项。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L2Q5.Why does the professor mention shrub expansion into other environments, such as semiarid grasslands?&lt;/p&gt;
&lt;p&gt;A. To suggest that new shrubland may not convert back to tundra&lt;/p&gt;
&lt;p&gt;B. To explain how shrubland can expand in a warm climate&lt;/p&gt;
&lt;p&gt;C. To cite a similarity between the types of shrubs in semiarid grassland and tundra environments&lt;/p&gt;
&lt;p&gt;D. To explain how a biological loop can cause shrub expansion&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;用意题，首先排除C，然后是注意在教授讲&amp;quot;expansion&amp;quot;的问题之前，女学生问了&amp;quot;But will it be long-term?I mean, maybe the shrubs will be abundant for a few years, &lt;strong&gt;and then it’ll change back to tundra&lt;/strong&gt;.&amp;ldquo;那么A是最直接的选项，至于B，原文的意思应该是有了&amp;quot;shrub&amp;quot;的生长，&amp;ldquo;shrubland&amp;quot;的扩张会持续下去，而不是因为&amp;quot;warm climate&amp;rdquo;。错选的D选项，虽然意思上没错且前文有提到，但如果学生不发出提问，则不会有这段&amp;quot;expansion&amp;quot;的解释。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L3Q2.What is the professor’s opinion about the conclusions of the recent study of the limestone formations in the Empty Quarter?&lt;/p&gt;
&lt;p&gt;A. They have changed the way geologists study desert environments.&lt;/p&gt;
&lt;p&gt;B. They contradict findings about similar desert lakes.&lt;/p&gt;
&lt;p&gt;C. They explain the causes of monsoons in the desert.&lt;/p&gt;
&lt;p&gt;D. They need to be confirmed by additional studies.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;limestone&amp;quot;出现在&amp;quot;But the Empty Quarter lakes disappeared thousands of years ago. They left behind their beds, or basins, as limestone formations that we can still see today. They look like low-lying white or gray buttes … long, narrow hills with flat tops … barely a meter high.&amp;ldquo;结合后文&amp;quot;Keep in mind, though, that this study only looked at 19 formations … and about a thousand have been documented, so there’s a lot more work to be done.&amp;ldquo;可得出D选项，难在要注意听到&amp;quot;limestone&amp;quot;一词。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L3Q3.According to the professor, what feature of the sand dunes made the formation of the lakes possible?&lt;/p&gt;
&lt;p&gt;A. The degree of slope of the sides of the dunes&lt;/p&gt;
&lt;p&gt;B. The presence of clay and silt particles in the dunes&lt;/p&gt;
&lt;p&gt;C. The position of the dunes relative to the wind and rain&lt;/p&gt;
&lt;p&gt;D. The narrowness of the valleys between the dunes&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;在明显的&amp;quot;Second&amp;hellip;&amp;ldquo;后就是&amp;quot;sand dunes&amp;quot;的内容&amp;quot;Now, when the rain fell, water ran down the sides of the dunes, carrying clay and silt particles with it. And wherever these particles settled, they formed a pan … a layer that water couldn&amp;rsquo;t penetrate. Once this pan formed, further runoff collected and formed a lake.&amp;ldquo;逻辑还是很清晰的，要注意听到&amp;quot;clay and silt&amp;quot;&amp;ldquo;particles&amp;quot;&amp;ldquo;couldn&amp;rsquo;t penetrate&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L3Q5.What does the professor imply about the lack of water buffalo and hippopotamus fossils in the more recent lakes?&lt;/p&gt;
&lt;p&gt;A. The level of water in the lakes was not sufficient for these animals.&lt;/p&gt;
&lt;p&gt;B. The bottoms of the lakes were too sandy for these animals to stand in.&lt;/p&gt;
&lt;p&gt;C. The location of the lakes made them too difficult for these animals to reach.&lt;/p&gt;
&lt;p&gt;D. The vegetation near the lakes did not attract these animals.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;文章最后的部分提到了&amp;quot;water buffalo and hippopotamus fossils&amp;quot;但先不需要知道其意思，接着听会发现，其大意是&amp;quot;lakes&amp;quot;只供饮用水，且动物种类少，最后&amp;quot;We&amp;rsquo;re not sure why. Uh, maybe there was a problem with the water … maybe it was too salty. That&amp;rsquo;s certainly true of other desert lakes.&amp;ldquo;指出了A选项。至于错选的C选项，与本段之前的内容矛盾&amp;quot;But … where did these animals come from? Well, the theory that has been suggested is that they migrated in from nearby habitats where they were already living.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;这套TPO9就是真的听不出细节的问题，听的时候应该也没有做逻辑笔记，然后关键词也听不到导致的。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="tpo10"&gt;TPO10
&lt;/h4&gt;&lt;p&gt;L2Q1.What is the main purpose of the lecture?&lt;/p&gt;
&lt;p&gt;A. To describe the trade in food crops between Europe and the Americas&lt;/p&gt;
&lt;p&gt;B. To describe the introduction of American food crops to Europeans&lt;/p&gt;
&lt;p&gt;C. To describe the influence of American food crops on traditional European dishes&lt;/p&gt;
&lt;p&gt;D. To describe the difficulties of growing American food crops in European climates&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;文章专注于介绍美洲的各种作物被引入欧洲，但没有提及欧洲菜肴的变化等，明显选B。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L2Q3.What does the professor imply about Thomas Jefferson’s attitude toward tomatoes?&lt;/p&gt;
&lt;p&gt;A. It was typical of his unconventional way of thinking.&lt;/p&gt;
&lt;p&gt;B. It helped to advance his political career.&lt;/p&gt;
&lt;p&gt;C. It changed the eating habits of North Americans.&lt;/p&gt;
&lt;p&gt;D. It helped to make tomatoes popular in Europe.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;FEMALE PROFESSOR: Oh, sure—&lt;strong&gt;people didn’t really start eating them here&lt;/strong&gt; until the mid-1800s.&lt;/p&gt;
&lt;p&gt;FEMALE STUDENT: But, ah—seems like I heard…didn’t Thomas Jefferson grow them or something?&lt;/p&gt;
&lt;p&gt;FEMALE PROFESSOR: Ah! Well, that’s true…but, then, Jefferson is known not only as the third President of the United States, but also as &lt;strong&gt;a scholar who was way ahead of his time—in many ways!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;结合上下文，以及最关键的&amp;quot;scholar&amp;quot;&amp;ldquo;way ahead of his time&amp;quot;可以得出&amp;quot;Jefferson&amp;quot;思想超前。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;C2Q3.Why is the professor not going to discuss the book by Jane Bowles in the class?&lt;/p&gt;
&lt;p&gt;A. There is not enough time left in the semester.&lt;/p&gt;
&lt;p&gt;B. Not all of the students were able to get a copy of the book.&lt;/p&gt;
&lt;p&gt;C. The professor miscalculated the difficulty level of the book.&lt;/p&gt;
&lt;p&gt;D. The book was not on the course syllabus.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;材料提到，&amp;ldquo;There’re only 2 weeks of classes left in the semester and there are like 6 books on the syllabus that we haven’t even touched.&amp;ldquo;指向选项A，但错选的C选项在其前一句&amp;quot;Um.. I think my professor really miscalculated. Anyway the syllabus, was way too ambitious in my opinion.&amp;ldquo;出现了&amp;quot;miscalculate&amp;quot;但其对象应该是&amp;quot;time&amp;quot;而非&amp;quot;difficulty&amp;rdquo;。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L3Q6.What does the professor mean when she says this:&lt;/p&gt;
&lt;p&gt;A. She realizes that the students are struggling with the concept.&lt;/p&gt;
&lt;p&gt;B. She is surprised that the student knew the answer to her question.&lt;/p&gt;
&lt;p&gt;C. She thinks that the answer to the question is obvious.&lt;/p&gt;
&lt;p&gt;D. She thinks that this phase of the cycle has an unusual name.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;FEMALE PROFESSOR: Can anyone guess what it’s called? Nancy?&lt;/p&gt;
&lt;p&gt;FEMALE STUDENT: Uh, well, if the one is called the land phase, then this has to be called the water phase, right?&lt;/p&gt;
&lt;p&gt;FEMALE PROFESSOR: Yes. &lt;strong&gt;That’s such a difficult point, isn’t it?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;看似是说其&amp;quot;difficult&amp;quot;实则是反义，从学生的回答也能看出&amp;quot;land phase&amp;quot;&amp;ldquo;then water phase&amp;rdquo;，加之教授的语气，并无错选的B选项表达的&amp;quot;surprised&amp;rdquo;，所以选C，教授这句话隐含的意思是“这个问题只有这样的难度”。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L4Q3.What does the professor imply about some of the explanations for childhood amnesia that she describes?&lt;/p&gt;
&lt;p&gt;A. They can never be proved or disproved.&lt;/p&gt;
&lt;p&gt;B. They were formed without proper evidence.&lt;/p&gt;
&lt;p&gt;C. They explain only certain types of childhood amnesia.&lt;/p&gt;
&lt;p&gt;D. They are contradicted by her own research.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;“Well, once a popular explanation was that childhood memories are repressed … uh, the memories are disturbing so that as adults we keep them buried, and so we can’t recall them. And this is based on … well, well, it’s not based on, on, on the kind of solid research and lab testing I want to talk about today …”听力中有明显停顿来突出&amp;quot;not based on &amp;hellip; &amp;ldquo;即这种说法并无根据。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L4Q4.The professor mentions some commonly held explanations for childhood amnesia. Indicate whether each of the following is one of the explanations she mentions.&lt;/p&gt;
&lt;p&gt;A. Early memories are repressed.&lt;/p&gt;
&lt;p&gt;B. Young children have few experiences to remember.&lt;/p&gt;
&lt;p&gt;C. Young children are unable to form memories.&lt;/p&gt;
&lt;p&gt;D. Children lose memories at a faster rate than adults.&lt;/p&gt;
&lt;p&gt;E. Young children do not make an effort to remember events.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;It—it could be that as children we do form memories of things prior to age 3, but forget them as we grow older. That’s one explanation.&lt;/p&gt;
&lt;p&gt;Another possibility is that children younger than 3 lack, um, lack some cognitive capacity for memory. And that idea… um, that children are unable to form memories, um… that’s been the dominant belief in psychology for the past hundred years.&lt;/p&gt;
&lt;p&gt;这段话中包含了正确的AC选项，但难在原题不会告诉要选几个，且D选项对应的答案在接近最后的&amp;quot;And childhood amnesia may reflect a high rate of forgetting. In other words, children under the age of 3 do form memories, and do so without language.&lt;/p&gt;
&lt;p&gt;But they forget the memories at a fast rate, probably faster than adults do.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L4Q5.How was recall tested in children without language ability?&lt;/p&gt;
&lt;p&gt;A. By recording children&amp;rsquo;s responses to familiar faces&lt;/p&gt;
&lt;p&gt;B. By observing children&amp;rsquo;s reaction to a repeated series of actions&lt;/p&gt;
&lt;p&gt;C. By having children imitate each other &amp;rsquo;s actions&lt;/p&gt;
&lt;p&gt;D. By having children imitate an ordered sequence of actions&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;Now, if the children can’t talk, how was recall tested?&amp;ldquo;在这之后一段讲解实验过程：&amp;ldquo;The children were asked to imitate the steps immediately, and then again after delays of 1 or more months. And, even after a delay, the children could-could recall, or replicate the action - the objects used, &lt;strong&gt;the steps involved and the order of the steps&lt;/strong&gt;. Even children as young as 9 months!&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;TPO10的Lecture4，是比较少见的心理学题材，且答案多藏于大段的对话中，难度较高。此外，Lecture3的&amp;quot;That’s such a difficult point, isn’t it?&amp;ldquo;要通过上下文和语气来判断，是道有趣的题目。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="tpo11-1"&gt;TPO11
&lt;/h4&gt;&lt;p&gt;C2Q2.Why does the student say he is interested in doing what the professor asks?&lt;/p&gt;
&lt;p&gt;A. He thinks it may help him improve his research skills.&lt;/p&gt;
&lt;p&gt;B. He thinks it will enable him to get a better grade in the professor’s class.&lt;/p&gt;
&lt;p&gt;C. He thinks it may help him get into graduate school.&lt;/p&gt;
&lt;p&gt;D. He thinks it will be good teaching practice for him.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;FEMALE PROFESSOR: So I&amp;rsquo;d like to know if you&amp;rsquo;d be willing to join as a student representative on the interview committee. It’d be a good experience for you. You could&amp;hellip; uh&amp;hellip; put it on your résumé.&lt;/p&gt;
&lt;p&gt;MALE STUDENT: Oh! That&amp;rsquo;d look good for my grad school application, I guess. So what do I have to do?&lt;/p&gt;
&lt;p&gt;关键词&amp;quot;resume&amp;quot;和&amp;quot;grad school application&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;C2Q4.Why does the professor mention that one of the applicants will give a talk on a topic the student is particularly interested in?&lt;/p&gt;
&lt;p&gt;A. To see if the student would enjoy joining the applicant’s research team&lt;/p&gt;
&lt;p&gt;B. To suggest that the student may not totally agree with what the applicant has to say&lt;/p&gt;
&lt;p&gt;C. To persuade the student to come to a talk on Friday&lt;/p&gt;
&lt;p&gt;D. To warn the student to focus on the applicant’s teaching ability&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;学生提到&amp;quot;That’s&amp;hellip;that&amp;rsquo;s what my research is about!&amp;quot;，即可得出和C选项的时间无关，B选项无提及，而A选项在前面就已确定学生回去参加，但参加的理由和题干的意思无关。&lt;/p&gt;
&lt;p&gt;回到材料&amp;quot;That&amp;rsquo;s why I feel it necessary to point out that even though this applicant&amp;rsquo;s research interests are similar to yours, we want you to tell us &lt;strong&gt;what you think about the teaching of all these applicants&lt;/strong&gt;. Your perspective as a student &amp;ndash; &lt;strong&gt;how the applicant teaches in the classroom&lt;/strong&gt; &amp;ndash;&amp;ldquo;教授在&amp;quot;how the applicant teaches in the classroom&amp;quot;进行强调，即确认参与者的教学情况，不难得出D选项。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id="tpo13"&gt;TPO13
&lt;/h4&gt;&lt;p&gt;C2Q5.What does the woman imply?&lt;/p&gt;
&lt;p&gt;A. She confused the man for another student who had visited the lab earlier in the day.&lt;/p&gt;
&lt;p&gt;B. The man is mistaken about how many videos are in the series.&lt;/p&gt;
&lt;p&gt;C. The language lab does not own the whole series of videos the man needs.&lt;/p&gt;
&lt;p&gt;D. The man is not familiar with the procedures used at the language lab.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Student: So, I can just take….err…..Can I take the whole series home? I think there are three of them.
Manager: I guess you &lt;strong&gt;haven’t&lt;/strong&gt; been here before.&lt;/p&gt;
&lt;p&gt;题干的音频对应文章开头部分的&amp;quot;I guess you haven’t been here before.&amp;ldquo;错选时是把&amp;quot;haven&amp;rsquo;t&amp;quot;错听成了&amp;quot;have&amp;quot;导致和材料后面的内容联系起来了，但正确听到&amp;quot;haven&amp;rsquo;t&amp;quot;便不难选出D选项。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L3Q3.According to the professor what is true about the hero in chanson poetry and the in romance poetry? Click in the correct box for each phrase (A: Chanson hero B:Romance hero)&lt;/p&gt;
&lt;p&gt;A. Is admired for loyalty country&lt;/p&gt;
&lt;p&gt;B. Engages in conflict for adventure&lt;/p&gt;
&lt;p&gt;C. Is willing to fact extreme dangers to protect the lord&lt;/p&gt;
&lt;p&gt;D. Is concerned with individual improvement&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;“Well, there’s a hero, a knight, who goes to battle, and he is admired for his courage, bravery and loyalty, &lt;strong&gt;loyalty to the lord he serves&lt;/strong&gt;, his country and his fellow warriors in the field. He’s &amp;hellip;.um&amp;hellip; he has a, he’s a skilled fighter, &lt;strong&gt;willing to face the most extreme dangers&lt;/strong&gt;, sacrificial, willing to sacrifice anything and everything to protect his king and country.”属于&amp;quot;Chanson poetry&amp;quot;特点，即AC。
“&lt;strong&gt;He does it for the sake of adventure, to improve himself&lt;/strong&gt;, to show he’s worthy of respect and love from his lady. He’s very conscious of the particular rules of social behavior he has to live up to somehow. And all of his actions are for the purpose of proving that he is an upright, moral, well-mannered, well-behaved &lt;strong&gt;individual&lt;/strong&gt;.”属于&amp;quot;Romance poetry&amp;quot;特点，即BD。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L3Q4.Why does the professor mention that romance poems often included biographical sketches?&lt;/p&gt;
&lt;p&gt;A. To emphasize the similarities between chanson authors and romance authors&lt;/p&gt;
&lt;p&gt;B. To explain why the social status of troubadours is known today&lt;/p&gt;
&lt;p&gt;C. To point out why the biographical sketches are reliable sources of information&lt;/p&gt;
&lt;p&gt;D. To provide evidence that many troubadours were also historians&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;首先要明确&amp;quot;romance poems&amp;quot;是指&amp;quot;troubadours&amp;rdquo;, &amp;ldquo;Another name for romance poetry that’s often synonymous with it is troubadour poetry.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;之后注意关键词&amp;quot;And we know a lot more about the troubadours than we do about the chanson authors because they often had small &lt;strong&gt;biographical sketches&lt;/strong&gt; added to their poems that &lt;strong&gt;gave pretty specific information about their social status&lt;/strong&gt;, geographical location, and a small outline of their career.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id="tpo14"&gt;TPO14
&lt;/h4&gt;&lt;p&gt;C2Q3.According to the advisor, how do newspaper editors evaluate an applicant for a reporting position? Click on 2 answers.&lt;/p&gt;
&lt;p&gt;A. They ask the applicant to present ideas for news stories.&lt;/p&gt;
&lt;p&gt;B. They ask the applicant to write a news story.&lt;/p&gt;
&lt;p&gt;C. They review the applicant’s university course work.&lt;/p&gt;
&lt;p&gt;D. They review a sample of the applicant’s published articles.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;“mean when you apply for a reporting job, editors look at two things&amp;mdash; they want to see clips, you know, &lt;strong&gt;some of your published articles&lt;/strong&gt;, they’ll also want you to try out, they’ll give you an assignment like… covering a press conference or some other event, then see &lt;strong&gt;if you can craft a story about it&lt;/strong&gt;, accurately, on deadline.”&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;C2Q5.What does the student imply when he says this:&lt;/p&gt;
&lt;p&gt;A. He was surprised by the amount of effort required to write a newspaper article.&lt;/p&gt;
&lt;p&gt;B. He feels that some of the editor’s changes were unnecessary.&lt;/p&gt;
&lt;p&gt;C. He does not want to take credit that he does not deserve.&lt;/p&gt;
&lt;p&gt;D. He will try to make sure his future articles are more accurate.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Student: &amp;ldquo;&lt;strong&gt;To be honest, the article got lots of editing&lt;/strong&gt;. In fact I barely recognized a couple of paragraphs. But the editor explained why the changes were made. I learned a lot and my second article didn&amp;rsquo;t need nearly as many changes.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;定位到原文，是在教授&amp;quot;And I read that article, too. It was very good.&amp;ldquo;后说的，所以学生的意思应该是表达自谦，那么关于&amp;quot;take credit that&amp;quot;的意思：&lt;/p&gt;
&lt;p&gt;To &lt;strong&gt;take the credit for&lt;/strong&gt; something means to &lt;strong&gt;claim recognition or praise for an achievement or action&lt;/strong&gt;, often implying that one is taking credit for work that may not solely belong to them. For example, you might say, &amp;ldquo;I can&amp;rsquo;t take credit for this,&amp;rdquo; indicating that you do not believe you deserve the recognition. This phrase can also suggest a sense of &lt;strong&gt;self-promotion or appropriation of others&amp;rsquo; efforts&lt;/strong&gt;, as in &amp;ldquo;You took credit for my work&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id="tpo56-1"&gt;TPO56
&lt;/h4&gt;
 &lt;blockquote&gt;
 &lt;p&gt;MALE PROFESSOR: With a major in philosophy..besides the possibility of grad school—which I think would be wonderful for you—you know lots of things that are valuable in any career&lt;/p&gt;
&lt;p&gt;FEMALE STUDENT: Like what? How Johnson tried to refute Berkeley’s empiricism?&lt;/p&gt;
&lt;p&gt;MALE PROFESSOR: Well&amp;hellip; what did Johnson do?&lt;/p&gt;
&lt;p&gt;FEMALE STUDENT: Well, you know&amp;hellip; what Berkeley said was that we can’t really know any objects, we can just perceive them. It’s all about our senses perceiving things. Berkeley basically made the point that it doesn’t really make sense to believe in actual, physical matter&amp;hellip; What Johnson did was, Johnson was trying to disprove that, so he kicked a big stone. He said that refuted Berkeley.&lt;/p&gt;
&lt;p&gt;MALE PROFESSOR: Uh-huh. So, what do you think of that?&lt;/p&gt;
&lt;p&gt;FEMALE STUDENT: &lt;strong&gt;Well, not that I’m convinced by Berkeley either, but I really don’t think Johnson refuted anything.&lt;/strong&gt; And I think Berkeley would just say that Johnson still doesn’t know anything apart from what he senses. Seeing the stone, feeling his foot hurting after he kicked it—&lt;strong&gt;it’s all still just based on his perceptions. Johnson can’t argue that he knows anything other than what his senses have told him.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;MALE PROFESSOR: You know what you just did?&lt;/p&gt;
&lt;p&gt;FEMALE STUDENT: Told you &lt;strong&gt;something that’s not relevant anywhere but a philosophy class&lt;/strong&gt;?&lt;/p&gt;
&lt;p&gt;MALE PROFESSOR: No. You demonstrated well-developed analytical skills. Philosophy majors can critique other people’s reasoning, make a convincing argument, summarize&amp;hellip; and communicate very effectively. &lt;strong&gt;These things are important in any career. And in life!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;FEMALE STUDENT: OK, but&amp;hellip; still! You don’t see any of that in job descriptions!&lt;/p&gt;
&lt;p&gt;MALE: Really? Oh, I think you do. I’ve seen so many articles lately, by heads of companies in all kinds of fields, complaining that it’s hard to find employees who can do that. Ask at the career services office—&lt;strong&gt;they’ll tell you the same thing&lt;/strong&gt;.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;C1Q3.Why does the student mention Johnson and Berkeley?&lt;/p&gt;
&lt;p&gt;A. To cast doubt on something the professor said&lt;/p&gt;
&lt;p&gt;B. To get the professor’s opinion about a topic from class&lt;/p&gt;
&lt;p&gt;C. To indicate that she wishes to change the subject&lt;/p&gt;
&lt;p&gt;D. To check whether she has understood a philosophical argument&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;由&amp;quot;Like what? How Johnson tried to refute Berkeley’s empiricism?&amp;ldquo;&amp;ldquo;Told you &lt;strong&gt;something that’s not relevant anywhere but a philosophy class&lt;/strong&gt;?&amp;ldquo;这两句可知，学生讲了一个自己认为只和哲学有关而与就业无关的故事，来反驳材料上面，教授一开始提及的&amp;quot;you know lots of things that are valuable in any career&amp;rdquo;。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;C1Q4.What does the student imply about Johnson&amp;rsquo;s argument?&lt;/p&gt;
&lt;p&gt;A. It is more convincing than Berkeley&amp;rsquo;s argument.&lt;/p&gt;
&lt;p&gt;B. It disproves an accepted theory.&lt;/p&gt;
&lt;p&gt;C. it demonstrates the existence of physical matter&lt;/p&gt;
&lt;p&gt;D. It fails to prove the point he was trying to make.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;细节题&amp;quot;FEMALE STUDENT: &lt;strong&gt;Well, not that I’m convinced by Berkeley either, but I really don’t think Johnson refuted anything.&lt;/strong&gt; And I think Berkeley would just say that Johnson still doesn’t know anything apart from what he senses. Seeing the stone, feeling his foot hurting after he kicked it—&lt;strong&gt;it’s all still just based on his perceptions. Johnson can’t argue that he knows anything other than what his senses have told him.&lt;/strong&gt;&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;C1Q5.Why does the professor tell the student to go to the career services office?&lt;/p&gt;
&lt;p&gt;A. To research summer internship opportunities&lt;/p&gt;
&lt;p&gt;B. To ask how to include her skills on her resume&lt;/p&gt;
&lt;p&gt;C. To read job descriptions for careers in philosophy&lt;/p&gt;
&lt;p&gt;D. To confirm that her skills are valuable to employers&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;这里要注意&amp;rdquo;&lt;strong&gt;career services office&lt;/strong&gt;&amp;ldquo;的内容不要和后面的&amp;rdquo;&lt;strong&gt;our department&lt;/strong&gt;&amp;ldquo;的搞混，关于&amp;quot;career services office&amp;quot;只提到了&amp;quot;Ask at the career services office—they’ll tell you the &lt;strong&gt;same thing&lt;/strong&gt;.&amp;ldquo;而这个&amp;quot;same thing&amp;quot;代指了前文的&amp;rdquo; &amp;hellip; complaining that it’s hard to find employees who can do that.&amp;quot;“很多公司高管抱怨找不到能够批判性思考的员工”&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;C2Q2.Why do the students want to get to the theater early?&lt;/p&gt;
&lt;p&gt;A. To purchase their concert tickets&lt;/p&gt;
&lt;p&gt;B. To avoid rush hour traffic&lt;/p&gt;
&lt;p&gt;C. To be able to get good seats&lt;/p&gt;
&lt;p&gt;D. To have time to eat dinner&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;细节题，但是和时间有关的信息有些多，错选的时候混掉了，&amp;ldquo;We already have tickets, but this theater doesn’t have assigned seating—so we need to get there early—like around seven thirty—&lt;strong&gt;to get good seats&lt;/strong&gt;.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;C2Q5.What information will the woman give the man tomorrow?&lt;/p&gt;
&lt;p&gt;A. The cost of the concert tickets&lt;/p&gt;
&lt;p&gt;B. The hourly charges for van drivers&lt;/p&gt;
&lt;p&gt;C. The amount of money the students need to deposit&lt;/p&gt;
&lt;p&gt;D. The amount of money the students still owe&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;FEMALE EMPLOYEE: I’ll have to run a few numbers to get the final cost. Vans are a lot cheaper than buses but we’ll have to pay for two drivers—they’ll charge us by the hour. Of course, you’ll get the normal student discount from the van company, and I’ll deduct your deposit. I can let you know the balance tomorrow.&lt;/p&gt;
&lt;p&gt;经济学的词汇不足问题，&amp;ldquo;deposit&amp;quot;表示钱的时候，有“存款；预付款，定金；押金”的意思，&amp;ldquo;deduct&amp;quot;为“减，减去；扣除”，&amp;ldquo;owe&amp;quot;为“欠债；该偿还”，&amp;ldquo;balance&amp;quot;为“结存，结余；差额”&lt;/p&gt;
&lt;p&gt;雇员问学生今天有没有带押金(deposit)，学生说带了，说他同学都知道之后还得再付押金之外的更多的钱，雇员说我明天算好把差额(balance)告诉你。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L3Q1.What aspect of archaeology in Iceland does the professor mainly discuss?&lt;/p&gt;
&lt;p&gt;A. Various techniques for dating archaeological sites&lt;/p&gt;
&lt;p&gt;B. Causes of damage to a Viking-era house&lt;/p&gt;
&lt;p&gt;C. Evidence of early agricultural tools&lt;/p&gt;
&lt;p&gt;D. A method for locating buried structures&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;BC易排除，回看材料，前半部分都在交代冰岛的背景，以及移民&amp;quot;Thorfinsson&amp;quot;的故事，而后半部分，从&amp;quot;But, back to my point&amp;hellip; one team of archaeologists working there decided to use an electromagnetic remote sensing tool to try to locate buried structures.&amp;ldquo;介绍了这个工具的原理，以及考古学家如何用它来找到了遗迹。文章最后再点题&amp;quot;Thank goodness for the remote sensing tool, or this house might never have been found!&amp;ldquo;表明了重点是这个&amp;quot;tool&amp;quot;而没有&amp;quot;various techniques&amp;rdquo;。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L3Q4.According to the professor ,what kind of data does the remote sensing tool provide?&lt;/p&gt;
&lt;p&gt;A. The approximate age of different types of buried structures&lt;/p&gt;
&lt;p&gt;B. The electrical conductivity of the ground at different locations&lt;/p&gt;
&lt;p&gt;C. The chemical composition of different types of soil and peat&lt;/p&gt;
&lt;p&gt;D. The temperature of the ground at different depths&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;结合材料&amp;quot;So the tool sends down &lt;strong&gt;alternating currents of electricity and then measures how well the electric current travels though the ground in different places&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Then you look at all of your data&amp;hellip; look for patterns of electrical resistance&amp;hellip; and this reveals where walls are located.&amp;rdquo; 可见与选项B同义。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;这一套TPO的听力确实是难做，第一篇的哲学，一下子大段的&amp;quot;Johnson and Berkeley&amp;rdquo;，且充斥着&amp;quot;perceive&amp;quot;这样的哲学词汇，听了4遍才可以说是明白了。&lt;/p&gt;
&lt;p&gt;第二篇对话就是最后算钱的部分，各种词汇量不足的问题了。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="tpo57-1"&gt;TPO57
&lt;/h4&gt;&lt;p&gt;L2Q2.Why does the professor mention rocks from Earth’s moon?&lt;/p&gt;
&lt;p&gt;A. To compare the surface of Earth’s moon to the surface of a moon of Jupiter&lt;/p&gt;
&lt;p&gt;B. To stress the need for further exploration of space&lt;/p&gt;
&lt;p&gt;C. To explain a way of calculating the absolute age of surfaces of planets or moons&lt;/p&gt;
&lt;p&gt;D. To show how to identify a secondary impact on the surface of Earth’s moon&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;But &lt;strong&gt;absolute age, actual age&lt;/strong&gt;, is trickier. We have to know exactly how old one surface is. For example, we do have a very clear idea of the ages of some surfaces of the moon from &lt;strong&gt;rocks&lt;/strong&gt; we brought back and then this information can allow us to extrapolate the age of another surface that has a similar concentration of craters.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L2Q6.What does the professor imply about information obtained from space probes?&lt;/p&gt;
&lt;p&gt;A. The information was probably distorted during transmission to Earth&lt;/p&gt;
&lt;p&gt;B. The information helped determine the age of most planetary surface features.&lt;/p&gt;
&lt;p&gt;C. Some of the information is at present difficult to interpret correctly&lt;/p&gt;
&lt;p&gt;D. The information applies only to the moons of Jupiter.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;You know, we&amp;rsquo;re getting great information and photos from our space probes all the time, &lt;strong&gt;but&lt;/strong&gt; they also remind us of &lt;strong&gt;just how much more we need to learn&lt;/strong&gt;.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;Lecture2是太空学话题，经典的听不太懂，然后在这一篇上试了下精听法，确实能把这篇听得很明白，但有些耗时间，换了新题效果就不好说。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="20250531---1"&gt;20250531 - 1
&lt;/h4&gt;&lt;p&gt;C1Q5.Why does the man say this to the student:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I&amp;rsquo;d be happy to answer your question, but are you a psychology major?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. To recommend an appropriate professor as her departmental advisor&lt;/li&gt;
&lt;li&gt;B. To confirm that she has already taken an introductory psychology course&lt;/li&gt;
&lt;li&gt;C. To let her know which psychology courses she is required to take&lt;/li&gt;
&lt;li&gt;D. To determine if she is eligible to assist professors in the department&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;显然此句出现在对话的开始部分，那么结合后面说有两个不合适的工作来看，应该是选D的&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t doubt your interest in psychology. It&amp;rsquo;s just that unfortunately, the part time jobs we have for students are either grading homework or else being &lt;strong&gt;a research assistant&lt;/strong&gt; for one of the professors. But you wouldn&amp;rsquo;t qualify for either of those until at least your third year. Have you tried the student employment office?&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;C2Q2.Why does the man mention that he saw a golden eagle in the wild?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. To make a point about the rarity of golden eagles in the local area&lt;/li&gt;
&lt;li&gt;B. To ask if course credit is given for independent fieldwork&lt;/li&gt;
&lt;li&gt;C. To suggest a news item for the biology department&amp;rsquo;s Web site&lt;/li&gt;
&lt;li&gt;D. To question a finding of a wildlife survey about golden eagles&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;And I actually saw a golden eagle at a tree near the river last winter. &lt;strong&gt;I’ve lived here in&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Minnesota all my life and had never seen a golden eagle in the wild before&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;(woman) I know. Golden eagles didn’t use to visit our area on any regular basis. But&lt;/p&gt;
&lt;p&gt;according to winter wildlife surveys done over the past few years, around sixty had begun&lt;/p&gt;
&lt;p&gt;hanging out around the cliffs overlooking the upper Mississippi river during the month of&lt;/p&gt;
&lt;p&gt;January.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;C2Q3.According to the woman, what prompted some members of the biology faculty to apply for a grant?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. Their desire to increase the number of internships offered to biology students.&lt;/li&gt;
&lt;li&gt;B. Their interest in upgrading the department&amp;rsquo;s radio-tracking technology&lt;/li&gt;
&lt;li&gt;C. The recent appearance of golden eagles wintering nearby&lt;/li&gt;
&lt;li&gt;D. A proposal by a graduate student to conserve the golden eagle&amp;rsquo;s winter habitat&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;(woman) When the winter survey showed a pattern, Professor Simmons and some other&lt;/p&gt;
&lt;p&gt;faculty thought the first step of understanding these birds would be to track their&lt;/p&gt;
&lt;p&gt;movements. So they applied for a research &lt;strong&gt;grant&lt;/strong&gt; and got it.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L3Q3.Why does the professor mention Thomas Jefferson?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. To cite a contemporary account of the weather written in 1816&lt;/li&gt;
&lt;li&gt;B. To explain the origin of a theory about the Sun’s magnetic cycles&lt;/li&gt;
&lt;li&gt;C. To give Jefferson credit for sending explorers to carefully study volcanoes&lt;/li&gt;
&lt;li&gt;D. To show how the strange weather events affected Jefferson’s presidency&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;There was widespread snowfall in June, followed by more cold spells in July and&lt;/p&gt;
&lt;p&gt;August. Historians can point to a number of contemporary diaries from the northeast and&lt;/p&gt;
&lt;p&gt;beyond, including Jefferson’s, that’s Thomas Jefferson of course, a former president who&lt;/p&gt;
&lt;p&gt;had retired to his home down in Virginia, diaries that recorded and remarked on the&lt;/p&gt;
&lt;p&gt;extraordinarily cold temperatures that year.&lt;/p&gt;
&lt;p&gt;A选项是指“引用1816年所写的一篇关于天气的当代记述”，即用名人Jefferson的记载来说明当年的情况。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h4 id="20251015"&gt;20251015
&lt;/h4&gt;&lt;p&gt;C1Q5.What does the student imply when she says this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Oh, you’re right! Oh, but no, I don’t think they actually let us take reserved books out of the library, like, you have to sit there and read them. So as much as I’d love to just live in the library these next couple of weeks!&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. She is already using too many library books.&lt;/li&gt;
&lt;li&gt;B. She does not have time to do all of the reading in the library.&lt;/li&gt;
&lt;li&gt;C. She would rather use a library book than buy her own copy.&lt;/li&gt;
&lt;li&gt;D. She prefers studying in the library to studying in her room.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;C2Q3.What does the professor emphasize about the play The Adding Machine?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. It was the first Surrealist play.&lt;/li&gt;
&lt;li&gt;B. It was more popular than other Expressionist plays.&lt;/li&gt;
&lt;li&gt;C. Its characters sang or danced to express their happiness.&lt;/li&gt;
&lt;li&gt;D. It used very few props.&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;(woman) Not really. Although that one play, &lt;strong&gt;The Adding Machine&lt;/strong&gt;, that you were just alluding to with all the paper.
(man) Yeah?
(woman) That one did &lt;strong&gt;attract a large audience&lt;/strong&gt; when it first came out, perhaps because it was more accessible than your typical expressionist play, which might have seemed even stranger.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L2Q6.What does the professor imply about the debate over Olmsted’s proposal?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. It showed off Olmsted’s stubbornness in refusing to compromise his ideas.&lt;/li&gt;
&lt;li&gt;B. It caused delays in the completion of the park.&lt;/li&gt;
&lt;li&gt;C. It was motivated largely by economic considerations.&lt;/li&gt;
&lt;li&gt;D. It led to the inclusion of ideas from some of the losing plans.&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;There was a great deal of debate, a lot of it &lt;strong&gt;political&lt;/strong&gt; in nature, but, eventually, Olmsted accepted the &lt;strong&gt;compromise&lt;/strong&gt; that actually turned out to work in the park’s favor.&lt;/p&gt;
&lt;p&gt;原文中明确提到，批评者中有人希望修改方案，以“&lt;strong&gt;包含一些出现在落选方案（losing plans）中的想法&lt;/strong&gt;”。教授接着说，奥姆斯特德最终“&lt;strong&gt;接受了妥协（accepted the compromise）&lt;/strong&gt;”。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id="20251108"&gt;20251108
&lt;/h4&gt;&lt;p&gt;L3Q4.What is the professor&amp;rsquo;s attitude regarding the destruction of the Cassini spacecraft?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. He suspects that it resulted from a mechanical problem.&lt;/li&gt;
&lt;li&gt;B. He recognized that it was necessary.&lt;/li&gt;
&lt;li&gt;C. He is surprised that it happened so quickly.&lt;/li&gt;
&lt;li&gt;D. He is impressed by the efforts undertaken to avoid it.&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;And so in April 2017, the scientists and engineers in control of the mission used the remaining fuel to change Cassini&amp;rsquo;s orbit and &lt;strong&gt;send the spacecraft hurdling into Saturn, where it burned up in Saturn&amp;rsquo;s thick atmosphere.&lt;/strong&gt; Couldn&amp;rsquo;t they have kept it going until it ran out of fuel?&lt;/p&gt;
&lt;p&gt;科学家们是有意利用最后的燃料改变轨道，让它在土星大气层中烧毁，以彻底消除后文的风险（If that happened, we&amp;rsquo;d be changing the Enceladus environment before we had a chance to fully explore it. We&amp;rsquo;d never know what Enceladus was like originally.）。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;L3Q6.Why does the professor make the point that the existence of liquid water on Enceladus was a discovery made by the Cassini spacecraft?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. To argue for the importance of space missions such as the Cassini mission&lt;/li&gt;
&lt;li&gt;B. To make a contrast between the Cassini mission and earlier missions to Saturn.&lt;/li&gt;
&lt;li&gt;C. To emphasize the sophistication of the instruments on the Cassini spacecraft.&lt;/li&gt;
&lt;li&gt;D. To justify a decision that was made before the Cassini spacecraft was launched.&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Well, when Cassini was launched in 1997, we didn&amp;rsquo;t know yet about Enceladus&amp;rsquo;s ocean. &lt;strong&gt;That ocean was discovered in the course of the Cassini mission when the spacecraft orbited that moon&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;教授说，消毒级别取决于该航天器进入支持生命的世界的可能性。而在 1997 年 Cassini &lt;strong&gt;发射时&lt;/strong&gt;，“我们还不知道土卫二有海洋（we didn&amp;rsquo;t know yet about Enceladus&amp;rsquo;s ocean）”。&lt;/p&gt;
&lt;p&gt;教授强调这个发现是在任务过程中才做出的，是为了&lt;strong&gt;证明（justify）当初发射时为什么没有采取最高级别消毒措施这一决定&lt;/strong&gt;是合理的——因为在当时的认知下，没有必要。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id="speaking"&gt;Speaking
&lt;/h3&gt;&lt;h4 id="tpo60"&gt;TPO60
&lt;/h4&gt;&lt;p&gt;Q1.A university wants to require all students to have their own laptop computers. Do you agree or disagree with this policy? Give specific reasons to support your opinion.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;[Main Point]&lt;/strong&gt; &amp;ldquo;I strongly agree with the policy that all students should have their own laptops.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;[Transition]&lt;/strong&gt; &amp;ldquo;I feel this way primarily because it creates a &lt;strong&gt;distraction-free and highly efficient&lt;/strong&gt; learning environment.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;[Deep Support]&lt;/strong&gt; &amp;ldquo;&lt;strong&gt;Specifically&lt;/strong&gt;, having a personal device allows students to customize their study tools and access a &lt;strong&gt;vast number of online materials&lt;/strong&gt; instantly during lectures. &lt;strong&gt;For example&lt;/strong&gt;, last semester, when I was preparing for a complex math exam, I used my laptop to search for video tutorials and academic papers right in the library. &lt;strong&gt;In contrast&lt;/strong&gt;, if I had to rely on school desktop computers, I would have wasted a lot of time queuing and transferring files, which is quite &lt;strong&gt;frustrating&lt;/strong&gt;. By having my own laptop, I could stay focused, which helped me &lt;strong&gt;recharge&lt;/strong&gt; my passion for the subject and ultimately achieve &lt;strong&gt;full marks&lt;/strong&gt;.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;[Conclusion]&lt;/strong&gt; &amp;ldquo;Thus, the convenience and efficiency it provides make it an indispensable tool for students.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;效率 角度&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="tpo63"&gt;TPO63
&lt;/h4&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;State Main Point&lt;/strong&gt; &amp;ldquo;I disagree with the statement that teachers should not be too friendly to their students.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transition&lt;/strong&gt; &amp;ldquo;I feel this way primarily because a friendly teacher can &lt;strong&gt;significantly boost a student’s confidence&lt;/strong&gt; and interest in learning.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Deep Support (核心展开)&lt;/strong&gt; &amp;ldquo;&lt;strong&gt;Specifically&lt;/strong&gt;, when a teacher is approachable and encouraging, students feel safe to ask questions without being judged. &lt;strong&gt;For example&lt;/strong&gt;, I used to struggle with chemistry and was too shy to speak up because I feared making mistakes. However, my teacher was always smiling and comforting, which made me feel &lt;strong&gt;refreshed&lt;/strong&gt; and more willing to study harder. &lt;strong&gt;In contrast&lt;/strong&gt;, if she had been strict or distant, I would have stayed frustrated and likely failed the final exam. Thanks to her kindness, I finally obtained &lt;strong&gt;full marks&lt;/strong&gt; and developed a lifelong interest in the subject.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt; &amp;ldquo;Therefore, I believe friendliness is an essential quality for effective teaching.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;心理 角度&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="tpo64"&gt;TPO64
&lt;/h4&gt;&lt;p&gt;Q1.Some people prefer to get information from books. Others prefer using a computer to access information via the Internet. Which do you prefer?&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;State Your Main Point&lt;/strong&gt; &amp;ldquo;I definitely prefer using a computer to access information via the Internet rather than relying on books.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transition&lt;/strong&gt; &amp;ldquo;I feel this way primarily because the Internet offers &lt;strong&gt;unparalleled efficiency&lt;/strong&gt; and a much wider variety of resources.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Deep Support (Reinforced)&lt;/strong&gt; &amp;ldquo;&lt;strong&gt;Specifically&lt;/strong&gt;, searching for information online allows for instant results, which &lt;strong&gt;eliminates the need&lt;/strong&gt; to spend hours in a library. &lt;strong&gt;For example&lt;/strong&gt;, last week I had to research a complex historical event for a class assignment. By simply typing keywords into a search engine, I accessed dozens of academic articles and primary sources in seconds. &lt;strong&gt;In contrast&lt;/strong&gt;, if I had used physical books, I would have struggled to find updated information, making the process much more &lt;strong&gt;frustrating&lt;/strong&gt; and time-consuming. This &lt;strong&gt;convenient&lt;/strong&gt; access helped me complete my work early and obtain &lt;strong&gt;full marks&lt;/strong&gt;.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt; &amp;ldquo;Therefore, I believe the speed and accessibility of the Internet make it a far superior tool for learning.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;效率 角度&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="tpo65"&gt;TPO65
&lt;/h4&gt;&lt;p&gt;Q1.Do you agree or disagree with the following statement? Having power and money is the best definition of success.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;State Your Main Point&lt;/strong&gt; &amp;ldquo;I strongly disagree with the idea that having power and money is the best definition of success.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transition&lt;/strong&gt; &amp;ldquo;I feel this way primarily because I believe true success is defined by &lt;strong&gt;personal fulfillment&lt;/strong&gt; and making a &lt;strong&gt;positive impact&lt;/strong&gt; on others.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Deep Support (Reinforced)&lt;/strong&gt; &amp;ldquo;&lt;strong&gt;Specifically&lt;/strong&gt;, relying solely on material wealth can lead to a hollow life, whereas pursuing one&amp;rsquo;s passion leads to long-term happiness. &lt;strong&gt;For example&lt;/strong&gt;, I have an uncle who was a high-paid corporate executive with immense power, but he was always &lt;strong&gt;stressed out&lt;/strong&gt; and rarely saw his family. Eventually, he quit to become a high school teacher. Although he earns less money now, he feels much more &lt;strong&gt;refreshed&lt;/strong&gt; and &lt;strong&gt;fulfilled&lt;/strong&gt; because he is helping students achieve &lt;strong&gt;full marks&lt;/strong&gt; and grow. &lt;strong&gt;In contrast&lt;/strong&gt;, if he had stayed in his powerful position, he would have remained miserable despite his bank account. This proves that &lt;strong&gt;personal growth&lt;/strong&gt; and helping others provide a much deeper sense of accomplishment.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt; &amp;ldquo;Therefore, I believe that happiness and contribution are far better measures of success than mere wealth or status.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id="tpo66"&gt;TPO66
&lt;/h4&gt;&lt;p&gt;Q1.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;State Your Main Point&lt;/strong&gt; &amp;ldquo;I agree with the point of view that a college education is not strictly necessary for a successful career.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transition&lt;/strong&gt; &amp;ldquo;I feel this way primarily because real-world &lt;strong&gt;practical skills&lt;/strong&gt; and &lt;strong&gt;personal passion&lt;/strong&gt; often override theoretical knowledge in many industries.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Deep Support&lt;/strong&gt; &amp;ldquo;&lt;strong&gt;Specifically&lt;/strong&gt;, success is increasingly defined by one&amp;rsquo;s ability to solve problems rather than just holding a degree. &lt;strong&gt;For example&lt;/strong&gt;, many successful entrepreneurs in the technology sector started their own businesses based on a unique idea and self-taught coding skills. &lt;strong&gt;In contrast&lt;/strong&gt;, if they had spent four years only focusing on textbooks in a classroom, they might have missed the &lt;strong&gt;keen competition&lt;/strong&gt; and fast-changing trends of the market. By following their own &lt;strong&gt;learning pace&lt;/strong&gt; and gaining hands-on experience, they were able to achieve &lt;strong&gt;personal fulfillment&lt;/strong&gt; and even create job opportunities for others. This proves that while college is valuable, it is not the only path to becoming a &lt;strong&gt;mature adult&lt;/strong&gt; with a flourishing career.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt; &amp;ldquo;Therefore, I believe that determination and practical experience are the true drivers of success.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id="tpo67"&gt;TPO67
&lt;/h4&gt;&lt;p&gt;Q1.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;State Your Main Point&lt;/strong&gt; &amp;ldquo;I believe it is a much better idea for international students to stay with a &lt;strong&gt;host family&lt;/strong&gt; rather than living on their own.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transition&lt;/strong&gt; &amp;ldquo;I feel this way primarily because it offers a cost-effective way to &lt;strong&gt;master a second language&lt;/strong&gt; in a natural environment.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Deep Support (核心展开)&lt;/strong&gt; &amp;ldquo;&lt;strong&gt;Specifically&lt;/strong&gt;, living with locals is the most &lt;strong&gt;efficient&lt;/strong&gt; way to improve speaking skills because you are forced to communicate in the target language daily. &lt;strong&gt;For example&lt;/strong&gt;, instead of just learning from textbooks, you can practice real-life conversations during dinner, which helps &lt;strong&gt;broaden your horizons&lt;/strong&gt;. &lt;strong&gt;Moreover&lt;/strong&gt;, it significantly &lt;strong&gt;saves money and transportation fees&lt;/strong&gt;. Host families often provide meals and furniture, which &lt;strong&gt;alleviates monetary pressure&lt;/strong&gt; for students. &lt;strong&gt;In contrast&lt;/strong&gt;, if a student lives alone, they not only pay higher rent but also lack the opportunity to interact with native speakers, often feeling isolated. This &lt;strong&gt;convenient&lt;/strong&gt; arrangement ensures students can focus more on their studies and achieve &lt;strong&gt;full marks&lt;/strong&gt;.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt; &amp;ldquo;Therefore, the linguistic and financial benefits make a host family the superior choice.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;经济 + 社交 角度&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="tpo68"&gt;TPO68
&lt;/h4&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;State Your Main Point&lt;/strong&gt; &amp;ldquo;I disagree with the statement that all workers should be required to retire by age sixty-five.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transition&lt;/strong&gt; &amp;ldquo;I feel this way primarily because continuing to work can significantly &lt;strong&gt;improve mental health&lt;/strong&gt; and utilize the &lt;strong&gt;valuable experience&lt;/strong&gt; of older employees.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Deep Support (核心展开)&lt;/strong&gt; &amp;ldquo;&lt;strong&gt;Specifically&lt;/strong&gt;, many individuals at sixty-five are still physically active and find a great sense of &lt;strong&gt;personal fulfillment&lt;/strong&gt; through their careers. &lt;strong&gt;For example&lt;/strong&gt;, my grandfather continued to work as a consultant after sixty-five; this &lt;strong&gt;constant interaction&lt;/strong&gt; with colleagues kept him &lt;strong&gt;refreshed&lt;/strong&gt; and prevented the social isolation often associated with retirement. &lt;strong&gt;Moreover&lt;/strong&gt;, older workers possess &lt;strong&gt;sophisticated skills&lt;/strong&gt; and profound knowledge that younger staff may lack. &lt;strong&gt;In contrast&lt;/strong&gt;, if companies force these experts to retire prematurely, they lose a wealth of wisdom, which can lead to &lt;strong&gt;inefficiency&lt;/strong&gt; in the workplace. Staying active in one&amp;rsquo;s profession is a &lt;strong&gt;crucial&lt;/strong&gt; way for seniors to stay connected to society.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt; &amp;ldquo;Therefore, I believe retirement should be a personal choice based on an individual&amp;rsquo;s health and capability rather than a fixed age.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;心理 角度&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="tpo69"&gt;TPO69
&lt;/h4&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;State Your Main Point&lt;/strong&gt; &amp;ldquo;I personally prefer to take a lot of photographs during family gatherings or meetings with friends.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transition&lt;/strong&gt; &amp;ldquo;I feel this way primarily because photos serve as a lasting record of &lt;strong&gt;personal fulfillment&lt;/strong&gt; and happiness.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Deep Support (Reinforced)&lt;/strong&gt; &amp;ldquo;&lt;strong&gt;Specifically&lt;/strong&gt;, capturing these special moments allows me to relive the joy whenever I feel &lt;strong&gt;stressed out&lt;/strong&gt; in the future. &lt;strong&gt;For example&lt;/strong&gt;, during our last family reunion, I took dozens of pictures of us laughing and sharing a meal. Now, whenever I face a heavy workload at school, looking at those photos helps me feel &lt;strong&gt;refreshed&lt;/strong&gt; and reminds me of the support I have. &lt;strong&gt;In contrast&lt;/strong&gt;, if I didn&amp;rsquo;t take any photos, those precious memories might fade over time, leaving me with nothing to look back on during challenging times. This simple act ultimately &lt;strong&gt;boosts my confidence&lt;/strong&gt; and mental well-being.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;心理 角度&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="tpo70"&gt;TPO70
&lt;/h4&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;State Your Main Point&lt;/strong&gt; &amp;ldquo;When I was a child, I much preferred playing games outdoors because I believe it is the most effective way to &lt;strong&gt;improve social skills&lt;/strong&gt;.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transition&lt;/strong&gt; &amp;ldquo;I feel this way primarily because outdoor activities often require teamwork and constant interaction with peers.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Deep Support (核心展开)&lt;/strong&gt; &amp;ldquo;&lt;strong&gt;Specifically&lt;/strong&gt;, playing sports like soccer or hide-and-seek forces children to communicate, negotiate, and cooperate to achieve a common goal. &lt;strong&gt;For example&lt;/strong&gt;, I remember spending every afternoon at the local park with a large group of neighborhood kids. Through these games, I learned how to resolve conflicts and support my teammates, which &lt;strong&gt;boosted my confidence&lt;/strong&gt; in social situations. &lt;strong&gt;In contrast&lt;/strong&gt;, if I had stayed inside playing video games alone, I would have missed these crucial opportunities to &lt;strong&gt;broaden my horizons&lt;/strong&gt; and build lasting friendships. This early experience in a &lt;strong&gt;vibrant&lt;/strong&gt; social environment eventually helped me become a more communicative and &lt;strong&gt;mature adult&lt;/strong&gt;.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt; &amp;ldquo;Therefore, I believe outdoor play is essential for developing the interpersonal skills needed for future success.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;社交 角度&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="tpo71"&gt;TPO71
&lt;/h4&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;State Your Main Point&lt;/strong&gt; &amp;ldquo;I personally agree with the statement that the process of doing something is more important than the final result.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transition&lt;/strong&gt; &amp;ldquo;I feel this way primarily because the process is where true &lt;strong&gt;personal growth&lt;/strong&gt; occurs and where we develop &lt;strong&gt;essential skills&lt;/strong&gt; for the future.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Deep Support (核心展开)&lt;/strong&gt; &amp;ldquo;&lt;strong&gt;Specifically&lt;/strong&gt;, even if the end result is not perfect, the dedication and persistence we show during the process help foster a &lt;strong&gt;diligent personality&lt;/strong&gt;. &lt;strong&gt;For example&lt;/strong&gt;, I remember when I first started learning to play the piano. At first, I couldn&amp;rsquo;t play even a simple scale fluently, let alone beautiful melodies. However, I kept practicing unfamiliar passages for hours every day. Although I didn&amp;rsquo;t win any major competitions in the end, that &lt;strong&gt;constant interaction&lt;/strong&gt; with the music and the effort I put in &lt;strong&gt;boosted my confidence&lt;/strong&gt; and taught me the value of persistence. &lt;strong&gt;In contrast&lt;/strong&gt;, if I only cared about the result, I would have felt &lt;strong&gt;frustrated&lt;/strong&gt; by my early failures and given up, missing out on this chance to improve my &lt;strong&gt;characteristic&lt;/strong&gt;. I believe these internal gains are much more valuable than any trophy.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt; &amp;ldquo;Therefore, the journey and the lessons learned along the way are what truly define success.&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id="writing"&gt;Writing
&lt;/h3&gt;&lt;h4 id="20250315---academic-discussion"&gt;20250315 - Academic Discussion
&lt;/h4&gt;&lt;h5 id="reading-2"&gt;Reading
&lt;/h5&gt;&lt;p&gt;Your professor is teaching a class on sociology.Write a post responding to the professor&amp;rsquo;s question.In your response,you should do the following:express and support your personal opinion;make a contribution to the discussion in your own words.
An effective response will contain at least 100 words.&lt;/p&gt;
&lt;p&gt;Dr.Achebe:This week,we will be discussing space exploration.Some people think that it is a waste of money for governments to fund space exploration.Others disagreewith this view arguing that space exploration is a valuable and necessary investment for our future.They think that it is worthy for governments to fund space exploration. I want to know what you think about this topic. Do you think that governments should fund space exploration?Why or why not?&lt;/p&gt;
&lt;p&gt;Kelly: I don&amp;rsquo;t think that governments should fund space exploration because it will be too costly to build spaceships and develop related technologies.Though space exploration tech costs billions,it doesn&amp;rsquo;t offer direct benefits to most people,which makes its funding a controversial issue&lt;/p&gt;
&lt;p&gt;Andrew: Personally, I do think that all the costs will be worth it. The potential scientific discoveries and technological advancements could have far-reaching impacts that justify the initial investment.Imagine the new inventions that might come from this exploration.Such technology could greatly improve our everyday lives.&lt;/p&gt;
&lt;h5 id="write-up"&gt;Write-up
&lt;/h5&gt;&lt;p&gt;As far as I am concerned, governments should fund space exploration, since it will definitely promote the development of technology and improve our daily lives.&lt;/p&gt;
&lt;p&gt;To be more specific, space exploration drives technological innovations, and many space technologies are adapted for civilian use, directly improving people&amp;rsquo;s quality of life and promoting the prosperity of related industries.&lt;/p&gt;
&lt;p&gt;For instance, there are seeds of organic vegetable being brought to space station or other plants like the Mars, result in more productive and highly adaptable species, due to space exploration.&lt;/p&gt;
&lt;p&gt;Nevertheless, some state that it&amp;rsquo;s too costly for governments to fund space exploration. However, with the funding of government, space exploration will show its massive value, which promote economic increase and make civilian life better.&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;实际上手一写，发现语言匮乏，且Concession部分不是很会，所幸有AI帮助，我认为解决了总结段的重复问题&lt;/p&gt;
&lt;p&gt;将 &lt;code&gt;promote the development&lt;/code&gt; 改为 &lt;code&gt;catalyzes technological breakthroughs&lt;/code&gt;（催化技术突破），表达更有力度。&lt;/p&gt;
&lt;p&gt;将 &lt;code&gt;seeds of organic vegetable being brought to space&lt;/code&gt; 修正为更专业的 &lt;code&gt;agricultural experiments in microgravity environments&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;使用了 &lt;code&gt;incubator&lt;/code&gt; (孵化器) 和 &lt;code&gt;economic dividends&lt;/code&gt; (经济红利) 等词汇，使论证从“科学研究”自然过渡到“经济价值”。&lt;/p&gt;
&lt;p&gt;原稿最后一段只是在重复自己的观点。修改版使用了 &lt;strong&gt;&amp;ldquo;short-sighted view&amp;rdquo; (短视)&lt;/strong&gt; 来定性 Kelly 的观点，并解释了“短期投入”与“长期回报”的关系。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h5 id="answer-generated-by-gemini"&gt;Answer generated by Gemini
&lt;/h5&gt;&lt;p&gt;As far as I am concerned, governments should prioritize funding space exploration, as it inevitably catalyzes technological breakthroughs that refine our daily lives.&lt;/p&gt;
&lt;p&gt;To be more specific, space research often acts as an incubator for civilian innovations, directly enhancing public welfare and industrial prosperity. For instance, &lt;strong&gt;agricultural experiments in microgravity environments&lt;/strong&gt;—such as those conducted on the International Space Station—have led to the development of &amp;ldquo;space seeds.&amp;rdquo; These genetically resilient crops offer significantly higher yields and better resistance to pests, providing a tangible solution to global food security.&lt;/p&gt;
&lt;p&gt;While Kelly argues that the exorbitant costs make space funding controversial, I believe this is a short-sighted view. Although the initial capital outlay is massive, the subsequent &lt;strong&gt;economic dividends&lt;/strong&gt;—from job creation in high-tech sectors to the birth of entirely new industries—far outweigh the costs, making it a vital investment for any visionary government.&lt;/p&gt;
&lt;hr&gt;</description></item><item><title>计算机组成原理</title><link>https://ottercoconut.github.io/p/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/</link><pubDate>Wed, 10 Sep 2025 00:00:00 +0000</pubDate><guid>https://ottercoconut.github.io/p/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/</guid><description>&lt;p&gt;课程源自B站“湖科大教学匠”的《计算机组成微课堂》 &lt;a class="link" href="https://www.bilibili.com/video/BV1qG41197E4/?share_source=copy_web&amp;amp;vd_source=440fb90b593ac5ecf9b12f264d73b53b" target="_blank" rel="noopener"
 &gt;https://www.bilibili.com/video/BV1qG41197E4/?share_source=copy_web&amp;vd_source=440fb90b593ac5ecf9b12f264d73b53b&lt;/a&gt;
BV1qG41197E4&lt;/p&gt;
&lt;h3 id="11-计算机系统的组成"&gt;1.1 计算机系统的组成
&lt;/h3&gt;&lt;p&gt;计算机系统分为 &lt;strong&gt;硬件&lt;/strong&gt; 和 &lt;strong&gt;软件&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;其中，硬件包括 &lt;strong&gt;主机&lt;/strong&gt; 和 &lt;strong&gt;外设&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;软件包括 &lt;strong&gt;系统软件&lt;/strong&gt; 和 &lt;strong&gt;应用软件&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;计算机系统性能的好坏，取决于硬件和软件功能的总和&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="12-计算机的发展"&gt;1.2 计算机的发展
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;第一台真正意义上的电子数字计算机&lt;/strong&gt; ：ABC&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一台实用的电子数字计算机&lt;/strong&gt; ：ENIAC&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;计算机硬件的发展&lt;/strong&gt; ：电子管计算机 -&amp;gt; 晶体管计算机 -&amp;gt; 集成电路计算机 -&amp;gt; 超大规模集成电路&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;计算机软件的发展&lt;/strong&gt; ：机器语言 -&amp;gt; 汇编语言 -&amp;gt; 高级语言 -&amp;gt; 面向对象&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="13-计算机硬件"&gt;1.3 计算机硬件
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;冯诺依曼计算机主要特点&lt;/strong&gt; ：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;构成程序的指令和数据均采用 &lt;strong&gt;二进制&lt;/strong&gt; 表示&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;指令和数据存放在存储器&lt;/strong&gt; 中，按地址访问&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;指令&lt;/strong&gt; 在存储器中 &lt;strong&gt;按顺序存放&lt;/strong&gt; ，一般情况下，指令是 &lt;strong&gt;顺序执行&lt;/strong&gt; 的&lt;/li&gt;
&lt;li&gt;指令由 &lt;strong&gt;操作码&lt;/strong&gt; 和 &lt;strong&gt;地址码&lt;/strong&gt; 组成&lt;/li&gt;
&lt;li&gt;机器 &lt;strong&gt;以运算器为中心&lt;/strong&gt; ，输入输出设备与存储器间的数据传送通过运算器完成&lt;/li&gt;
&lt;li&gt;计算器硬件由 &lt;strong&gt;运算器、控制器、存储器、输入输出设备&lt;/strong&gt; 组成&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-05-30_165712.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-05-30_165743.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;其中，存储器分为 &lt;strong&gt;主存储器&lt;/strong&gt; 和 &lt;strong&gt;辅助存储器&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;主存储器：用于存放程序和数据，可以 &lt;strong&gt;直接与CPU交换信息&lt;/strong&gt; ，又称为内存储器，简称内存或主存。&lt;/p&gt;
&lt;p&gt;辅助存储器：用于帮助主存存储更多的信息。又称外部存储器，简称为外存或辅存。 &lt;strong&gt;储存中的信息必须调入主存后，才能被CPU访问&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;运算器&lt;/strong&gt; 的核心为 &lt;strong&gt;算术逻辑单元ALU&lt;/strong&gt; ，主要功能有算术运算和逻辑运算。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="14-计算机软件"&gt;1.4 计算机软件
&lt;/h3&gt;&lt;p&gt;分为 &lt;strong&gt;系统软件&lt;/strong&gt; 和 &lt;strong&gt;应用软件&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;计算器软件的发展：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;用机器语言编程&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;使用 &lt;strong&gt;机器指令的二进制编码&lt;/strong&gt; 编写程序&lt;/p&gt;
&lt;p&gt;编程繁琐，易出错且不易排错&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;计算机可以直接识别和执行&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;用汇编语言编程&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;使用 &lt;strong&gt;表示机器指令的特殊符号&lt;/strong&gt; 编写程序&lt;/p&gt;
&lt;p&gt;相比于用机器语言编写，汇编语言这种符号语言简单直观，便于记忆&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;计算机不能识别和执行&lt;/strong&gt; 用汇编语言编写的程序，须通过汇编器翻译成机器语言程序&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;用高级语言编程&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;使用 &lt;strong&gt;规定好的一套基本符号和编程规则&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;直观通用， &lt;strong&gt;与具体机器无关&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;计算机不能识别和执行&lt;/strong&gt; 用高级语言编写的程序，须通过编译器翻译成汇编语言或机器语言&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-06_204731.png" alt="Screenshot 2025-06-06 204731" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;将高级语言程序转换成可执行目标程序的主要过程：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;预处理 -&amp;gt; 编译 -&amp;gt; 汇编 -&amp;gt; 链接&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;随着硬件和软件的不断发展，人们又创造出了一类程序，称为 &lt;strong&gt;操作系统&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;操作系统提供了在 &lt;strong&gt;汇编语言和高级语言的使用和实现过程中所需的某些基本操作&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;操作系统负责 &lt;strong&gt;控制并管理计算机系统全部硬件资源&lt;/strong&gt; （例如CPU、内存和外部设备）和 &lt;strong&gt;软件资源&lt;/strong&gt; （例如编译程序、应用程序等）。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id="15-计算机系统的层次结构"&gt;1.5 计算机系统的层次结构
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;层次&lt;/th&gt;
					&lt;th&gt;描述&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;第 6 层&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;高级语言层&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;使用与机器无关的高级语言编程，无需掌握机器的底层技术细节，只要掌握某种高级语言的语法规则以及算法和数据结构等方面的知识进行编程。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;第 5 层&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;汇编语言层&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;使用汇编语言进行编程。由于汇编语言的每条语句都与机器语言的某条语句对应，因此仍要求程序员对实际机器的内部组成和指令系统非常熟悉。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;第 4 层&lt;/td&gt;
					&lt;td&gt;操作系统层&lt;/td&gt;
					&lt;td&gt;设计人员不仅要对操作系统的设计理论有比较深入的理解，还需要掌握具体机器的指令集和汇编语言以及适于编写操作系统软件的高级语言。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;第 3 层&lt;/td&gt;
					&lt;td&gt;指令集体系结构层 ISA&lt;/td&gt;
					&lt;td&gt;定义了某计算机可执行的所有机器指令的集合，规定了对于每条机器指令计算机应执行什么操作，所处理的操作数应存放的位置以及操作数的类型等。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;第 2 层&lt;/td&gt;
					&lt;td&gt;微程序层&lt;/td&gt;
					&lt;td&gt;将一条机器指令编写成一个微程序。每个微程序包含若干条微指令，每条微指令对应一条或多条微操作。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;第 1 层&lt;/td&gt;
					&lt;td&gt;逻辑电路层&lt;/td&gt;
					&lt;td&gt;计算机硬件系统的底层，由逻辑门、寄存器等逻辑电路组成。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="16-计算机的基本工作原理"&gt;1.6 计算机的基本工作原理
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-08_175334.png" alt="Screenshot 2025-06-08 175334" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="运算器"&gt;运算器
&lt;/h4&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;ALU&lt;/th&gt;
					&lt;th&gt;加&lt;/th&gt;
					&lt;th&gt;减&lt;/th&gt;
					&lt;th&gt;乘&lt;/th&gt;
					&lt;th&gt;除&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;ACC&lt;/td&gt;
					&lt;td&gt;被加数和&lt;/td&gt;
					&lt;td&gt;被减数差&lt;/td&gt;
					&lt;td&gt;乘积高位&lt;/td&gt;
					&lt;td&gt;被除数余数&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;MQ&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;乘数 乘积低位&lt;/td&gt;
					&lt;td&gt;商&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;X&lt;/td&gt;
					&lt;td&gt;加数&lt;/td&gt;
					&lt;td&gt;减数&lt;/td&gt;
					&lt;td&gt;被乘数&lt;/td&gt;
					&lt;td&gt;除数&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;

 &lt;blockquote&gt;
 &lt;ul&gt;
&lt;li&gt;ACC 表示累加器
(ACC)表示累加器中的内容&lt;/li&gt;
&lt;li&gt;MQ 表示乘商寄存器
(MQ)表示乘商寄存器中的内容&lt;/li&gt;
&lt;li&gt;X 表示操作数寄存器
(X)表示操作数寄存器中的内容&lt;/li&gt;
&lt;li&gt;M表示主存储器中某个存储单元的地址
(M)表示地址为M的存储单元中的内容&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;p&gt;加法操作过程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;(M)→X
取出存放在主存中地址为M的存储单元中的内容(M)（加数），送到操作数寄存器X中&lt;/li&gt;
&lt;li&gt;(ACC) + (X) → ACC
将累加器ACC中的内容(ACC)（被加数）与操作数寄存器X中的内容(X)（加数）相加，结果（和）保留在累加器ACC中&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;减法操作过程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;(M)→X
取出存放在主存中地址为M的存储单元中的内容(M)（减数），送到操作数寄存器X中&lt;/li&gt;
&lt;li&gt;(ACC) - (X) → ACC
将累加器ACC中的内容(ACC)（被减数）与操作数寄存器X中的内容(X)（减数）相减，结果（差）保留在累加器ACC中&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;乘法操作过程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;(M)→MQ
取出存放在主存中地址为M的存储单元中的内容(M)（乘数），送到乘商寄存器MQ中&lt;/li&gt;
&lt;li&gt;(ACC)→X
将累加器ACC中的内容(ACC)（被乘数），送到操作数寄存器X中&lt;/li&gt;
&lt;li&gt;(X) × (MQ)→ACC // MQ
将操作数寄存器X中的内容(X)（被乘数）与乘商寄存器MQ中的内容(MQ)（乘数）相乘，结果（积）的高位保留在累加器ACC中，低位保留在乘商寄存器MQ中&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;除法操作过程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;(M)→X
取出存放在主存中地址为M的存储单元中的内容(M)（除数），送到操作数寄存器X中&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(ACC) ÷ (X) → MQ
将累加器ACC中的内容(ACC)（被除数）除以操作数寄存器X中的内容(X)（除数），结果（商）保留在乘商寄存器MQ中，余数保留在累加器ACC中。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h4 id="存储器"&gt;存储器
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;存储体&lt;/strong&gt; 由很多个 &lt;strong&gt;存储单元&lt;/strong&gt; 组成&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;每个 &lt;strong&gt;存储单元&lt;/strong&gt; 由若个 &lt;strong&gt;存储元件&lt;/strong&gt; 组成&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;每个存储元件能存储一位 &lt;strong&gt;二进制数&amp;quot;0&amp;quot;或&amp;quot;1&amp;quot;&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;一个存储单元中可存储一串二进制信息，称这串二进制信息为一个 &lt;strong&gt;存储字&lt;/strong&gt; ，这串 &lt;strong&gt;二进制信息的位数&lt;/strong&gt; 称为 &lt;strong&gt;存储字长&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;给每个存储单元都赋予一个编号，称为 &lt;strong&gt;存储单元的地址&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;存储器 &lt;strong&gt;地址寄存器 MAR&lt;/strong&gt; ，用来 &lt;strong&gt;存放欲访问的存储单元的地址&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;MAR的位数&lt;/strong&gt; ，决定了 &lt;strong&gt;存储单元的数量&lt;/strong&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;存储器 &lt;strong&gt;数据寄存器MDR&lt;/strong&gt; ，用来 &lt;strong&gt;存放从存储体的某个存储单元取出的信息或者准备往某个存储单元存入的信息&lt;/strong&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;MDR的位数（长度）&lt;/strong&gt; ，与 &lt;strong&gt;存储字长相等&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;主存（内存）的这种按存储单元的地址来实现对其写入和读取的存取操作，需要在CPU中的控制器的控制下进行。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-08_174813.png" alt="Screenshot 2025-06-08 174813" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="控制器"&gt;控制器
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-08_175631.png" alt="Screenshot 2025-06-08 175631" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;控制器是计算机的神经中枢，由它指挥各部件自动、协调地工作。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;控制从主存中读取一条指令，称为 &lt;strong&gt;取指&lt;/strong&gt; 过程（阶段）。&lt;/li&gt;
&lt;li&gt;对指令进行分析，指出该指令要完成何种操作，并按寻址特征指明操作数的地址，称为 &lt;strong&gt;分析&lt;/strong&gt; 过程（阶段）。&lt;/li&gt;
&lt;li&gt;根据指令的操作码和操作数所在的地址完成某种操作，称为 &lt;strong&gt;执行&lt;/strong&gt; 过程（阶段）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;程序计数器PC&lt;/strong&gt; 用来 &lt;strong&gt;存放当前欲执行指令的地址&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PC与MAR&lt;/strong&gt; 之间有一条直接通路。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PC自动形成 &lt;strong&gt;下一条指令的地址&lt;/strong&gt; “自动加1”功能）&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;指令寄存器IR&lt;/strong&gt; 用来存放当前的指令&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;IR的内容来自MDR。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;IR中的 &lt;strong&gt;操作码&lt;/strong&gt; （用OP(IR)表示）会送至CU（用 &lt;strong&gt;OP(IR)→CU&lt;/strong&gt; 表示），用来 &lt;strong&gt;分析指令&lt;/strong&gt; 。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;IR中的 &lt;strong&gt;地址码&lt;/strong&gt; （用Ad(IR)表示）作为操作数的地址送至MAR（用 &lt;strong&gt;Ad(IR)→MAR&lt;/strong&gt; 表示），用来 &lt;strong&gt;从内存中取操作数&lt;/strong&gt; 。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;控制单元CU&lt;/strong&gt; 用来 &lt;strong&gt;分析当前指令所需完成的操作，并发出各种微操作命令序列&lt;/strong&gt; ，用以控制所有被控对象。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="机器指令简介"&gt;机器指令简介
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-08_184259.png" alt="Screenshot 2025-06-08 184259" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-08_181635.png" alt="Screenshot 2025-06-08 181635" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="计算机的基本工作原理"&gt;计算机的基本工作原理
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-08_182228.png" alt="Screenshot 2025-06-08 182228" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;初始化：(PC)=0，指向内存中的编号为0的存储单元，该存储单元的内容是第一条机器指令&lt;/p&gt;
&lt;p&gt;对第一条指令进行 &lt;strong&gt;取指&lt;/strong&gt; ：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;控制器将PC的内容送至内存的MAR（用(PC)→MAR表示）对内存进行寻址，并命令内存做读操作，此时所寻址的存储单元（0号存储单元）的内容“0000010000010101”被送入MDR内。&lt;/li&gt;
&lt;li&gt;将MDR的内容传送至控制器的IR（用(MDR)→IR表示）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;接下来，程序计数器PC中的值从0自动增加到了1，在完成对第一条指令的取指操作后，对该指令进行 &lt;strong&gt;分析&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-08_182733.png" alt="Screenshot 2025-06-08 182733" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;对第一条指令进行 &lt;strong&gt;执行&lt;/strong&gt; ：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;将IR中保存的指令的地址码送至MAR（用Ad(IR)→MAR）对内存进行寻址，并命令内存做读操作，此时所寻址的存储单元（“0000000101”号存储单元，即5号存储单元）的内容“a”被送入MDR内。&lt;/li&gt;
&lt;li&gt;将MDR的内容传送至运算器的ACC（用(MDR)→ACC表示）。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h4 id="例题"&gt;例题
&lt;/h4&gt;&lt;p&gt;【习题3】存放当前指令的寄存器是（C）。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;A. PC B. MDR C. IR D. MAR&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;【习题4】用来存放当前欲执行指令的地址的寄存器是（B）。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;A. IR B. PC C. MAR D. CU&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;解析：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;指令寄存器IR用来存放 &lt;strong&gt;当前的指令&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;IR的内容来自存储器数据寄存器MDR。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;程序计数器PC用来存放 &lt;strong&gt;当前欲执行指令的地址&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;PC与存储器地址寄存器MAR之间有一条直接通路。&lt;/li&gt;
&lt;li&gt;PC自动形成下一条指令的地址（“自动加1”功能）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;【习题7】若存储字长为8位，MAR的位数为16位，则存储体的总容量为（B）。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;A.128B B.64KB C.128KB D.256KB&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;解析：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-08_184026.png" alt="Screenshot 2025-06-08 184026" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="21-数据表示的相关基本概念"&gt;2.1 数据表示的相关基本概念
&lt;/h3&gt;&lt;p&gt;数字分类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;无符号数：3238264832&lt;/li&gt;
&lt;li&gt;有符号数：-1056702464（整数）、-0.491943359375（纯小数）、-8.25（带小数）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;数字表示方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;整数：小数点位置固定&lt;/li&gt;
&lt;li&gt;纯小数：小数点位置固定&lt;/li&gt;
&lt;li&gt;定点数：小数点位置固定&lt;/li&gt;
&lt;li&gt;浮点数：小数点位置浮动&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-08_192309.png" alt="Screenshot 2025-06-08 192309" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="22-进位计数制及其数据之间的相互转换"&gt;2.2 进位计数制及其数据之间的相互转换
&lt;/h3&gt;&lt;p&gt;常用的进位计数制有十进制、二进制、八进制、十六进制&lt;/p&gt;
&lt;h4 id="任意进制-十进制"&gt;任意进制-&amp;gt;十进制
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-08_194040.png" alt="Screenshot 2025-06-08 194040" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="常用进制数对照表"&gt;常用进制数对照表
&lt;/h4&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;十进制&lt;/th&gt;
					&lt;th&gt;二进制&lt;/th&gt;
					&lt;th&gt;八进制&lt;/th&gt;
					&lt;th&gt;十六进制&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0000&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0001&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;0010&lt;/td&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;2&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;0011&lt;/td&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;3&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;4&lt;/td&gt;
					&lt;td&gt;0100&lt;/td&gt;
					&lt;td&gt;4&lt;/td&gt;
					&lt;td&gt;4&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;5&lt;/td&gt;
					&lt;td&gt;0101&lt;/td&gt;
					&lt;td&gt;5&lt;/td&gt;
					&lt;td&gt;5&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;6&lt;/td&gt;
					&lt;td&gt;0110&lt;/td&gt;
					&lt;td&gt;6&lt;/td&gt;
					&lt;td&gt;6&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;7&lt;/td&gt;
					&lt;td&gt;0111&lt;/td&gt;
					&lt;td&gt;7&lt;/td&gt;
					&lt;td&gt;7&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;8&lt;/td&gt;
					&lt;td&gt;1000&lt;/td&gt;
					&lt;td&gt;10&lt;/td&gt;
					&lt;td&gt;8&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;9&lt;/td&gt;
					&lt;td&gt;1001&lt;/td&gt;
					&lt;td&gt;11&lt;/td&gt;
					&lt;td&gt;9&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;10&lt;/td&gt;
					&lt;td&gt;1010&lt;/td&gt;
					&lt;td&gt;12&lt;/td&gt;
					&lt;td&gt;A&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;11&lt;/td&gt;
					&lt;td&gt;1011&lt;/td&gt;
					&lt;td&gt;13&lt;/td&gt;
					&lt;td&gt;B&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;12&lt;/td&gt;
					&lt;td&gt;1100&lt;/td&gt;
					&lt;td&gt;14&lt;/td&gt;
					&lt;td&gt;C&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;13&lt;/td&gt;
					&lt;td&gt;1101&lt;/td&gt;
					&lt;td&gt;15&lt;/td&gt;
					&lt;td&gt;D&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;14&lt;/td&gt;
					&lt;td&gt;1110&lt;/td&gt;
					&lt;td&gt;16&lt;/td&gt;
					&lt;td&gt;E&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;15&lt;/td&gt;
					&lt;td&gt;1111&lt;/td&gt;
					&lt;td&gt;17&lt;/td&gt;
					&lt;td&gt;F&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h4 id="二进制-其他进制"&gt;二进制-&amp;gt;其他进制
&lt;/h4&gt;&lt;p&gt;3位二进制数 ↔ 1位八进制数&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;举例：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;二进制：$(1011001100.11011)_2$&lt;/li&gt;
&lt;li&gt;转换为八进制：$(1314.66)_8$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;转换过程：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;将二进制数按每 &lt;strong&gt;三位一组&lt;/strong&gt; 进行分组：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;小数部分：110 110（后面少位则补零）&lt;/p&gt;
&lt;p&gt;整数部分：001 011 001 100（前面少位则补零）&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;4位二进制数 ↔ 1位十六进制数&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;举例：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;二进制：$(1011001100.11011)_2$&lt;/li&gt;
&lt;li&gt;转换为十六进制：$(2CC.D8)_{16}$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;转换过程：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;将二进制数按每 &lt;strong&gt;四位一组&lt;/strong&gt; 进行分组：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;小数部分：1101 1000&lt;/p&gt;
&lt;p&gt;整数部分：0010 1100 1100&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id="十进制-任意进制"&gt;十进制-&amp;gt;任意进制
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-08_200927.png" alt="Screenshot 2025-06-08 200927" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="231-原码"&gt;2.3.1 原码
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;符号位&lt;/strong&gt; ，值为 &lt;strong&gt;0表示正数，1表示负数&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;数值位&lt;/strong&gt; (二进制)，为真值的绝对值&lt;/p&gt;
&lt;p&gt;原码表示又称为 &lt;strong&gt;带符号的绝对值表示&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id="定点整数的原码定义"&gt;定点整数的原码定义
&lt;/h4&gt;&lt;p&gt;假设真值 &lt;em&gt;x&lt;/em&gt; 为 &lt;strong&gt;定点整数&lt;/strong&gt; ，&lt;em&gt;n&lt;/em&gt; 为 &lt;em&gt;x&lt;/em&gt; 的原码表示中数值位的位数（比特数量）：
&lt;/p&gt;
$$
[x]_原 = 
\begin{cases}
0 &amp; \text{} 0 \leq x&lt;2^n \\
2^n + |x| &amp;\text{} -2^n&lt;x \leq 0
\end{cases}
$$&lt;p&gt;
假设真值 $x= −b_1b_2b_3b_4$，$n=4$，x的原码表示中符号位为 $b_4$（其位权值为 24）。&lt;/p&gt;
&lt;p&gt;$[x]_原$ = 24 + | $−b_1b_2b_3b_4$ | = $24 + b_1b_2b_3b_4$ = 10000 + $b_1b_2b_3b_4$ = 1, $b_1b_2b_3b_4$&lt;/p&gt;
&lt;p&gt;举例：&lt;/p&gt;
&lt;p&gt;x = +1110 则 $[x]_原 = 0,1110$&lt;/p&gt;
&lt;p&gt;x = -1110 则 $[x]_原 = 2^4 + |-1110| = 2^4 + 1110 = 10000 + 1110 = 11110$&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;须注意 &lt;strong&gt;第一位的1是负数&lt;/strong&gt; 的含义&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h4 id="定点小数的原码定义"&gt;定点小数的原码定义
&lt;/h4&gt;&lt;p&gt;假设真值&lt;em&gt;x&lt;/em&gt;为&lt;strong&gt;定点小数&lt;/strong&gt;：
&lt;/p&gt;
$$
[x]_原 = 
\begin{cases} 
x &amp; \text{ } x \leq 0 &lt; 1 \\
1 + |x| &amp; \text{} -1 &lt; x \leq 0 
\end{cases}
$$&lt;p&gt;
举例：&lt;/p&gt;
&lt;p&gt;x = +0.1101 则$[x]_原 = 0.1101$&lt;/p&gt;
&lt;p&gt;x = -0.1101 则$[x]_原 = 1 + |-0.1101| = 1 + 0.1101 = 1.1101$&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="原码的特点"&gt;原码的特点
&lt;/h4&gt;&lt;p&gt;原码在计算机中目前仅仅用于表示浮点数的尾码&lt;/p&gt;
&lt;p&gt;优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;表示方法简单直观&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;缺点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;真值0&lt;/strong&gt; 在原码中 &lt;strong&gt;有两种不同的表示&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
$$
 [x]_原=
 \begin {cases}
 1,0000000 &amp; \text{} x = -0 \\
 0,0000000 &amp; \text{} x = +0
 \end {cases}
 $$&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;符号位不能直接参与运算&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="232-补码"&gt;2.3.2 补码
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;将补数的概念应用到计算机内部，便出现了补码这种机器码（机器数）。&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;正数的补码：符号位为0，数值位是它本身。&lt;/li&gt;
&lt;li&gt;负数的补码：等于 &lt;strong&gt;模数加上该负数本身&lt;/strong&gt; ，而模数就是最高位进位的位权值。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="补数"&gt;补数
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;模的概念&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;模&lt;/strong&gt; （或称模数）是一个数值计量系统的 &lt;strong&gt;计量范围&lt;/strong&gt; ，记作mod或M。&lt;/li&gt;
&lt;li&gt;只要确定了“模”，就可找到一个 &lt;strong&gt;与负数等价的正数&lt;/strong&gt; 来代替此负数，该正数就是负数的 &lt;strong&gt;补数&lt;/strong&gt; 。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;超过计量范围的数都应该自动舍弃模数&lt;/strong&gt; 。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;补数的特点&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个负数可用它的正补数来替代，而这个正补数可以用 &lt;strong&gt;模数加上负数本身&lt;/strong&gt; 求得。&lt;/li&gt;
&lt;li&gt;一个正数和一个负数 &lt;strong&gt;互为补数时，它们的绝对值之和即为模数&lt;/strong&gt; 。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;正数的补数即该正数本身&lt;/strong&gt; 。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;寻找一个负数的正补数的意义&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;把减法运算用加法实现&lt;/li&gt;
&lt;li&gt;符号位也可以直接参与运算&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;举例：设 A = 9 , B = 5 , 求 A - B , (mod 12)&lt;/p&gt;
&lt;p&gt;作加法运算：A - B = $[A]_补$ + $[-B]_补$ = $[9]_补$ + $[-5]_补$ = 9 + (模数 + (-5)) = 9 + (12 + (-5)) = 16 = 4&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="定点整数的补码定义"&gt;定点整数的补码定义
&lt;/h4&gt;&lt;p&gt;假设真值$x$为定点指数，$n$为$x$的补码表示中首位位的位数（比特数），$n$为$x$的补码表示中数值位的位数（比特数），加上1个符号位，$x$的补码表示共有 $n+1$ 位，最低位的位权值为 $2^0$ ，而最高位（符号位）的位权数为 $2^n$ ，因此最高位进位的位权值为值为 $2^{n+1}$ ，即 &lt;strong&gt;模数为 $2^{n+1}$&lt;/strong&gt; 。
&lt;/p&gt;
$$
[x]_补=
\begin {cases}
0,x &amp; \text{} 0 \leq x&lt;2^n \\
2^{n+1}+x &amp; \text{} -2^n \leq x&lt;0
\end {cases}
$$&lt;p&gt;
【举例】 某计算机的字长为8位，真值为定点整数 $(-10101)_2$， 求$[-x]_补$。&lt;/p&gt;
&lt;p&gt;模数为 2⁸ , $[x]_补 = 2^8 + (-10101) = 100000000 - 10101 = 1,1101011$&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="定点小数的补码定义"&gt;定点小数的补码定义
&lt;/h4&gt;&lt;p&gt;假设真值$x$为定点小数（纯小数），小数点在左侧的位为最高位（符号位），其位权值为 $2^{0}$ ，而最高位进位的位权值为$2^1$，即 &lt;strong&gt;模数为$2^1=2$&lt;/strong&gt; 。
&lt;/p&gt;
$$
[x]_补=
\begin {cases}
x &amp; \text{} 0 \leq x&lt;1 \\
2+x &amp; \text{} -1 \leq x&lt;0
\end {cases}
$$&lt;p&gt;
【举例】&lt;/p&gt;
&lt;p&gt;$x = +0.0101$ $[x]_补 = 0.0101$&lt;/p&gt;
&lt;p&gt;$x=-0.0101$ $[x]_补 = 2+(-0.0101)=10.0000-0.0101=1.1011$&lt;/p&gt;
&lt;p&gt;现代计算机中多采用IEEE 754标准表示浮点数，而其中的 &lt;strong&gt;定点小数采用原码表示&lt;/strong&gt; ，因此通常 &lt;strong&gt;不会涉及设计定点小数的补码表示&lt;/strong&gt; 。&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="补码的特点"&gt;补码的特点
&lt;/h4&gt;&lt;p&gt;目前计算机中普遍采用补码表示有符号定点整数，例如C语言中char,short,int,long型整数都是采用补码进行表示的。&lt;/p&gt;
&lt;p&gt;优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;补码表示方法使得减法运算可以转换成加法运算。&lt;/li&gt;
&lt;li&gt;真值0在补码中只有一种表示，这使得补码比原码多表示一个最小负数。&lt;/li&gt;
&lt;li&gt;符号位可以直接参与运算，运算时符号位的进位作为模会被自动舍弃。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;缺点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;补码的表示相对原码更加复杂
&lt;ul&gt;
&lt;li&gt;原码的数值位与真值的绝对值相同。因此，通过原码可以很容易地得出真值。但是，补码就没有这么简单了。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="233-反码"&gt;2.3.3 反码
&lt;/h3&gt;&lt;p&gt;反码通常用来作为有原码求补码或者由补码求原码的 &lt;strong&gt;中间过渡&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;正数的反码：符号位为0，数值位就是它本身。&lt;/li&gt;
&lt;li&gt;负数的反码：符号位为1，数值位就是真值数值位取反。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="原码-反码-补码"&gt;原码-&amp;gt;反码-&amp;gt;补码
&lt;/h4&gt;&lt;p&gt;原码的符号位不变，数值位取反，之后末位加一&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;真值&lt;/th&gt;
					&lt;th&gt;原码&lt;/th&gt;
					&lt;th&gt;取反说明&lt;/th&gt;
					&lt;th&gt;反码&lt;/th&gt;
					&lt;th&gt;加1说明&lt;/th&gt;
					&lt;th&gt;补码&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;-1&lt;/td&gt;
					&lt;td&gt;1,001&lt;/td&gt;
					&lt;td&gt;符号位不变，数值位取反&lt;/td&gt;
					&lt;td&gt;1,110&lt;/td&gt;
					&lt;td&gt;末位加1&lt;/td&gt;
					&lt;td&gt;1,111&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;-2&lt;/td&gt;
					&lt;td&gt;1,010&lt;/td&gt;
					&lt;td&gt;符号位不变，数值位取反&lt;/td&gt;
					&lt;td&gt;1,101&lt;/td&gt;
					&lt;td&gt;末位加1&lt;/td&gt;
					&lt;td&gt;1,110&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;-3&lt;/td&gt;
					&lt;td&gt;1,011&lt;/td&gt;
					&lt;td&gt;符号位不变，数值位取反&lt;/td&gt;
					&lt;td&gt;1,100&lt;/td&gt;
					&lt;td&gt;末位加1&lt;/td&gt;
					&lt;td&gt;1,101&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;-4&lt;/td&gt;
					&lt;td&gt;1,100&lt;/td&gt;
					&lt;td&gt;符号位不变，数值位取反&lt;/td&gt;
					&lt;td&gt;1,011&lt;/td&gt;
					&lt;td&gt;末位加1&lt;/td&gt;
					&lt;td&gt;1,100&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;-5&lt;/td&gt;
					&lt;td&gt;1,101&lt;/td&gt;
					&lt;td&gt;符号位不变，数值位取反&lt;/td&gt;
					&lt;td&gt;1,010&lt;/td&gt;
					&lt;td&gt;末位加1&lt;/td&gt;
					&lt;td&gt;1,011&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;-6&lt;/td&gt;
					&lt;td&gt;1,110&lt;/td&gt;
					&lt;td&gt;符号位不变，数值位取反&lt;/td&gt;
					&lt;td&gt;1,001&lt;/td&gt;
					&lt;td&gt;末位加1&lt;/td&gt;
					&lt;td&gt;1,010&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;-7&lt;/td&gt;
					&lt;td&gt;1,111&lt;/td&gt;
					&lt;td&gt;符号位不变，数值位取反&lt;/td&gt;
					&lt;td&gt;1,000&lt;/td&gt;
					&lt;td&gt;末位加1&lt;/td&gt;
					&lt;td&gt;1,001&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-09_170831.png" alt="Screenshot 2025-06-09 170831" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="定点整数的反码定义"&gt;定点整数的反码定义
&lt;/h4&gt;&lt;p&gt;假设真值$x$位定点整数，$n$为$x$的反码表示中数值位的位数（比特数量）。
&lt;/p&gt;
$$
[x]_反=
\begin{cases}
0,x &amp; 0 \leq x&lt;2^n \\
(2^{n+1}-1)+x &amp; -2^n&lt;x \leq 0
\end{cases}
$$&lt;p&gt;
【举例】&lt;/p&gt;
&lt;p&gt;$x=+1101$ $[x]_反=0,1101$&lt;/p&gt;
&lt;p&gt;$x=-1111$ $[x]_反 =2^{4+1}-1+(-1111)=2^5-1-1111=100000-1-1111=1,0000$&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="定点小数的反码定义"&gt;定点小数的反码定义
&lt;/h4&gt;&lt;p&gt;假设真值$x$为定点小数，$n$为$x$的反码表示中数值位的位数（比特数量）。
&lt;/p&gt;
$$
[x]_反=
\begin{cases}
x &amp; 0 \leq x &lt; 1 \\
[x]_补-2^{-n} &amp; -1&lt;x\leq 0
\end{cases}
$$&lt;p&gt;
【举例】&lt;/p&gt;
&lt;p&gt;$x=+0.1101$ $[x]_反=0.1101$&lt;/p&gt;
&lt;p&gt;$x=-0.1111$ $[x]_反=2-2^{-4}+(-0.1111)=10.0000-0.0001-0.1111=1.0000$&lt;/p&gt;
&lt;p&gt;【练习】&lt;/p&gt;
&lt;p&gt;$x=+0.0000$ $[x]_反=0.0000$&lt;/p&gt;
&lt;p&gt;$x=-0.0000$ $[x]_反=2-2^{-4}+(-0.0000)=10.0000-0.0001-0.0000=1.1111$&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="反码的特点"&gt;反码的特点
&lt;/h4&gt;&lt;p&gt;反码在计算机中目前很少被使用&lt;/p&gt;
&lt;p&gt;优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;符号位可以参与运算&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;缺点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;最高位（符号位）产生的进位要加到运算结果的低位（循环进位）&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;真值0在反码中由两种不同的表示&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="234-移码"&gt;2.3.4 移码
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-09_172851.png" alt="Screenshot 2025-06-09 172851" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;移码就是在 **真值上加一个常数$2^n$ **&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在数轴上，移码所表示的范围对应于真值在数轴上的范围 &lt;strong&gt;向轴的正方向移动$2^n$个单元&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;移码 &lt;strong&gt;只用于定点整数&lt;/strong&gt; 的表示&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="移码定义"&gt;移码定义
&lt;/h4&gt;&lt;p&gt;假设真值$x$为定点整数，$n$ 为 $x$ 的移码表示中数值位的位数（比特数量）
&lt;/p&gt;
$$
[x]_移=
\begin{cases}
x+2^n &amp; -2^n \leq x&lt;2^n
\end{cases}
$$&lt;p&gt;
【举例】&lt;/p&gt;
&lt;p&gt;$x=+1010110$ $[x]_移=+1010110+2^7=+1010110+10000000=1,1010110$&lt;/p&gt;
&lt;p&gt;$x=-1010110$ $[x]_移=-1010110+2^7=-1010110+10000000=0,0101010$&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="移码的特点"&gt;移码的特点
&lt;/h4&gt;&lt;p&gt;优点；&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;真值0&lt;/strong&gt; 在移码中只有 &lt;strong&gt;一种表示&lt;/strong&gt; 。&lt;/li&gt;
&lt;li&gt;移码保持了 &lt;strong&gt;真值原有的大小顺序&lt;/strong&gt; ，可以直接比较大小。&lt;/li&gt;
&lt;li&gt;最小真值的移码为全0，最大真值的移码为全1，符合人们的习惯。&lt;/li&gt;
&lt;li&gt;当浮点数的阶码用移码来表示时，就能很方便地比较阶码的大小。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="235-定点数的编码间的相互转化"&gt;2.3.5 定点数的编码间的相互转化
&lt;/h3&gt;&lt;p&gt;原码和补码互为补码，补码的补码是原码&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-18_212832.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;仅对数位值 &lt;strong&gt;从右到左&lt;/strong&gt; 顺序扫描，右起第一个1及其右边的0保持不变，其余各位取反（也可以反过来从补码求原码）&lt;/p&gt;
&lt;p&gt;【举例】&lt;/p&gt;
&lt;p&gt;原码 $1,1011010$ 从右到左，也就是最右侧 $10$ 的部分不变，而剩下的数值位上的数字均取反，即 $10110$ 这部分取反，最后可得补码为 $1,0100110$&lt;/p&gt;
&lt;p&gt;再者，若已知 $[x]_补$ 求 $[-x]_补$ ，则可以先将 &lt;strong&gt;全部位&lt;/strong&gt; 按位取反，然后 &lt;strong&gt;末位加1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;已知原码、反码、补码，如何算出真值（十进制形式）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;正数：&lt;/strong&gt;
将原码、反码、补码的数值位按权展开相加，符号位的0表示“+”。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;负数：&lt;/strong&gt;
将反码、补码转换成原码，然后将原码的数值位按权展开相加，符号位的1表示“-”。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="236-定点数的编码习题课"&gt;2.3.6 定点数的编码——习题课
&lt;/h3&gt;&lt;p&gt;【习题1】对真值0具有唯一表示形式的机器数是（ &lt;strong&gt;C&lt;/strong&gt; ）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. 原码	B.补码和反码	C.移码和补码	D.以上都不对&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;0的数量 取决于机器字长&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;/th&gt;
					&lt;th&gt;原码&lt;/th&gt;
					&lt;th&gt;反码&lt;/th&gt;
					&lt;th&gt;补码&lt;/th&gt;
					&lt;th&gt;移码&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;[+0]&lt;/td&gt;
					&lt;td&gt;0,000…0&lt;/td&gt;
					&lt;td&gt;0,000…0&lt;/td&gt;
					&lt;td&gt;0,000…0&lt;/td&gt;
					&lt;td&gt;1,000…0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;[−0]&lt;/td&gt;
					&lt;td&gt;1,000…0&lt;/td&gt;
					&lt;td&gt;1,111…1&lt;/td&gt;
					&lt;td&gt;0,000…0&lt;/td&gt;
					&lt;td&gt;1,000…0&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;

 &lt;/blockquote&gt;
&lt;p&gt;【习题2】8位原码能表示的不同的数据的量是（ &lt;strong&gt;C&lt;/strong&gt; ）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A.127	B.128	C.255	D.256&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;8位原码应共有 $2^8$ 个组合，但0在原码中有[+0]和[-0]两种表示（见上题），算是重复的数据&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;【习题3】某机器字长为8位，机器码采用补码，则机器码所能表示的范围是（ &lt;strong&gt;B&lt;/strong&gt; ）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. -127 ~ +127	B. -128 ~ +127	C. -128 ~ +128	D.以上都不对&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: center"&gt;补码（二进制）&lt;/th&gt;
					&lt;th style="text-align: center"&gt;十进制值&lt;/th&gt;
					&lt;th style="text-align: left"&gt;说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;0000 0000&lt;/td&gt;
					&lt;td style="text-align: center"&gt;0&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;0000 0001&lt;/td&gt;
					&lt;td style="text-align: center"&gt;+1&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;0000 0010&lt;/td&gt;
					&lt;td style="text-align: center"&gt;+2&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;0000 0011&lt;/td&gt;
					&lt;td style="text-align: center"&gt;+3&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;&amp;hellip;&lt;/td&gt;
					&lt;td style="text-align: center"&gt;&amp;hellip;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;0111 1111&lt;/td&gt;
					&lt;td style="text-align: center"&gt;+127&lt;/td&gt;
					&lt;td style="text-align: left"&gt;最大值&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;1000 0000&lt;/td&gt;
					&lt;td style="text-align: center"&gt;-128&lt;/td&gt;
					&lt;td style="text-align: left"&gt;最小值&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;1000 0001&lt;/td&gt;
					&lt;td style="text-align: center"&gt;-127&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;1000 0010&lt;/td&gt;
					&lt;td style="text-align: center"&gt;-126&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;1000 0011&lt;/td&gt;
					&lt;td style="text-align: center"&gt;-125&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;&amp;hellip;&lt;/td&gt;
					&lt;td style="text-align: center"&gt;&amp;hellip;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;1111 1111&lt;/td&gt;
					&lt;td style="text-align: center"&gt;-1&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;

 &lt;/blockquote&gt;
&lt;p&gt;【习题4】若 $[x]_补 = 1,0110100$ , 则 $[x]_原$ 是（ &lt;strong&gt;D&lt;/strong&gt; ）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. 0,1001011	B. 0,1001100	C. 1,1001011	D. 1,1001100&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;详见2.3.5的 原码&amp;lt;-&amp;gt;补码 扫描法&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;【习题5】若 $[x]_补 = 1,0110100$ , 则 $x$ 是（ &lt;strong&gt;D&lt;/strong&gt; ）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. +75	B. +76	C. -75	D. -76&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;先转化为原码，再将二进制原码转化为十进制数（注意第一位的符号位）&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;【习题6】设机器码采用补码形式，若寄存器内容为9BH，则对应的十进制数是（ &lt;strong&gt;C&lt;/strong&gt; ）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. -27	B. -97	C. -101	D. 155&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;H表示为16进制数，即 $(9B)_{16}$&lt;/p&gt;
&lt;p&gt;十六进制转为二进制，1个数转换成4个数&lt;/p&gt;
&lt;p&gt;$9=1001$ $B=1011$&lt;/p&gt;
&lt;p&gt;$[x]_补=10011011$ 则原码为 $1,1100101$&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;【习题7】假定十进制数为-66，按补码形式存放在一个8位寄存器中，该寄存器的内容用十六进制表示为（ &lt;strong&gt;B&lt;/strong&gt; ）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. C2H	B. BEH	C. BDH	D. 42H&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;【习题8】已知 $[x]_补 = 1,0110100$ , 则 $[-x]_补$ 是（ &lt;strong&gt;B&lt;/strong&gt; ）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. 0,1001011	B. 0,1001100	C. 1,1001011	D. 1,1001100&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;详见2.3.5&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;【习题9】已知 $[x]_补=1,0000000$ , 则 $[-x]_补$ 是（ &lt;strong&gt;D&lt;/strong&gt; ）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. 0,1111111	B. 0,0000001	C. 1,0000000	D. 无法表示&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;$x = -2^7=-128$ 所以$-x=128$&lt;/p&gt;
&lt;p&gt;然而8位定点整数补码能表示的最大正数为$0,1111111 , 即127$ , 128无法用8位补码表示，结果溢出&lt;/p&gt;
&lt;p&gt;若是用2.3.5的全取反再加1的方法，可得 $0,1111111 末位+1 = 1,0000000$ 成了正数相加为负数，结果溢出&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;【2015考研 题13】由3个1和5个0组成的8位二进制补码，能表示的最小整数是（ &lt;strong&gt;B&lt;/strong&gt; ）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. -126	B. -125	C. -32	D. -3&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;首先要用一个1放在符号位取负，另外两个一，按照原码补码转换方法反向思考，将它们放到最低位，组成 $1,0000011$ , 接下来再转换，可得$[x]_原=1,1111101 = -125$&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;【2021考研 题13】已知带符号整数用补码表示，变量 $x,y,z$ 的机器数分别为 $FFFDH , FFDFH , 7FFCH$
下列结论中，正确的是（ &lt;strong&gt;D&lt;/strong&gt; ）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A. 若$x,y$和$z$为无符号整数，则 $z&lt;x&lt;y$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;B. 若$x,y$和$z$为无符号整数，则 $x&lt;y&lt;z$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;C. 若$x,y$和$z$为带符号整数，则 $x&lt;y&lt;z$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;D. 若$x,y$和$z$为带符号整数，则 $y&lt;x&lt;z$&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;无符号整数可以直接比较大小，$x&gt;y&gt;z$&lt;/p&gt;
&lt;p&gt;带符号整数则要写成二进制形式：&lt;/p&gt;
&lt;p&gt;$[x]_补 = FFFDH = 1,111 1111 1111 1101 转换后x=-3$&lt;/p&gt;
&lt;p&gt;$[y]_补 = FFDFH = 1,111 1111 1101 1111转换后y=-33$&lt;/p&gt;
&lt;p&gt;$[z]_补=7FFCH = 0,111 1111 1111 1100为正数$&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;【2022考研 题13】32位补码所能表示的整数范围是（ &lt;strong&gt;B&lt;/strong&gt; ）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A. $-2^{32}$ ~ $2^{31}-1$ 	B. $-2^{31}$ ~ $2^{31}-1$ 	C. $-2^{32}$ ~ $2^{32}-1$ 	D. $-2^{31}$ ~ $2^{32}-1$&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;以8位补码为例，最小值是 $-2^{8-1}$ 最大值是 $2^{8-1}-1$&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id="241-浮点数的表示形式和表示范围"&gt;2.4.1 浮点数的表示形式和表示范围
&lt;/h3&gt;&lt;h4 id="定点小数"&gt;定点小数
&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌──────┬──────┬──────┬──────┬─────┬──────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ b₀ │ b₋₁ │ b₋₂ │ b₋₃ │ ... │ b₋ₙ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└──────┴──────┴──────┴──────┴─────┴──────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↑ ↑
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;符号位 小数点
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; （b₀与b₋₁之间）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; |←────机器字长为n+1位 n个数值位 ────→|
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: center"&gt;&lt;/th&gt;
					&lt;th style="text-align: center"&gt;原码&lt;/th&gt;
					&lt;th style="text-align: center"&gt;&lt;/th&gt;
					&lt;th style="text-align: center"&gt;反码&lt;/th&gt;
					&lt;th style="text-align: center"&gt;&lt;/th&gt;
					&lt;th style="text-align: center"&gt;补码&lt;/th&gt;
					&lt;th style="text-align: center"&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;&lt;/td&gt;
					&lt;td style="text-align: center"&gt;二进制&lt;/td&gt;
					&lt;td style="text-align: center"&gt;数值表达式&lt;/td&gt;
					&lt;td style="text-align: center"&gt;二进制&lt;/td&gt;
					&lt;td style="text-align: center"&gt;数值表达式&lt;/td&gt;
					&lt;td style="text-align: center"&gt;二进制&lt;/td&gt;
					&lt;td style="text-align: center"&gt;数值表达式&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;最大正数&lt;/td&gt;
					&lt;td style="text-align: center"&gt;0.111&amp;hellip;11&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$1-2^{-n}$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;0.111&amp;hellip;11&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$1-2^{-n}$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;0.111&amp;hellip;11&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$1-2^{-n}$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;最小正数&lt;/td&gt;
					&lt;td style="text-align: center"&gt;0.000&amp;hellip;01&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$2^{-n}$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;0.000&amp;hellip;01&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$2^{-n}$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;0.000&amp;hellip;01&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$2^{-n}$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;0&lt;/td&gt;
					&lt;td style="text-align: center"&gt;0.000&amp;hellip;00&lt;/td&gt;
					&lt;td style="text-align: center"&gt;0&lt;/td&gt;
					&lt;td style="text-align: center"&gt;0.000&amp;hellip;00&lt;/td&gt;
					&lt;td style="text-align: center"&gt;0&lt;/td&gt;
					&lt;td style="text-align: center"&gt;0.000&amp;hellip;00&lt;/td&gt;
					&lt;td style="text-align: center"&gt;0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;&lt;/td&gt;
					&lt;td style="text-align: center"&gt;1.000&amp;hellip;00&lt;/td&gt;
					&lt;td style="text-align: center"&gt;0&lt;/td&gt;
					&lt;td style="text-align: center"&gt;1.111&amp;hellip;11&lt;/td&gt;
					&lt;td style="text-align: center"&gt;0&lt;/td&gt;
					&lt;td style="text-align: center"&gt;&lt;/td&gt;
					&lt;td style="text-align: center"&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;最大负数&lt;/td&gt;
					&lt;td style="text-align: center"&gt;1.000&amp;hellip;01&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$-2^{-n}$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;1.111&amp;hellip;10&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$-2^{-n}$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;1.111&amp;hellip;11&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$-2^{-n}$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;最小负数&lt;/td&gt;
					&lt;td style="text-align: center"&gt;1.111&amp;hellip;11&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$- (1-2^{-n})$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;1.000&amp;hellip;00&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$- (1-2^{-n})$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;1.000&amp;hellip;00&lt;/td&gt;
					&lt;td style="text-align: center"&gt;-1&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;定点数所能表示的 &lt;strong&gt;数据范围&lt;/strong&gt; 与下列因素有关：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;机器字长&lt;/strong&gt; ：字长越长，其表示的数据范围就越大&lt;/li&gt;
&lt;li&gt;所采用的 &lt;strong&gt;机器码&lt;/strong&gt; ：补码和移码所能表示的数据范围，比原码和反码所能表示的数据范围 &lt;strong&gt;要多一个最小负数&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实际上，计算机中处理的数 &lt;strong&gt;不一定都是纯小数或者纯整数&lt;/strong&gt; 例如$\pi$ , 因此这样的数 &lt;strong&gt;不能直接&lt;/strong&gt; 用定点数表示&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="浮点数表示"&gt;浮点数表示
&lt;/h4&gt;&lt;p&gt;二进制浮点数可采用 &lt;strong&gt;类似十进制科学记数法&lt;/strong&gt; 的表示方法
&lt;/p&gt;
$$
110.0101=
\begin{cases}
2^{10} \times 1.100101 \\
2^{-1} \times 1100.101 \\
2^{11} \times 0.1100101
\end{cases}
$$&lt;p&gt;
其中底数（如2）是 &lt;strong&gt;基数r&lt;/strong&gt; 在机器中是隐含约定的，不需要专门存储表示&lt;/p&gt;
&lt;p&gt;指数（如10, 11)为二进制数，指数也就是 &lt;strong&gt;阶码E&lt;/strong&gt; , 用 &lt;strong&gt;定点整数&lt;/strong&gt; 表示&lt;/p&gt;
&lt;p&gt;小数点后面的部分是 &lt;strong&gt;尾数M&lt;/strong&gt; , 用 &lt;strong&gt;定点小数&lt;/strong&gt; 表示&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;任意一个二进制数N可表示成如下形式&lt;/strong&gt; ：
&lt;/p&gt;
$$
N=r^E \times M
$$&lt;hr&gt;
&lt;h4 id="浮点数在机器中的表示形式"&gt;浮点数在机器中的表示形式
&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌───────────────────────────────┬────────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 阶码 E │ 尾数 M │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├──────┬───────────────────────┼──────┬─────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ Ef │ E₁ E₂ E₃ ... Eₖ │ Mf │ M₁ M₂ M₃ ... Mₙ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├──────┴───────────────────────┼──────┴─────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 阶符 阶码的数值部分 │ 数符 尾数的数值部分 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└───────────────────────────────┴────────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;阶码&lt;/strong&gt; ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;阶码的位数决定了数据表示的范围，位数越多，能表示的数据范围就越大。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;阶码的值决定了小数点的位置。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;阶码可采用原码、补码、反码、移码进行表示。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;尾数&lt;/strong&gt; ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;尾数的位数决定了数据的表示精度。阶码长度相同时，分配给尾数的位数越多，数据表示的精度就越高。&lt;/li&gt;
&lt;li&gt;尾数可采用原码、补码、反码进行表示。&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;N&lt;/th&gt;
					&lt;th&gt;阶码E&lt;/th&gt;
					&lt;th&gt;尾数M&lt;/th&gt;
					&lt;th&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;正数N最大值&lt;/td&gt;
					&lt;td&gt;最大值&lt;/td&gt;
					&lt;td&gt;正数最大值&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;正数N最小值（浮点数的最小精度）&lt;/td&gt;
					&lt;td&gt;最小值&lt;/td&gt;
					&lt;td&gt;正数最小值&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;负数N最小值&lt;/td&gt;
					&lt;td&gt;最大值&lt;/td&gt;
					&lt;td&gt;负数最小值&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;负数N最大值&lt;/td&gt;
					&lt;td&gt;最小值&lt;/td&gt;
					&lt;td&gt;负数最大值&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;【练习】&lt;/p&gt;
&lt;p&gt;（1）设浮点数字长为8位，其中阶码3位（含1位阶符），尾数5位（含1位数符），阶码和尾数均以原码表示，基数r为8，则浮点数的最大最小值分别是多少？&lt;/p&gt;
&lt;p&gt;（2）设定点数原码为8位，则定点数的最大最小值分别是多少？&lt;/p&gt;
&lt;p&gt;（3）比较（1）（2）能得出什么结论？&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;（1）浮点数取最大值，即阶码取最大值，尾数取正数最大值
最大值= $8^{+3} \times (0.1111)_2 = 8^{+3} \times (0.9375) = +480$&lt;/p&gt;
&lt;p&gt;浮点数取最小值，即阶码取最大值，尾数取负数最小值&lt;/p&gt;
&lt;p&gt;最小值= $8^{+3} \times (-0.1111)_2 = -480$&lt;/p&gt;
&lt;p&gt;（2）定点数最大值 = $+(2^7-1)=+127$&lt;/p&gt;
&lt;p&gt;定点数最小值 = $-(2^7-1)=-127$&lt;/p&gt;
&lt;p&gt;（3）浮点数有效扩大了数据表示范围&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id="浮点数表示范围"&gt;浮点数表示范围
&lt;/h4&gt;&lt;p&gt;尽管浮点数有效扩大了数据表示范围，但 &lt;strong&gt;受机器字长限制，浮点数仍然存在溢出现象&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当浮点数的阶码大于最大阶码时，称为 &lt;strong&gt;上溢&lt;/strong&gt; ，此时机器 &lt;strong&gt;停止运算&lt;/strong&gt; ，浮点运算器件会显示溢出标志。&lt;/li&gt;
&lt;li&gt;当浮点数的阶码小于最小阶码时，称为 &lt;strong&gt;下溢&lt;/strong&gt; ，虽然此时数据 &lt;strong&gt;不能被精确表示&lt;/strong&gt; ，但由于发生下溢时数据的绝对值很小，通常将尾数各位强置为0， &lt;strong&gt;按机器0处理&lt;/strong&gt; ，此时机器可以 &lt;strong&gt;继续运行&lt;/strong&gt; 。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当一个浮点数在正、负区域中但并不在某个数轴刻度上时，也会出现 &lt;strong&gt;精度&lt;/strong&gt; 溢出的问题，此时只能用 &lt;strong&gt;近似数&lt;/strong&gt; 表示&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;最小负数&lt;/th&gt;
					&lt;th&gt;最大负数&lt;/th&gt;
					&lt;th&gt;最小正数&lt;/th&gt;
					&lt;th&gt;最大正数&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;$2^{2^k-1} \times (-(1-2^{-n}))$&lt;/td&gt;
					&lt;td&gt;$2^{-(2^k-1)} \times (-2^{-n})$&lt;/td&gt;
					&lt;td&gt;$2^{-(2^k-1)} \times 2^{-n}$&lt;/td&gt;
					&lt;td&gt;$2^{2^k-1} \times (1-2^{-n})$&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;最小负数和最大负数之间是 &lt;strong&gt;负数区域&lt;/strong&gt; ，最小正数和最大负数之间是 &lt;strong&gt;正数区域&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 上溢 | 负数区域 | 下溢 | 0 | 下溢 | 正数区域 | 上溢 |
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;一旦浮点数的位数确定后，合理分配 &lt;strong&gt;阶码E&lt;/strong&gt; 和 &lt;strong&gt;尾数M&lt;/strong&gt; 的位数，直接影响浮点数的 &lt;strong&gt;表示范围&lt;/strong&gt; 和 &lt;strong&gt;精度&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;短实数（32位）: 阶码E取8位（含1位阶符）尾数M取24位（含1位数符）&lt;/li&gt;
&lt;li&gt;长实数（64位）: 阶码E取11位（含1位阶符）尾数M取53位（含1位数符）&lt;/li&gt;
&lt;li&gt;临时实数（80位）: 阶码E取15位（含1位阶符）尾数M取65位（含1位数符）&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;【习题2】假设浮点数A和B的字长相同，A的阶码位数大于B的阶码位数，A的尾数位数小于B的位数位数，其他规定都相同，则A和B可表示的数的范围和精度是（ &lt;strong&gt;C&lt;/strong&gt; ）。&lt;/p&gt;
&lt;p&gt;A. B可表示的数的范围大且精度高&lt;/p&gt;
&lt;p&gt;B. A和B可表示的数的范围和精度相同&lt;/p&gt;
&lt;p&gt;C. A可表示的数的范围大但精度低&lt;/p&gt;
&lt;p&gt;D. A可表示的数的范围大且精度高&lt;/p&gt;
&lt;p&gt;【习题3】&lt;/p&gt;
&lt;p&gt;某浮点数字长为12位，其中阶码4位（含1位阶符号），基数为2，尾数8位（含1位数符），若阶码和尾数都用补码表示，则该浮点数所能表示的最大正数是（ &lt;strong&gt;D&lt;/strong&gt; ）。&lt;/p&gt;
&lt;p&gt;A. $2^8$ 	 B. $2^8−1$ 	 C. $2^7$ 	 D. $2^7−1$&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;最大正数：$2^{(2^3-1)} \times (1-2^{-7}) = 2^7 - 1$&lt;/p&gt;
&lt;p&gt;阶码数值位是3位，尾数数值位是7位&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id="242-浮点数的规格化"&gt;2.4.2 浮点数的规格化
&lt;/h3&gt;&lt;p&gt;通常要求浮点数在数据表示时 &lt;strong&gt;对尾数进行规格化处理&lt;/strong&gt; ，即 &lt;strong&gt;使得尾数的最高数值位必须是一个有效值&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;浮点数规格化有以下好处：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使浮点数的表示 &lt;strong&gt;形式唯一&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;使浮点数的表示 &lt;strong&gt;精度最高&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于非规格化尾数，需要对其进行 &lt;strong&gt;规格化操作&lt;/strong&gt; ，即根据具体形式通过将非规格化 &lt;strong&gt;尾数的数值部分&lt;/strong&gt; 进行 &lt;strong&gt;左移或右移&lt;/strong&gt; ，并 &lt;strong&gt;相应减少或增加阶码值&lt;/strong&gt; 的操作进行规格化，对应的规格化方法分别称为向左规格化（简称 &lt;strong&gt;左规&lt;/strong&gt; ）和向右规格化（简称 &lt;strong&gt;右规&lt;/strong&gt; ）。&lt;/p&gt;
&lt;p&gt;对于 &lt;strong&gt;基数r不同的浮点数&lt;/strong&gt; ，因其 &lt;strong&gt;规格化数的形式不同&lt;/strong&gt; ，规格化 &lt;strong&gt;过程也不同&lt;/strong&gt; 。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;当 &lt;strong&gt;r = 2&lt;/strong&gt; 时，尾数 &lt;strong&gt;数值部分最高位为1&lt;/strong&gt; 的数为规格化数。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;左规：尾数数值部分 &lt;strong&gt;每左移1位，阶码减1&lt;/strong&gt; 。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;右规：尾数数值部分 &lt;strong&gt;每右移1位，阶码加1&lt;/strong&gt; 。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;

 &lt;blockquote&gt;
 &lt;p&gt;【举例】二进制浮点数 $110.0101$&lt;/p&gt;
&lt;p&gt;非规格化表示： $2^{100} \times 0.01100101$ 阶码数减1，尾数小数点左移1位&lt;/p&gt;
&lt;p&gt;规格化表示： $2^{11} \times 0.11001010$&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当 &lt;strong&gt;r = 4&lt;/strong&gt; 时，尾数 &lt;strong&gt;数值部分最高2位不全为0&lt;/strong&gt; 的数为规格化数&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;左规：尾数数值部分每左移2位，阶码减1。&lt;/li&gt;
&lt;li&gt;右规：尾数数值部分每右移2位，阶码加1。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当 &lt;strong&gt;r = 8&lt;/strong&gt; 时，尾数 &lt;strong&gt;数值部分最高3位不全为0&lt;/strong&gt; 的数为规格化数。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;左规：尾数数值部分每左移3位，阶码减1。&lt;/li&gt;
&lt;li&gt;右规：尾数数值部分每右移3位，阶码加1。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;基数r&lt;/strong&gt;不同，对数的 &lt;strong&gt;表示范围和精度等都有影响&lt;/strong&gt; ，一般来说：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;基数r越大&lt;/strong&gt; ，可表示的 &lt;strong&gt;浮点数范围越大&lt;/strong&gt; ，而且所表示的数的 &lt;strong&gt;个数越多&lt;/strong&gt; ，但浮点数的 &lt;strong&gt;精度反而下降&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;【举例】&lt;/p&gt;
&lt;p&gt;第二行为基数r=16的浮点数的尾数规格化&lt;/p&gt;
&lt;p&gt;第三行为基数r=2的浮点数的尾数规格化&lt;/p&gt;
&lt;p&gt;可见基数r=2时，比r=16时多3位精度&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;$M_f$&lt;/th&gt;
					&lt;th&gt;$M_1$&lt;/th&gt;
					&lt;th&gt;$M_2$&lt;/th&gt;
					&lt;th&gt;$M_3$&lt;/th&gt;
					&lt;th&gt;$M_4$&lt;/th&gt;
					&lt;th&gt;$M_5$&lt;/th&gt;
					&lt;th&gt;&amp;hellip;&lt;/th&gt;
					&lt;th&gt;$M_n$&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;$M_f$&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;$M_5$&lt;/td&gt;
					&lt;td&gt;&amp;hellip;&lt;/td&gt;
					&lt;td&gt;$M_n$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;$M_f$&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;$M_2$&lt;/td&gt;
					&lt;td&gt;$M_3$&lt;/td&gt;
					&lt;td&gt;$M_4$&lt;/td&gt;
					&lt;td&gt;$M_5$&lt;/td&gt;
					&lt;td&gt;&amp;hellip;&lt;/td&gt;
					&lt;td&gt;$M_n$&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h4 id="浮点数规格化后的表示范围"&gt;浮点数规格化后的表示范围
&lt;/h4&gt;&lt;p&gt;相较于2.4.1，最小负数和最大正数不变&lt;/p&gt;
&lt;p&gt;最大负数变为： $2^{-(2^k-1)} \times (-2^{-1})$ 最小正数变为： $2^{-(2^k-1)} \times 2^{-n}$&lt;/p&gt;
&lt;p&gt;【例题1】&lt;/p&gt;
&lt;p&gt;设浮点数字长为16位，其中阶码5位（含1位阶符），尾数11位（含1位数符），将十进制数-56写成二进制定点数和浮点数（要求规格化表示），并分别写出它们各自的机器数（原码、反码、补码）形式。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;设 $x=−56$&lt;/p&gt;
&lt;p&gt;&lt;em&gt;x&lt;/em&gt; 的二进制形式 $x=−111000$&lt;/p&gt;
&lt;p&gt;&lt;em&gt;x&lt;/em&gt; 的二进制定点数表示 $x=−0000111000$ (尾数有10位数值位，须补零)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;x&lt;/em&gt; 的二进制浮点数规格化表示 $x=(−0.1110000000)×2^{110}$ (小数点应右移6位，因此乘2的6次方)&lt;/p&gt;

 &lt;/blockquote&gt;

 &lt;blockquote&gt;
 &lt;p&gt;二进制定点数转换&lt;/p&gt;
&lt;p&gt;$[x]_原=1,0000111000$&lt;/p&gt;
&lt;p&gt;$[x]_反=1,1111000111$&lt;/p&gt;
&lt;p&gt;$[x]_补=1,1111001000$&lt;/p&gt;

 &lt;/blockquote&gt;

 &lt;blockquote&gt;
 &lt;p&gt;二进制浮点数转换&lt;/p&gt;
&lt;p&gt;$[x]_原=0,0110;1,1110000000$&lt;/p&gt;
&lt;p&gt;$[x]_反=0,0110;1,0001111111$&lt;/p&gt;
&lt;p&gt;$[x]_补=0,0110;1,0010000000$&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-11_161532.png" alt="Screenshot 2025-06-11 161532" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-11_162231.png" alt="Screenshot 2025-06-11 162231" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-11_163857.png" alt="Screenshot 2025-06-11 163857" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="243-ieee-754-浮点数标准"&gt;2.4.3 IEEE 754 浮点数标准
&lt;/h3&gt;&lt;p&gt;IEEE 754标准主要包括两种基本的浮点数格式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;32位单精度浮点数&lt;/strong&gt; （对应C语言的float型）&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|&amp;lt;----------32bit----------&amp;gt;|
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|&amp;lt;-1bit-&amp;gt;|&amp;lt;-8bit-&amp;gt;|&amp;lt;-23bit-&amp;gt;|
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 31|30 23|22 0|
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 符号 | 阶码 | 尾数 |
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;64位双精度浮点数&lt;/strong&gt; （对应C语言中的double型）&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|&amp;lt;-----------64bit----------&amp;gt;|
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;|&amp;lt;-1bit-&amp;gt;|&amp;lt;-11bit-&amp;gt;|&amp;lt;-52bit-&amp;gt;|
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 63|62 52|51 0|
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 符号 | 阶码 | 尾数 |
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;其中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;符号&lt;/strong&gt; ：取值0表示正数；取值1表示负数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;阶码&lt;/strong&gt; ：定点整数，用 &lt;strong&gt;移码&lt;/strong&gt; 表示。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;尾数&lt;/strong&gt; ：定点小数，用 &lt;strong&gt;原码&lt;/strong&gt; 表示。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id="ieee-754-单精度浮点数的阶码"&gt;IEEE 754 单精度浮点数的阶码
&lt;/h4&gt;&lt;p&gt;用移码来表示阶码的特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;真值0在移码中只有一种表示。&lt;/li&gt;
&lt;li&gt;移码保持了真值原有的大小顺序，可以直接比较大小。（不考虑移码的符号位 看作无符号二进制数）&lt;/li&gt;
&lt;li&gt;最小真值的移码为全0，最大真值的移码为全1，符合人们的习惯。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在IEEE 754 浮点数标准中，32位单精度浮点数的 &lt;strong&gt;8位阶码尽管采用移码表示&lt;/strong&gt; ，但 **采用偏移常数是 $2^7-1=127$ ** ，而 **不是标准的 $2^7=128$ ** 。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;真值 $x$&lt;/th&gt;
					&lt;th&gt;$[x]_移$&lt;/th&gt;
					&lt;th&gt;IEEE $[x]_移$&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;-128&lt;/td&gt;
					&lt;td&gt;0,0000000&lt;/td&gt;
					&lt;td&gt;1,1111111&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;-127&lt;/td&gt;
					&lt;td&gt;0,0000001&lt;/td&gt;
					&lt;td&gt;0,0000000&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&amp;hellip;&lt;/td&gt;
					&lt;td&gt;&amp;hellip;&lt;/td&gt;
					&lt;td&gt;&amp;hellip;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;-2&lt;/td&gt;
					&lt;td&gt;0,1111110&lt;/td&gt;
					&lt;td&gt;0,1111101&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;-1&lt;/td&gt;
					&lt;td&gt;0,1111111&lt;/td&gt;
					&lt;td&gt;0,1111110&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1,0000000&lt;/td&gt;
					&lt;td&gt;0,1111111&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1,0000001&lt;/td&gt;
					&lt;td&gt;1,0000000&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;1,0000010&lt;/td&gt;
					&lt;td&gt;1,0000001&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&amp;hellip;&lt;/td&gt;
					&lt;td&gt;&amp;hellip;&lt;/td&gt;
					&lt;td&gt;&amp;hellip;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;125&lt;/td&gt;
					&lt;td&gt;1,1111101&lt;/td&gt;
					&lt;td&gt;1,1111100&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;126&lt;/td&gt;
					&lt;td&gt;1,1111110&lt;/td&gt;
					&lt;td&gt;1,1111101&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;127&lt;/td&gt;
					&lt;td&gt;1,1111111&lt;/td&gt;
					&lt;td&gt;1,1111110&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;为什么偏移常数不采用标准的128，而采用127？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将阶码全为1、全0的对应到最小的两个数-128和-127，有特殊用途&lt;/li&gt;
&lt;li&gt;采用偏移常数128表示的最小规格化数的 &lt;strong&gt;倒数会发生溢出&lt;/strong&gt; ，而采用偏移常数127表示的任何一个规格化数的倒数则不会溢出。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id="ieee-754-单精度浮点数的尾数"&gt;IEEE 754 单精度浮点数的尾数
&lt;/h4&gt;&lt;p&gt;尾数的特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;符号位前移到最左侧。相邻左侧隐藏一个1，表示数值而不表示符号。&lt;/li&gt;
&lt;li&gt;尾数实际有24位，但不保存隐藏的那个1，只保存23位，节省的比特位可用于提高尾数的精度。&lt;/li&gt;
&lt;li&gt;完整的尾数形式为1.M&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id="ieee-754-单精度浮点数标准"&gt;IEEE 754 单精度浮点数标准
&lt;/h4&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;数值的分类&lt;/th&gt;
					&lt;th style="text-align: left"&gt;符号 S&lt;/th&gt;
					&lt;th style="text-align: left"&gt;阶码 E&lt;/th&gt;
					&lt;th style="text-align: left"&gt;尾数 M&lt;/th&gt;
					&lt;th style="text-align: left"&gt;真值（LaTeX）&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;正零&lt;/td&gt;
					&lt;td style="text-align: left"&gt;0&lt;/td&gt;
					&lt;td style="text-align: left"&gt;0（全0）&lt;/td&gt;
					&lt;td style="text-align: left"&gt;0&lt;/td&gt;
					&lt;td style="text-align: left"&gt;+0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;负零&lt;/td&gt;
					&lt;td style="text-align: left"&gt;1&lt;/td&gt;
					&lt;td style="text-align: left"&gt;0（全0）&lt;/td&gt;
					&lt;td style="text-align: left"&gt;0&lt;/td&gt;
					&lt;td style="text-align: left"&gt;−0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;非规格化正数&lt;/td&gt;
					&lt;td style="text-align: left"&gt;0&lt;/td&gt;
					&lt;td style="text-align: left"&gt;0（全0）&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$M≠0$&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$(−1)^0 \times2^{−126}\times0.M$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;非规格化负数&lt;/td&gt;
					&lt;td style="text-align: left"&gt;1&lt;/td&gt;
					&lt;td style="text-align: left"&gt;0（全0）&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$M≠0$&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$(−1)^1\times2^{−126}\times0.M$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;正无穷大&lt;/td&gt;
					&lt;td style="text-align: left"&gt;0&lt;/td&gt;
					&lt;td style="text-align: left"&gt;255（全1）&lt;/td&gt;
					&lt;td style="text-align: left"&gt;0&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$+\infty$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;负无穷大&lt;/td&gt;
					&lt;td style="text-align: left"&gt;1&lt;/td&gt;
					&lt;td style="text-align: left"&gt;255（全1）&lt;/td&gt;
					&lt;td style="text-align: left"&gt;0&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$-\infty$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;无定义数（非数）&lt;/td&gt;
					&lt;td style="text-align: left"&gt;0 或 1&lt;/td&gt;
					&lt;td style="text-align: left"&gt;255（全1）&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$≠0$&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$NaN$ (not a number)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;规格化正数&lt;/td&gt;
					&lt;td style="text-align: left"&gt;0&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$1≤E≤254$&lt;/td&gt;
					&lt;td style="text-align: left"&gt;M&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$(−1)^0\times2^{E−127}\times1.M$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;规格化负数&lt;/td&gt;
					&lt;td style="text-align: left"&gt;1&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$1≤E≤254$&lt;/td&gt;
					&lt;td style="text-align: left"&gt;M&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$(−1)^1\times2^{E−127}\times1.M$&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;一般情况下，+0 和 -0 是等效的。&lt;/li&gt;
&lt;li&gt;非规格化数可用于处理阶码下溢，使得出现比最小规格化数还小的数时程序也能继续进行下去。&lt;/li&gt;
&lt;li&gt;引入无穷大数可使计算过程中出现异常的情况下程序能继续执行，并且可为程序提供错误检测功能。例如非0浮点数除0运算的结果就是无穷大，因此非0浮点数除0不会像整型数除0一样产生严重错误。&lt;/li&gt;
&lt;li&gt;非数 $NaN$ 则用于表示 $0/0$、$+\infty$、$-\infty$、$0\times\infty$、负数的平方根等。部分非数 $NaN$ 运算结果可能会产生异常。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id="ieee-754-单精度浮点数与对应真值之间的转换"&gt;IEEE 754 单精度浮点数与对应真值之间的转换
&lt;/h4&gt;&lt;p&gt;【例题1】将十进制数 $408.6875$ 转换成 IEEE 754 单精度浮点数的十六进制机器码&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;$408.6875 = (110011000.1011)_2 = 2^8 \times 1.100110001011$&lt;/p&gt;
&lt;p&gt;$符号位S = 0 表示正数，阶码E = 8 + 127 = 135 = 10000111，尾数M = 100110001011$&lt;/p&gt;
&lt;p&gt;尾数不足23位则在后面补零&lt;/p&gt;
&lt;p&gt;按四个一组进行二进制到十六进制的转换，即 $43CC5800$&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;【例题2】若 $C1830000$ 是某个IEEE 754单精度浮点数的十六进制机器码，求其对应的十进制值&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;将十六进制数转换为二进制数 $11000001100000110000000000000000$&lt;/p&gt;
&lt;p&gt;符号S=1，阶码E=10000011，尾数M=00000110000000000000000&lt;/p&gt;
&lt;p&gt;阶码的真值 $=阶码E-127=4$ ，尾数的1.M形式=1.0000011&lt;/p&gt;
&lt;p&gt;浮点数的真值 $= (-1)^S \times 2^x \times 1.M = (-1)^1 \times 2^4 \times 1.0000011 = -10000.011 = -16.375$&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id="ieee-754-单精度浮点数的表示范围"&gt;IEEE 754 单精度浮点数的表示范围
&lt;/h4&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;数值分类&lt;/th&gt;
					&lt;th style="text-align: left"&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;规格化&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;正数最大值&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$(-1)^0 \times 2^{254-127} \times 1.111\ldots1 = 2^{127} \times (2 - 2^{-23}) \approx 3.4 \times 10^{38}$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;正数最小值&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$(-1)^0 \times 2^{1-127} \times 1.0 = 2^{-126}$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;负数最大值&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$(-1)^1 \times 2^{1-127} \times 1.0 = -2^{-126}$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;负数最小值&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$(-1)^1 \times 2^{254-127} \times 1.111\ldots1 = -(2^{127} \times (2 - 2^{-23})) \approx -3.4 \times 10^{38}$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;&lt;strong&gt;非规格化&lt;/strong&gt;&lt;/td&gt;
					&lt;td style="text-align: left"&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;正数最大值&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$(-1)^0 \times 2^{-126} \times 0.111\ldots11 = 2^{-126} \times (1 - 2^{-23})$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;正数最小值&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$(-1)^0 \times 2^{-126} \times 0.000\ldots01 = 2^{-126} \times 2^{-23} = 2^{-149}$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;负数最大值&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$(-1)^1 \times 2^{-126} \times 0.000\ldots01 = -2^{-126} \times 2^{-23} = -2^{-149}$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;负数最小值&lt;/td&gt;
					&lt;td style="text-align: left"&gt;$(-1)^1 \times 2^{-126} \times 0.111\ldots11 = -2^{-126} \times (1 - 2^{-23})$&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;【2012考研 题14】float类型能表示的最大正整数是（ &lt;strong&gt;D&lt;/strong&gt; ）&lt;/p&gt;
&lt;p&gt;A. $2^{126}-2^{103}$ 	B. $2^{127}-2^{104}$ 	C. $2^{127}-2^{103}$ 	D. $2^{128}-2^{104}$&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;根据上表的推导公式 $2^{127} \times (2 - 2^{-23})$ 进行化简可知 $=2^{128}-2^{104}$&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;【2021考研 题14】下列数值中，不能用IEEE 754浮点格式精确表示的是（ &lt;strong&gt;A&lt;/strong&gt;）&lt;/p&gt;
&lt;p&gt;A. 1.2	B. 1.25	C. 2.0	D. 2.5&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;将这些十进制数转换为二进制数会发现 $1.2 = (1.001100110011...)_2$ 是无限循环的，而IEEE 754浮点数格式位数有限，无法精确表示无限循环小数&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id="311-逻辑移位"&gt;3.1.1 逻辑移位
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;逻辑移位的对象： &lt;strong&gt;无符号数&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;逻辑移位的规则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;逻辑左移&lt;/strong&gt; ：高位移除，低位补零&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;逻辑右移&lt;/strong&gt; ：低位移除，高位补零&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;【举例】假设某寄存器的内容如下所示，请给出逻辑左移3位和逻辑右移1位的结果&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;$b_7$&lt;/th&gt;
					&lt;th&gt;$b_6$&lt;/th&gt;
					&lt;th&gt;$b_5$&lt;/th&gt;
					&lt;th&gt;$b_4$&lt;/th&gt;
					&lt;th&gt;$b_3$&lt;/th&gt;
					&lt;th&gt;$b_2$&lt;/th&gt;
					&lt;th&gt;$b_1$&lt;/th&gt;
					&lt;th&gt;$b_0$&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;逻辑左移3位后，即高位移除了1,0,1，低位补3个0&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;$b_7$&lt;/th&gt;
					&lt;th&gt;$b_6$&lt;/th&gt;
					&lt;th&gt;$b_5$&lt;/th&gt;
					&lt;th&gt;$b_4$&lt;/th&gt;
					&lt;th&gt;$b_3$&lt;/th&gt;
					&lt;th&gt;$b_2$&lt;/th&gt;
					&lt;th&gt;$b_1$&lt;/th&gt;
					&lt;th&gt;$b_0$&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;逻辑右移1位后，即低位移除了0，高位补1个0&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;$b_7$&lt;/th&gt;
					&lt;th&gt;$b_6$&lt;/th&gt;
					&lt;th&gt;$b_5$&lt;/th&gt;
					&lt;th&gt;$b_4$&lt;/th&gt;
					&lt;th&gt;$b_3$&lt;/th&gt;
					&lt;th&gt;$b_2$&lt;/th&gt;
					&lt;th&gt;$b_1$&lt;/th&gt;
					&lt;th&gt;$b_0$&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="312-算术移位"&gt;3.1.2 算术移位
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;算术移位的对象： &lt;strong&gt;有符号数&lt;/strong&gt; （针对定点数，包括定点整数和定点小数）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不论正数还是负数， &lt;strong&gt;符号位保持不变，仅对数值位进行移位&lt;/strong&gt; （左移或右移）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对真值的原码、反码和补码进行算术移位后，它们各自所对应的新的真值应该保持一致。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;当真值为 &lt;strong&gt;正数&lt;/strong&gt; 时，真值的 &lt;strong&gt;原码、反码和补码都相同&lt;/strong&gt; ，因此，对它们进行算术移位后，它们各自所对应的新的真值自然是保持一致的。对于 &lt;strong&gt;移位后出现的空位，规定添补0&lt;/strong&gt; 。左移时，若最高位丢1，则 &lt;strong&gt;结果出错&lt;/strong&gt; ；右移时，若最低位丢1，则 &lt;strong&gt;精度缺失&lt;/strong&gt; 。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当真值为 &lt;strong&gt;负数&lt;/strong&gt; 时，真值的 &lt;strong&gt;原码、反码和补码都不同&lt;/strong&gt; ，因此，对它们进行算术移位后，为了确保它们各自 &lt;strong&gt;所对应的新的真值保持一致&lt;/strong&gt; ，对于 &lt;strong&gt;移位后出现的空位，添补规则各不相同&lt;/strong&gt; ，我们稍后推导给出它们各自具体的添补规则。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;- | 真值 | 机器码 | 空位填补 | 丢位情况 | 算术移位效果 |
 | :--- | :------------- | :------- | :-------------------------------------- | :----------------------------------------------------------- |
 | 正数 | 原码=补码=反码 | 0 | 最高位丢1，结果出错 最低位丢1，精度缺失 | 在未出现因丢位产生结果出错或精度缺失的情况下： ● 左移：乘以 $2^n$ ● 右移：除以 $2^n$ 其中，$n$ 为移位次数。 |
 | 负数 | 原码 | 1 | 最高位丢0，结果出错 最低位丢0，精度缺失 | |
 | | 反码 | 1 | 最高位丢0，结果出错 最低位丢0，精度缺失 | |
 | | 补码 | 左移补0 | 最高位丢0，结果出错 | |
 | | 补码 | 右移补1 | 最低位丢1，精度缺失 | |
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;【练习1】假设机器数字长为8位（含1位符号位），若真值 $x=+52$，请写出 $x$ 的补码算术左移1位、2位后的表示形式以及对应的真值 $a$ , $b$ ，并对移位结果进行分析。&lt;/p&gt;
&lt;p&gt;$[x]_{\text{原}} = [x]_{\text{反}} = [x]_{\text{补}} = 0,0110100$&lt;/p&gt;
&lt;p&gt;$b_7$ 为符号位&lt;/p&gt;
&lt;p&gt;下面三行分别为补码、算术左移1位、算术左移2位&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;$b_7$&lt;/th&gt;
					&lt;th&gt;$b_6$&lt;/th&gt;
					&lt;th&gt;$b_5$&lt;/th&gt;
					&lt;th&gt;$b_4$&lt;/th&gt;
					&lt;th&gt;$b_3$&lt;/th&gt;
					&lt;th&gt;$b_2$&lt;/th&gt;
					&lt;th&gt;$b_1$&lt;/th&gt;
					&lt;th&gt;$b_0$&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;可见，左移1位高位丢0，相当于乘以 $2^1$ ，而左移2位后，高位丢01，含1，所以 &lt;strong&gt;结果出错&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;【练习2】假设机器数字长为8位（含1位符号位），若真值 $x = +52$，请写出 $x$ 的反码算术右移1位、2位、3位后的表示形式以及对应的真值 $a$、$b$、$c$，并对移位结果进行分析。&lt;/p&gt;
&lt;p&gt;$x = +52 = (+110100)_2$&lt;/p&gt;
&lt;p&gt;$[x]_{\text{原}} = [x]_{\text{反}} = [x]_{\text{补}} = 0,0110100$&lt;/p&gt;
&lt;p&gt;下面四行分别为反码、算术右移1位、算术右移2位、算术右移3位&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;$b_7$&lt;/th&gt;
					&lt;th&gt;$b_6$&lt;/th&gt;
					&lt;th&gt;$b_5$&lt;/th&gt;
					&lt;th&gt;$b_4$&lt;/th&gt;
					&lt;th&gt;$b_3$&lt;/th&gt;
					&lt;th&gt;$b_2$&lt;/th&gt;
					&lt;th&gt;$b_1$&lt;/th&gt;
					&lt;th&gt;$b_0$&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;可见，右移1位和右移2位时，都是低位丢0，相当于除以 $2^1$ 和 $2^2$&lt;/p&gt;
&lt;p&gt;而右移3位，结果发生变化，并非除以了 $2^3$ ，精度缺失 $2^{-1}$&lt;/p&gt;
&lt;p&gt;【练习5】假设机器数字长为8位（含1位符号位），若真值 $x = -26$，请写出 $x$ 的补码算术左移1位、2位、3位后的表示形式以及对应的真值 $a$、$b$、$c$，并对移位结果进行分析。&lt;/p&gt;
&lt;p&gt;$[x]_补=1,1100110$&lt;/p&gt;
&lt;p&gt;下面四行分别为补码、算术左移1位、左移2位、左移3位&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;$b_7$&lt;/th&gt;
					&lt;th&gt;$b_6$&lt;/th&gt;
					&lt;th&gt;$b_5$&lt;/th&gt;
					&lt;th&gt;$b_4$&lt;/th&gt;
					&lt;th&gt;$b_3$&lt;/th&gt;
					&lt;th&gt;$b_2$&lt;/th&gt;
					&lt;th&gt;$b_1$&lt;/th&gt;
					&lt;th&gt;$b_0$&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;根据补码的计算方式（或者说形式）可知，高位（左侧部分）和反码一样，低位（右侧部分）和原码一样，所以说左移的规则同反码，右移的规则同原码。&lt;/p&gt;
&lt;p&gt;可见，左移1位和2位，分别是高位丢1，和高位丢11，也就是乘以 $2^1$ 和 $2^2$ ， 左移3位时，高位丢110，含0，结果出错&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="补码的符号位参与移位法"&gt;补码的“符号位参与”移位法
&lt;/h4&gt;&lt;p&gt;有符号定点数的补码的另一种算术移位方法，即“符号位也参与移位”，具体规则如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;左移：高位移除，低位添补0；移动前后 &lt;strong&gt;若符号位发生变化，则发生溢出&lt;/strong&gt; 。&lt;/li&gt;
&lt;li&gt;右移：低位移除， &lt;strong&gt;高位添补符号&lt;/strong&gt; （0或1）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上述这种针对有符号定点数的补码的算术移位方法，具有以下优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;左移时&lt;/strong&gt;，有检测出发生溢出的方法：符号位发生变化可判定溢出。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;符号位与数值位一起移位， &lt;strong&gt;方便ALU处理&lt;/strong&gt; ，也方便人们记忆。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;【举例】假设机器数字长为8位（含1位符号位），若真值 $x = +26$，请写出 $x$ 的补码算术右移1位、2位后的表示形式以及对应的真值 $a$、$b$，并对移位结果进行分析。&lt;/p&gt;
&lt;p&gt;$x = +26 = (+11010)_2$ $[x]_{\text{补}} = 0,0011010$&lt;/p&gt;
&lt;p&gt;下面三行分别为补码、算术右移1位、右移2位&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;$b_7$&lt;/th&gt;
					&lt;th&gt;$b_6$&lt;/th&gt;
					&lt;th&gt;$b_5$&lt;/th&gt;
					&lt;th&gt;$b_4$&lt;/th&gt;
					&lt;th&gt;$b_3$&lt;/th&gt;
					&lt;th&gt;$b_2$&lt;/th&gt;
					&lt;th&gt;$b_1$&lt;/th&gt;
					&lt;th&gt;$b_0$&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;高位补符号0&lt;/p&gt;
&lt;p&gt;【练习9】假设机器数字长为8位（含1位符号位），若真值 $x = -26$，请写出 $x$ 的补码算术左移1位、2位、3位后的表示形式以及对应的真值 $a$、$b$、$c$，并对移位结果进行分析。&lt;/p&gt;
&lt;p&gt;$x = -26 = (-11010)_2$ $[x]_{\text{补}} = 1,1100110$&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;$b_7$&lt;/th&gt;
					&lt;th&gt;$b_6$&lt;/th&gt;
					&lt;th&gt;$b_5$&lt;/th&gt;
					&lt;th&gt;$b_4$&lt;/th&gt;
					&lt;th&gt;$b_3$&lt;/th&gt;
					&lt;th&gt;$b_2$&lt;/th&gt;
					&lt;th&gt;$b_1$&lt;/th&gt;
					&lt;th&gt;$b_0$&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;题目同练习5，方法不同。左移3位时，发现符号位由1变0，即为发生溢出&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="算术移位的应用举例"&gt;算术移位的应用举例
&lt;/h4&gt;&lt;p&gt;假设 $x=-26$ ，仅用 &lt;strong&gt;加法和算术移位&lt;/strong&gt; 操作计算 $x \times 3$&lt;/p&gt;
&lt;p&gt;$[x]_补=(1,1100110)_2$&lt;/p&gt;
&lt;p&gt;对 $[x]_补$ 算术左移1位可得其乘以2的结果，然后将 $[x]_补$ 和 $2 \times [x]_补$ 相加即可&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;【2018考研 题16】整数 $x$ 的机器数为 $1101\ 1000$，分别对 $x$ 进行逻辑右移1位和算术右移1位操作，得到的机器数各是（ &lt;strong&gt;B&lt;/strong&gt; ）。&lt;/p&gt;
&lt;p&gt;A. 1110 1100、1110 1100
B. 0110 1100、1110 1100
C. 1110 1100、0110 1100
D. 0110 1100、0110 1100&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;逻辑右移1位：将其当作无符号数，高位补0，结果为 $0110\ 1100$&lt;/li&gt;
&lt;li&gt;算术右移1位：将其当作有符号数，则机器数 $1101\ 1000$ 就是 $x$ 的补码，高位补符号位（原最高位为1），结果为 $1110\ 1100$&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="313-循环移位"&gt;3.1.3 循环移位
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;循环移位的对象：&lt;strong&gt;无符号数&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;将无符号数二进制形式中的各个位向左或向右移动， &lt;strong&gt;被移出的位会重新出现在另一端，形成循环&lt;/strong&gt; 。&lt;/li&gt;
&lt;li&gt;在很多处理器架构中，&lt;strong&gt;循环移位指令会影响状态寄存器中的进位标志CF（Carry Flag）位&lt;/strong&gt;，CF标志位用于标识在执行算术或逻辑移操作时是否发生了进位。&lt;/li&gt;
&lt;li&gt;根据 &lt;strong&gt;CF标志位是否加入循环移位&lt;/strong&gt; 过程，循环移位可分为以下四种：
&lt;ul&gt;
&lt;li&gt;不带CF标志位的循环右移&lt;/li&gt;
&lt;li&gt;不带CF标志位的循环左移
（合称为&lt;strong&gt;小循环&lt;/strong&gt;）&lt;/li&gt;
&lt;li&gt;带CF标志位的循环右移&lt;/li&gt;
&lt;li&gt;带CF标志位的循环左移
（合称为&lt;strong&gt;大循环&lt;/strong&gt;）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id="不带cf标志位的循环右移"&gt;不带CF标志位的循环右移
&lt;/h4&gt;&lt;p&gt;最低位移出的值会存入最高位，CF标志位本身不存在于循环右移中，CF位的值为最低位移出的值&lt;/p&gt;
&lt;p&gt;第三行为循环右移一次的结果，CF标志位此时的值为 $x_0$&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;$b_7$&lt;/th&gt;
					&lt;th&gt;$b_6$&lt;/th&gt;
					&lt;th&gt;$b_5$&lt;/th&gt;
					&lt;th&gt;$b_4$&lt;/th&gt;
					&lt;th&gt;$b_3$&lt;/th&gt;
					&lt;th&gt;$b_2$&lt;/th&gt;
					&lt;th&gt;$b_1$&lt;/th&gt;
					&lt;th&gt;$b_0$&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;$x_7$&lt;/td&gt;
					&lt;td&gt;$x_6$&lt;/td&gt;
					&lt;td&gt;$x_5$&lt;/td&gt;
					&lt;td&gt;$x_4$&lt;/td&gt;
					&lt;td&gt;$x_3$&lt;/td&gt;
					&lt;td&gt;$x_2$&lt;/td&gt;
					&lt;td&gt;$x_1$&lt;/td&gt;
					&lt;td&gt;$x_0$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;$x_0$&lt;/td&gt;
					&lt;td&gt;$x_7$&lt;/td&gt;
					&lt;td&gt;$x_6$&lt;/td&gt;
					&lt;td&gt;$x_5$&lt;/td&gt;
					&lt;td&gt;$x_4$&lt;/td&gt;
					&lt;td&gt;$x_3$&lt;/td&gt;
					&lt;td&gt;$x_2$&lt;/td&gt;
					&lt;td&gt;$x_1$&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id="不带cf标志位的循环左移"&gt;不带CF标志位的循环左移
&lt;/h4&gt;&lt;p&gt;基本同上。最高位移出的值会存入最低位，CF位的值位最高位移出的值&lt;/p&gt;
&lt;h4 id="带cf标志位的循环右移"&gt;带CF标志位的循环右移
&lt;/h4&gt;&lt;p&gt;寄存器中的值整体向右移动（包括CF位），最低位移出的值会存入CF位，CF位移出的值会存入最高位（ $b_7$ ）&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: center"&gt;CF&lt;/th&gt;
					&lt;th style="text-align: center"&gt;$b_7$&lt;/th&gt;
					&lt;th style="text-align: center"&gt;$b_6$&lt;/th&gt;
					&lt;th style="text-align: center"&gt;$b_5$&lt;/th&gt;
					&lt;th style="text-align: center"&gt;$b_4$&lt;/th&gt;
					&lt;th style="text-align: center"&gt;$b_3$&lt;/th&gt;
					&lt;th style="text-align: center"&gt;$b_2$&lt;/th&gt;
					&lt;th style="text-align: center"&gt;$b_1$&lt;/th&gt;
					&lt;th style="text-align: center"&gt;$b_0$&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;$x_{CF}$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$x_7$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$x_6$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$x_5$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$x_4$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$x_3$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$x_2$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$x_1$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$x_0$&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: center"&gt;$x_0$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$x_{CF}$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$x_7$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$x_6$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$x_5$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$x_4$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$x_3$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$x_2$&lt;/td&gt;
					&lt;td style="text-align: center"&gt;$x_1$&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id="带cf标志位的循环左移"&gt;带CF标志位的循环左移
&lt;/h4&gt;&lt;p&gt;基本同上。寄存器中的值整体向左移动（包括CF位），最高位移出的值会存入CF位，CF位移出的值会存入最低位（ $b_0$ ）&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="循环移位的应用"&gt;循环移位的应用
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;循环移位的应用主要有：&lt;strong&gt;加密算法、哈希函数、优化算法&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;加密算法：通过循环移位可以实现数据的混淆和置换，增强加密算法的安全性。&lt;/li&gt;
&lt;li&gt;哈希函数：通过循环移位可以用来改变输入数据的排列顺序，以产生不同的哈希值，有利于增强哈希函数的混淆性和扩散性。&lt;/li&gt;
&lt;li&gt;优化算法：在某些算法中，循环移位可以用于优化性能和节省资源。例如，在图形处理和数字信号处理中，循环移位可以用于加速算法的执行。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="321-补码加减法运算公式"&gt;3.2.1 补码加减法运算公式
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;经过第2章的学习可知，&lt;strong&gt;定点数&lt;/strong&gt;（定点整数和定点小数）在&lt;strong&gt;计算机内部采用补码表示&lt;/strong&gt;，原因如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;补码的符号位可以与数值位一起参加加运算。&lt;/li&gt;
&lt;li&gt;采用补码可将减法运算转换成加法运算。&lt;/li&gt;
&lt;li&gt;运算规则简单，易于实现。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;补码加法和减法运算的公式如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;$[A]_补+[B]_补=[A+B]_补$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;$[A]_补-[B]_补=[A-B]_补=[A]_补+[-B]_补$ （$[-B]_补 = -[B]_补$)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;【例题1】设 $x=0,0101\ y=0,0001$ , 求 $[x]_补+[y]_补$ 。&lt;/p&gt;
&lt;p&gt;$[x]_补+[y]_补=[x+y]_补=0,0110$&lt;/p&gt;
&lt;p&gt;【例题2】设 $x=-0,0101\ y=-0,0001$ , 求 $[x]_补+[y]_补$ 。&lt;/p&gt;
&lt;p&gt;$[x]_补=1.1011\ [y]_补=1.1111$&lt;/p&gt;
&lt;p&gt;$[x]_补+[y]_补=[x+y]_补=[-0,0110]_补=1,1010$&lt;/p&gt;
&lt;p&gt;【例题3】设 $x=0,1011\ y=-0,0101$ , 求 $[x]_补+[y]_补$ 。&lt;/p&gt;
&lt;p&gt;$[x]_补=0.1011\ [y]_补=1.1011$&lt;/p&gt;
&lt;p&gt;$[x]_补+[y]_补=[x+y]_补=[0,0110]_补=0,0110$&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="322-补码加减法的溢出检测"&gt;3.2.2 补码加减法的溢出检测
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;计算机的字长是有限的，因此所能表示的数据范围也是有限的。&lt;/li&gt;
&lt;li&gt;当运算结果超出所能表示的数据范围时，就会出现&lt;strong&gt;溢出&lt;/strong&gt;（Overflow）。
&lt;ul&gt;
&lt;li&gt;溢出会导致错误的运算结果。&lt;/li&gt;
&lt;li&gt;计算机系统设计人员必须要解决溢出的检测问题，以便在发生溢出时计算机能做出相应的处理&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-16_150345.png" alt="Screenshot 2025-06-16 150345" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;如图所示，两负数相加，舍去进位的模数后，结果变为正数，出现错误&lt;/p&gt;
&lt;p&gt;两正数相加，舍去进位的模数后，结果变为负数，出现错误&lt;/p&gt;
&lt;p&gt;（出现错误的原因并非计算过程中和模数 $2^n$ 有关的部分）&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="溢出检测"&gt;溢出检测
&lt;/h4&gt;&lt;p&gt;定点数补码加减运算&lt;strong&gt;判断溢出的方法&lt;/strong&gt;主要有以下3种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;方法1：根据 &lt;strong&gt;操作数的符号位&lt;/strong&gt; 与 &lt;strong&gt;运算结果的符号位&lt;/strong&gt; 是否一致进行判断&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;两个操作数 &lt;strong&gt;相加&lt;/strong&gt; 时，当它们的 &lt;strong&gt;符号位相同&lt;/strong&gt; 时，才 &lt;strong&gt;可能发生溢出&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;若运算结果的符号位与原操作数的 &lt;strong&gt;符号位不同&lt;/strong&gt; ，则为 &lt;strong&gt;溢出&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;由于采用补码可将减法运算转换成加法运算，因此不论作加法还是减法，只要 &lt;strong&gt;实际参加运算的两个操作数符号相同&lt;/strong&gt; ， &lt;strong&gt;但运算结果的符号位与原操作数不同&lt;/strong&gt; ，即为 &lt;strong&gt;溢出&lt;/strong&gt; 。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-16_153920.png" alt="Screenshot 2025-06-16 153920" loading="lazy" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;操作数 $x$ 的符号位记为 $x_{n-1}$ 操作数 $y$ 的符号位记为 $y_{n-1}$ 运算结果 $s$ 的符号位记为 $s_{n-1}$
&lt;strong&gt;溢出标志位&lt;/strong&gt; 记为 $OF$ ， $OF=1$ 表示发生溢出。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
$$
 OF = x_{n-1} \cdot y_{n-1} \cdot \bar{s}_{n-1} + \bar{x}_{n-1} \cdot \bar{y}_{n-1} \cdot s_{n-1}
 $$&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;方法2：根据运算过程中 &lt;strong&gt;最高数值位的进位&lt;/strong&gt; 与 &lt;strong&gt;符号位的进位&lt;/strong&gt; 是否一致进行判断&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-16_162751.png" alt="Screenshot 2025-06-16 162751" loading="lazy" /&gt;&lt;/li&gt;
&lt;li&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-16_165544.png" alt="Screenshot 2025-06-16 165544" loading="lazy" /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;方法3：利用 &lt;strong&gt;变形补码&lt;/strong&gt; （具有2位符号位的补码）的符号位进位进行判断&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;双符号位为 00 时，表示正数；&lt;/li&gt;
&lt;li&gt;双符号位为 01 时，表示正溢出；&lt;/li&gt;
&lt;li&gt;双符号位为 11 时，表示负数；&lt;/li&gt;
&lt;li&gt;双符号位为 10 时，表示负溢出；&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;【2009考研 题12】一个C语言程序在一台32位机器上运行。程序中定义了三个变量x，y和z，x和z为int型，y为short型。当x = 127，y = -9时，执行赋值语句z = x + y后，x，y和z的值分别是（ &lt;strong&gt;D&lt;/strong&gt; ）。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A&lt;/em&gt;. $x=00000007FH，y=FFF9H，z=00000076H$&lt;/p&gt;
&lt;p&gt;&lt;em&gt;B&lt;/em&gt;. $x=00000007FH，y=FFF9H，z=FFFF0076H$&lt;/p&gt;
&lt;p&gt;&lt;em&gt;C.&lt;/em&gt; $x=00000007FH，y=FFF7H， z=FFFF0076H$&lt;/p&gt;
&lt;p&gt;&lt;em&gt;D&lt;/em&gt;. $x=00000007FH，y=FFF7H，z=00000076H$&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;y的补码可得为 FFF7H，z的真值由计算可得为118&amp;gt;0 所以符号位应为0&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;【2013考研 题14】某个字长为8位的计算机中，已知整型变量x和y的机器数分别为&lt;em&gt;x&lt;/em&gt;补 = 11110100，&lt;em&gt;y&lt;/em&gt;补 = 10110000。若整型变量 $z = 2x + y/2$ ，则z的机器数为（ &lt;strong&gt;A&lt;/strong&gt; ）。&lt;/p&gt;
&lt;p&gt;A. $1 1000000$
B. $0 0100100$
C. $1 0101010$
D. 溢出&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;将 $[x]_{\text{补}}$ 算术左移1位可得 $[2x]_补=1,1101000$ ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;高位移除，低位补0；&lt;/li&gt;
&lt;li&gt;移动前后若符号发生变化，则发生溢出。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;将 $[y]_{\text{补}}$ 算术右移1位可得$[y/2]_补=1,1011000$ ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;低位移除，高位补符号位。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;相加，符号位进位的值为模数，应舍弃，符号位进位的值等于操作数，不溢出&lt;/p&gt;
&lt;p&gt;$[z]_补=1,1000000$&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id="351-浮点加减法运算"&gt;3.5.1 浮点加减法运算
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;在尾数右规时，尾数末位的几位会因超出计算机字长而被丢弃，从而产生误差。此时，计算机可以按选定的方式进行舍入操作。&lt;/li&gt;
&lt;li&gt;在尾数规格化和尾数舍入时，可能会对结果的阶码执行加、减运算。因此，必须考虑结果的阶码出现溢出的问题。
- 由于浮点数中阶码的位数决定了浮点数的表示范围，因此，对于浮点运算，当阶码出现溢出时，表示运算结果出现溢出。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注：下例并不符合IEEE 754标准&lt;/p&gt;
&lt;p&gt;【例1】设$x = 2^{-101} \times (-0.101011)$，$y = 2^{-010} \times 0.001110$，x和y的阶码和尾数都用 &lt;strong&gt;双符号补码&lt;/strong&gt; 表示，阶码为3位、尾数为6位（均不含符号位），请按照浮点数加减法运算步骤计算$x + y$。&lt;/p&gt;
&lt;p&gt;解析：$E_x = -101$ $M_x = -0.101011$&lt;/p&gt;
&lt;p&gt;$E_y = -010$ $M_y = 0.001110$&lt;/p&gt;
&lt;p&gt;$[E_x]_{补} = 11,011$ $[M_x]_{补} = 11.010101$&lt;/p&gt;
&lt;p&gt;$[E_y]_{补} = 11,110$ $[M_y]_{补} = 00.001110$&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="对阶"&gt;&lt;strong&gt;对阶&lt;/strong&gt;
&lt;/h4&gt;&lt;p&gt;对阶原则： &lt;strong&gt;小阶向大阶看齐&lt;/strong&gt; ，尾数右移相应位数（两个阶的差的绝对值）&lt;/p&gt;
&lt;p&gt;$[E_x]_{补} - [E_y]_{补} = [E_x]_{补} + [-E_y]_{补} = 11,011 + 00,010 = 11,101 = [E_x - E_y]_{补}$&lt;/p&gt;
&lt;p&gt;$E_x - E_y = -3$ 这表明：x的阶码比y的阶码小3&lt;/p&gt;
&lt;p&gt;因此，x的阶码应向y的阶码看齐（即相同）；相应地，需要将x的尾数向右移动3位&lt;/p&gt;
&lt;p&gt;对阶后：$[E_x]_{补} = [E_y]_{补} = 11,110$ $[M_x]_{补} = 11.010101 \xrightarrow{算术右移3位} 11.111010(101)$&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;上式括号中的101是移出位，但暂时保留，称为 &lt;strong&gt;保留附加位&lt;/strong&gt; 。&lt;strong&gt;保留附加位参与中间运算以提高运算精度&lt;/strong&gt; ，尾数运算结束，结果规格化后再进行舍入。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id="尾数运算"&gt;&lt;strong&gt;尾数运算&lt;/strong&gt;
&lt;/h4&gt;&lt;p&gt;${[M_x + M_y]}_补=00,001000(101)$&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id="结果规格化"&gt;&lt;strong&gt;结果规格化&lt;/strong&gt;
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;左规&lt;/strong&gt; ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;尾数运算结果为 $11,1bb......b$ 或 $00,0bb......b$ ：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;尾数每左移1位，阶码减1&lt;/strong&gt; ，直到尾数成为规格化数为止。&lt;/li&gt;
&lt;li&gt;还需要判断阶码是否 &lt;strong&gt;下溢&lt;/strong&gt; 。若发生下溢（符号位为10），可认为 &lt;strong&gt;结果为0&lt;/strong&gt; 。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;右规&lt;/strong&gt; ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;尾数运算结果为10.bb &amp;hellip; b或01.bb &amp;hellip; b，即尾数运算结果溢出：
&lt;ul&gt;
&lt;li&gt;尾数只需要右移1位，阶码加1。&lt;/li&gt;
&lt;li&gt;还需要判断阶码是否上溢。若发生上溢（符号位为01），可认为结果为∞。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本题则符合左规的条件，算术左移2位，得到 $00,100010(1)$&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;且有2位保留附加位直接移入了数值位。因此，采用保留附加位可以提高运算精度。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;相应的，将阶码减2，得到$[E]_补={[E_y]}_补+[-2]_补=11,110+11,110=11,110$&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;当阶码的符号位为01（上溢）和10（下溢）时表示溢出。因此本例未溢出。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4 id="舍入处理"&gt;舍入处理
&lt;/h4&gt;&lt;p&gt;在进行对阶时会用到算术右移，而进行结果规格化时，可能会用到算术右移。这会导致尾数末位的几位因超出机器字长而被丢掉，从而产生误差。此时，机器可按选定方式进行舍入处理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;截断法&lt;/strong&gt; ：直接丢弃超出机器字长的尾数低位（导致 &lt;strong&gt;误差积累&lt;/strong&gt; ）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;末位恒置1法&lt;/strong&gt; ：将机器字长内的尾数的最低位恒置为1（损失1位精度，但误差积累较小）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;0舍1入法&lt;/strong&gt; ：当需要丢弃的尾数低位中的最高位为1时，将机器字长内的尾数的最低位加1&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;采用该方法，若破坏规格化结果，则还需要再次进行规格化处理&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于本题，运用以上方法来处理要被舍弃的最后一位1，结果分别如下：&lt;/p&gt;
&lt;p&gt;$00,100010$	$00,100011$	$00,100011$&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;【练习】下列有关浮点数加减运算的叙述中，正确的是（ &lt;strong&gt;D&lt;/strong&gt; ）。&lt;/p&gt;
&lt;p&gt;I. 对阶操作不会引起阶码上溢或下溢
II. 右规时可能引起阶码上溢
III. 左规时可能引起阶码下溢
IV. 尾数溢出时浮点数本身不一定溢出&lt;/p&gt;
&lt;p&gt;A. 仅II、III
B. 仅I、II、IV
C. 仅I、III、IV
D. I、II、III、IV&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="352-ieee-754-浮点数运算"&gt;3.5.2 IEEE 754 浮点数运算
&lt;/h3&gt;&lt;p&gt;图中包含以下文字：&lt;/p&gt;
&lt;p&gt;IEEE 754浮点数的阶码采用移码表示，尾数采用原码表示，并且尾数的最高位隐藏。&lt;/p&gt;
&lt;p&gt;因此，IEEE 754浮点数的加减运算与（上节课介绍的）基于补码表示的浮点数的加减运算有如下不同：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在对阶和结果规格化过程中，涉及到 &lt;strong&gt;阶码&lt;/strong&gt;的加减运算时采用 &lt;strong&gt;移码的加减运算&lt;/strong&gt; 规则。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;尾数运算采用原码运算规则，且隐藏位要参与尾数运算&lt;/strong&gt; 。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;隐藏位参与尾数规格化判断和规格化过程&lt;/strong&gt; 。&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;若尾数形式为1……，则为 &lt;strong&gt;规格化&lt;/strong&gt; 尾数。&lt;/li&gt;
&lt;li&gt;若尾数形式为0……，则需要进行 &lt;strong&gt;左规&lt;/strong&gt; （将尾数左移1位，相应地将阶码减1）， &lt;strong&gt;直到尾数规格化为止&lt;/strong&gt; 。&lt;/li&gt;
&lt;li&gt;若尾数形式为1b……，则需要进行 &lt;strong&gt;1次右规&lt;/strong&gt; （将尾数右移1位，相应地将阶码加1）。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="4"&gt;
&lt;li&gt;&lt;strong&gt;舍入处理&lt;/strong&gt; ：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;就近舍入：舍入为可表示的最近的数，如果数据正好处于两个可表示的数的中间，则向偶数舍入。&lt;/li&gt;
&lt;li&gt;朝 $+\infty$ 方向舍入：总是取右侧可表示的最近的数。&lt;/li&gt;
&lt;li&gt;朝 $-\infty$ 方向舍入：总是取左侧可表示的最近的数。&lt;/li&gt;
&lt;li&gt;截断处理：直接丢弃多余位，朝0方向舍入。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="5"&gt;
&lt;li&gt;&lt;strong&gt;溢出判断&lt;/strong&gt; ：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;浮点运算的溢出可通过阶码的溢出来判断。对于IEEE 754单精度浮点数而言，向右规格化使阶码为全1（即11111111，真值为-128）时发生 &lt;strong&gt;规格化上溢&lt;/strong&gt; ；向左规格化使阶码为全0时发生 &lt;strong&gt;规格化下溢&lt;/strong&gt; 。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;【举例】设IEEE 754单精度浮点数x和y的机器码分别为 $00C0\ 0000H$ , $0080\ 0000H$ , 求 $x-y$&lt;/p&gt;
&lt;p&gt;首先将其转换为二进制形式：&lt;/p&gt;
&lt;p&gt;$x=0|00000001|10000000000000000000000000$&lt;/p&gt;
&lt;p&gt;$y=0|00000001|00000000000000000000000000$&lt;/p&gt;
&lt;p&gt;可知， ${[E)_x]}_移=00000001={[E_y]}_移$ 阶码相同，无需对阶&lt;/p&gt;
&lt;p&gt;考虑到IEEE 754浮点数的 &lt;strong&gt;隐藏位&lt;/strong&gt; ，可得 ${[M_x]}_原=0.11000......$&lt;/p&gt;
&lt;p&gt;${[M_y]}_原=0.1000......$&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;小数点后面的第一个1就是隐藏位&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;$M_x=1.1$ $M_y=1.0$ $M=M_x-M_y=0.1$&lt;/p&gt;
&lt;p&gt;M需要进行左规，小数点左移1位，阶码减1， $E=-127$ , $[E]_移=00000000$&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;IEEE 754规定，阶码全为0时为非规格化浮点数。因此，该运算结果产生了 &lt;strong&gt;规格化下溢&lt;/strong&gt; ，所以本例结果应为 &lt;strong&gt;非规格化&lt;/strong&gt; 形式&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;$x-y = 2^{-126} \times 0.1=0040\ 0000H$&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="41-存储器概述"&gt;4.1 存储器概述
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;现代计算机以存储器为中心，它是计算机中存放指令和数据的主要部件。
&lt;ul&gt;
&lt;li&gt;存储器的容量越大，能存储的信息越多。&lt;/li&gt;
&lt;li&gt;提高存储系统的访问速度，是提高计算机处理信息速度的重要措施。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;因此，开发具有大容量、高速度和低成本的存储系统是计算机技术发展的关键目标之一。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="411-存储器分类"&gt;4.1.1 存储器分类
&lt;/h3&gt;&lt;h4 id="存储介质"&gt;存储介质
&lt;/h4&gt;&lt;p&gt;按 &lt;strong&gt;存储介质&lt;/strong&gt; 可分为 &lt;strong&gt;磁存储器、光存储器、半导体存储器&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;磁存储器&lt;/strong&gt; ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;以磁性材料作为存储介质。&lt;/li&gt;
&lt;li&gt;利用磁化单元的不同磁化方向来存储数据0和1。&lt;/li&gt;
&lt;li&gt;主要包括磁芯、磁盘、磁带存储器。&lt;/li&gt;
&lt;li&gt;磁盘、磁带中都包含有机械装置，因此体积大、存取速度慢，但其单位容量成本最低。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;光存储器&lt;/strong&gt; ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;利用介质的光学特性读出数据。
&lt;ul&gt;
&lt;li&gt;例如CD-ROM、DVD-ROM都以刻痕的形式将数据存储在盘面上，用激光束照射盘面，靠盘面的不同反射率来读出信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;光盘存储器成本低廉，适用于电子出版物的发行。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;半导体存储器&lt;/strong&gt; ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用半导体器件组成的存储器。&lt;/li&gt;
&lt;li&gt;存取速度快、体积小、性能可靠，但单位容量成本相对较高。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id="存取方式"&gt;存取方式
&lt;/h4&gt;&lt;p&gt;按 &lt;strong&gt;存取方式&lt;/strong&gt; 可分为 &lt;strong&gt;顺序存储器、随机存储器、直接存储器&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;顺序存储器&lt;/strong&gt; ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;存储单元中的内容只能按地址顺序访问。
&lt;ul&gt;
&lt;li&gt;存取速度与存储单元的位置有关。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;磁带存储器就是典型的顺序存储器。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;随机存储器&lt;/strong&gt; ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可按指定的任何一个存储单元的地址对其内容进行存取。
&lt;ul&gt;
&lt;li&gt;存取速度与存储单元的位置无关。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;早期的磁芯存储器和当前广泛使用的半导体存储器都是随机存储器。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;直接存储器&lt;/strong&gt; ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不必经过顺序搜索就能在存储器中直接存取信息。
&lt;ul&gt;
&lt;li&gt;兼有随机存储器和顺序存储器的访问特性。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;典型的如磁盘存储器。由于磁盘存在机械寻道和旋转延迟，因此数据访问时间和磁头与目标扇区的距离有关。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id="可改写性"&gt;可改写性
&lt;/h4&gt;&lt;p&gt;按 &lt;strong&gt;可改写性&lt;/strong&gt; 可分为 &lt;strong&gt;读写存储器、只读存储器&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;读写存储器&lt;/strong&gt; ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;既能读出也能写入信息&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;只读存储器&lt;/strong&gt; ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;存储的内容不允许被改变，只能读出。&lt;/li&gt;
&lt;li&gt;常见的有光盘存储器。&lt;/li&gt;
&lt;li&gt;还有半导体只读存储器，信息只能读出，不能随意写入。主要用来存放一些不需要修改的程序（例如BIOS）和常量。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id="可保存性"&gt;可保存性
&lt;/h4&gt;&lt;p&gt;按 &lt;strong&gt;可保存性&lt;/strong&gt; 可分为 &lt;strong&gt;易失性存储器、非易失性存储器&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;易失性存储器&lt;/strong&gt; ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;断电后所保存的信息会丢失&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;非易失性存储器&lt;/strong&gt; ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;断电后所保存的信息不会丢失&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id="功能和存取速度"&gt;功能和存取速度
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-19_152730.png" alt="Screenshot 2025-06-19 152730" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;按 &lt;strong&gt;功能和存取速度&lt;/strong&gt; 可分为 &lt;strong&gt;寄存器存储器、高速缓冲存储器、主存储器、辅助存储器&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;寄存器存储器&lt;/strong&gt; （CPU寄存器）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CPU内部的多个寄存器（例如MAR、MDR、ACC、MQ等）。&lt;/li&gt;
&lt;li&gt;用于存放地址、数据以及运算的中间结果。&lt;/li&gt;
&lt;li&gt;速度与CPU匹配，容量极小。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;高速缓冲存储器&lt;/strong&gt; （cache）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;寄存器与主存之间的一个高速小容量存储器。&lt;/li&gt;
&lt;li&gt;用于缓冲CPU与主存之间的性能差异，提高存储系统的访问速度。&lt;/li&gt;
&lt;li&gt;存放内容一般是即将或经常要使用的指令和数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;主存储器&lt;/strong&gt; （内存）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用于存放指令和数据。&lt;/li&gt;
&lt;li&gt;CPU可以通过主存地址随机地读写主存。&lt;/li&gt;
&lt;li&gt;存取速度低于高速缓存，但一般高于辅存。&lt;/li&gt;
&lt;li&gt;容量远大于高速缓存，但一般远小于辅存。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;辅助存储器&lt;/strong&gt; （外存）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;存放当前暂不参与运行的程序和数据，以及一些需要长期保存的信息。&lt;/li&gt;
&lt;li&gt;容量很大，但存取速度相对较低。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;存储器&lt;/th&gt;
					&lt;th&gt;按存储介质&lt;/th&gt;
					&lt;th&gt;按存取方式&lt;/th&gt;
					&lt;th&gt;按可改写性&lt;/th&gt;
					&lt;th&gt;按可保存性&lt;/th&gt;
					&lt;th&gt;按功能和存取速度&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;磁带&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;磁存储器&lt;/td&gt;
					&lt;td&gt;顺序存储器&lt;/td&gt;
					&lt;td&gt;读写存储器&lt;/td&gt;
					&lt;td&gt;非易失性存储器&lt;/td&gt;
					&lt;td&gt;辅存（外存）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;机械硬盘&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;磁存储器&lt;/td&gt;
					&lt;td&gt;直接存储器&lt;/td&gt;
					&lt;td&gt;读写存储器&lt;/td&gt;
					&lt;td&gt;非易失性存储器&lt;/td&gt;
					&lt;td&gt;辅存（外存）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;光盘&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;光存储器&lt;/td&gt;
					&lt;td&gt;直接存储器&lt;/td&gt;
					&lt;td&gt;只读存储器&lt;/td&gt;
					&lt;td&gt;非易失性存储器&lt;/td&gt;
					&lt;td&gt;辅存（外存）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;BIOS芯片&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;半导体存储器&lt;/td&gt;
					&lt;td&gt;随机存储器&lt;/td&gt;
					&lt;td&gt;只读存储器&lt;/td&gt;
					&lt;td&gt;非易失性存储器&lt;/td&gt;
					&lt;td&gt;辅存（外存）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;固态硬盘&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;半导体存储器&lt;/td&gt;
					&lt;td&gt;随机存储器&lt;/td&gt;
					&lt;td&gt;读写存储器&lt;/td&gt;
					&lt;td&gt;非易失性存储器&lt;/td&gt;
					&lt;td&gt;辅存（外存）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;CPU寄存器&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;半导体存储器&lt;/td&gt;
					&lt;td&gt;随机存储器&lt;/td&gt;
					&lt;td&gt;读写存储器&lt;/td&gt;
					&lt;td&gt;易失性存储器&lt;/td&gt;
					&lt;td&gt;寄存器存储器&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;cache&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;半导体存储器&lt;/td&gt;
					&lt;td&gt;随机存储器&lt;/td&gt;
					&lt;td&gt;读写存储器&lt;/td&gt;
					&lt;td&gt;易失性存储器&lt;/td&gt;
					&lt;td&gt;高速缓冲存储器&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;内存&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;半导体存储器&lt;/td&gt;
					&lt;td&gt;随机存储器&lt;/td&gt;
					&lt;td&gt;读写存储器&lt;/td&gt;
					&lt;td&gt;易失性存储器&lt;/td&gt;
					&lt;td&gt;主存（内存）&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="412-存储器性能指标与存储系统层次结构"&gt;4.1.2 存储器性能指标与存储系统层次结构
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;存储器性能指标&lt;/strong&gt; 分为 &lt;strong&gt;存储容量、存取速度&lt;/strong&gt; 这两个性能指标&lt;/p&gt;
&lt;h4 id="存储容量"&gt;存储容量
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;存储容量是指存储器可以 &lt;strong&gt;存储的二进制信息的总量&lt;/strong&gt; 。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如主存储器中有MAR和MDR，MAR的位数决定了 &lt;strong&gt;存储单元&lt;/strong&gt; 的数量，MDR的位数与 &lt;strong&gt;存储字长&lt;/strong&gt; 相等&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
$$
 存储容量=存储字长 \times 存储单元数量
 $$&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id="存储速度"&gt;存储速度
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;存取时间&lt;/strong&gt; ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;启动一次存储器操作到该操作完成所经历的时间。
&lt;ul&gt;
&lt;li&gt;读出时间&lt;/li&gt;
&lt;li&gt;写入时间&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;读出时间和写入时间可能不同&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;存取周期&lt;/strong&gt; ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;连续两次访问存储器操作（读操作或写操作）之间所需要的最短时间间隔。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对于主存，存取周期除包括存取时间外，还包括存储器状态的稳定恢复时间，因此存取周期略大于存取时间。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 第 n 次存取 | 恢复时间 | 第 n+1 次存取 |
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;| 存取周期 |
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;存储器带宽&lt;/strong&gt; ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单位时间内存储器所能传输的信息量（单位：b/s或B/s）。&lt;/li&gt;
&lt;li&gt;它是衡量数据传输速率的重要指标，与一次传输的数据位的多少和存取时间的长短有关。
&lt;ul&gt;
&lt;li&gt;一般而言，数据位宽越大、存取时间越短，则存储器带宽越高。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id="存储器层次结构"&gt;存储器层次结构
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-19_154735.png" alt="Screenshot 2025-06-19 154735" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;上层存储器可为下层存储器做缓冲&lt;/strong&gt; ，将最经常使用的数据的副本调度到上层，使得CPU只需要访问上层的快速小容量存储器即可获得大部分数据。可以 &lt;strong&gt;有效提高存储系统的访问速度，缓解CPU与主存（内存）、主存（内存）与辅存（外存）的性能差异&lt;/strong&gt; 。&lt;/li&gt;
&lt;li&gt;另外， &lt;strong&gt;使用大容量辅存&lt;/strong&gt; （外存）， &lt;strong&gt;缓解了主存（内存）容量不足的问题&lt;/strong&gt; 。&lt;/li&gt;
&lt;li&gt;基于这种层次结构，就可构建出满足应用需求的 &lt;strong&gt;存储容量大、存取速度快、成本低&lt;/strong&gt; 的存储系统。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="413-主存的基本结构"&gt;4.1.3 主存的基本结构
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;主存是机器指令直接操作的存储器，需要基于 &lt;strong&gt;主存地址&lt;/strong&gt; 对其进行 &lt;strong&gt;随机访问&lt;/strong&gt; 。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-20_001711.png" alt="Screenshot 2025-06-20 001711" loading="lazy" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CPU &lt;strong&gt;从主存中读取信息&lt;/strong&gt; 的过程：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-20_002344.png" alt="Screenshot 2025-06-20 002344" loading="lazy" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CPU通过地址总线将某值（如图中的110）送入MAR&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CPU通过控制信号，控制地址译码器进行译码输出&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CPU通过控制信号，控制主存将该存储单元中的信息读取到存储器数据寄存器MDR中暂存&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CPU通过控制信号，将MDR中的信息通过数据总线 读取到CPU中&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CPU &lt;strong&gt;向主存中写入信息&lt;/strong&gt; 的过程：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-06-20_002916.png" alt="Screenshot 2025-06-20 002916" loading="lazy" /&gt;&lt;/li&gt;
&lt;li&gt;CPU通过数据总线，将待写入主存中的信息，写入到主存的MDR中&lt;/li&gt;
&lt;li&gt;CPU通过地址总线，将待写入信息的存储单元的地址，送入存储器地址寄存器MAR中&lt;/li&gt;
&lt;li&gt;假设待写入信息的存储单元的地址为某值（如图中的111）&lt;/li&gt;
&lt;li&gt;CPU通过控制信号，控制地址译码器进行译码输出&lt;/li&gt;
&lt;li&gt;CPU通过控制信号，将之前送入到MDR中的信息，写入到该存储单元&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="414-用于地址译码的译码结构"&gt;4.1.4 用于地址译码的译码结构
&lt;/h3&gt;&lt;h4 id="单译码结构"&gt;单译码结构
&lt;/h4&gt;&lt;p&gt;【举例】若主存的存储体包含64个存储单元，每个存储单元只能存储1个二进制位，请给出只使用一个译码器就能寻址这64个存储单元的方案（即译码器的地址输入线和译码输出线各需要几条）。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;因为 $2^6=64$ 所以 &lt;strong&gt;地址输入线&lt;/strong&gt; 有6条， &lt;strong&gt;译码输出线&lt;/strong&gt; 数量和存储单元数量相等，也就是64条&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;若存储体包含64k个存储单元，则译码器的地址输入线和译码输出线各需要几条？&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;64k条 ; 16条($2^{16}=64k$)&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;随着存储容量（存储体中存储单元的数量）的增大，译码输出线也随之增多，这样，译码电路的开销就不容忽视，过多的译码输出线也会占用较多的晶圆面积，为生产制造带来困难。&lt;/li&gt;
&lt;li&gt;因此， &lt;strong&gt;单译码结构只适用于容量很小的存储芯片&lt;/strong&gt; （例如容量在几百个存储单元以内的存储芯片）。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h4 id="双译码结构"&gt;双译码结构
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-18_214418.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;【举例】若相同存储容量，改用单译码结构，则译码输出线有多少条？&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;$2^n$ 条&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;在大容量存储器中普遍采用双译码结构&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="415-主存中数据的存放"&gt;4.1.5 主存中数据的存放
&lt;/h3&gt;&lt;h4 id="机器字长与存储字长的区别"&gt;机器字长与存储字长的区别
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;机器字长&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;定义：CPU一次能够处理的二进制数据的位数。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;存储字长&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;定义：主存中的一个存储单元所能存储的二进制位数。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;注意事项&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;存储字长与机器字长不一定相同。&lt;/li&gt;
&lt;li&gt;例如：机器字长为32位的计算机，所采用的存储字长可以是16位、32位或64位。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="地址访问模式"&gt;地址访问模式
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;主存通常按字节进行编址，而存储字长（主存中的一个存储单元所能存储的二进制位数）是字节的2的整数次幂倍（例如1字节，2字节，4字节）。&lt;/li&gt;
&lt;li&gt;以机器字长为 &lt;strong&gt;32位&lt;/strong&gt; 的计算机为例，对主存的访问既可以按 &lt;strong&gt;字节访问&lt;/strong&gt; ，也可以按 &lt;strong&gt;16位半字访问&lt;/strong&gt; ，还可以按 &lt;strong&gt;32位字访问&lt;/strong&gt; 。因此，可将主存地址分为：
&lt;ul&gt;
&lt;li&gt;字节地址&lt;/li&gt;
&lt;li&gt;半字地址&lt;/li&gt;
&lt;li&gt;字地址&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-18_220234.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;不同的地址访问模式&lt;/strong&gt; （字节访问、半字访问、字访问） &lt;strong&gt;所使用的主存地址实际上都是字节地址&lt;/strong&gt; 。&lt;/li&gt;
&lt;li&gt;CPU在执行指令的时候可以将字节地址的低2位用于访问控制：
&lt;ul&gt;
&lt;li&gt;采用字节访问模式，字节地址的低2位用于选择字存储单元中的哪一个字节。&lt;/li&gt;
&lt;li&gt;采用半字访问模式，字节地址的倒数第2位用于选择字存储单元中的哪个半字。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="小端和大端方式"&gt;小端和大端方式
&lt;/h5&gt;&lt;p&gt;（下图上部分为小端方式，下部分为大端方式）&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-18_220801.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;小端方式&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将数据的&lt;strong&gt;低字节&lt;/strong&gt;保存在主存的低地址中，而数据的&lt;strong&gt;高字节&lt;/strong&gt;保存在主存的高地址中。&lt;/li&gt;
&lt;li&gt;这样可以&lt;strong&gt;将主存地址的高低与数据的位权有效地结合起来&lt;/strong&gt;，高地址存储的数据部分的权值高，低地址存储的数据部分的权值低，符合逻辑。&lt;/li&gt;
&lt;li&gt;Intel x86、IA64、RISC-V等处理器采用&lt;strong&gt;小端方式&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;大端方式&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将数据的&lt;strong&gt;高字节&lt;/strong&gt;保存在主存的低地址中，而数据的&lt;strong&gt;低字节&lt;/strong&gt;保存在主存的高地址中。&lt;/li&gt;
&lt;li&gt;符合人类的正常思维。&lt;/li&gt;
&lt;li&gt;PowerPC处理器采用&lt;strong&gt;大端方式&lt;/strong&gt;；ARM、MIPS等处理器同时支持大端方式和小端方式。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;注意事项&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;上述两种方式并没有绝对的优劣之分，它们在不同的处理器架构和应用场景中都有各自的适用性和优势。&lt;/li&gt;
&lt;li&gt;除处理器外，大小端方式还涉及外部设备设计、网络数据传输、音视频文件保存等。&lt;/li&gt;
&lt;li&gt;小端与大端方式的区别不仅存在于处理器的寄存器、存储器中，在指令集、系统总线等各个层次中也可能存在差别。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="数据的边界对齐"&gt;数据的边界对齐
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;主存空间&lt;/strong&gt; 通常按&lt;strong&gt;字节&lt;/strong&gt;进行编址。&lt;/li&gt;
&lt;li&gt;高级语言中 &lt;strong&gt;不同数据类型的变量&lt;/strong&gt; 所包含的&lt;strong&gt;字节数量&lt;/strong&gt;可能不同。
&lt;ul&gt;
&lt;li&gt;编译器在为这些变量分配主存空间时，理论上可以从主存空间的&lt;strong&gt;任何一个字节地址&lt;/strong&gt;开始。&lt;/li&gt;
&lt;li&gt;当一个多字节变量被编译器 &lt;strong&gt;分布在不同的字存储单元中&lt;/strong&gt; 时，访问该变量就需要 &lt;strong&gt;多个存取周期&lt;/strong&gt; 。&lt;/li&gt;
&lt;li&gt;为了 &lt;strong&gt;提高数据访问效率&lt;/strong&gt; ，应该要考虑数据变量、数据结构在 &lt;strong&gt;主存空间中的边界对齐问题&lt;/strong&gt; 。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;【举例】假设存储字长为32位，为C语言不同数据类型的变量分配主存空间&lt;/p&gt;
&lt;h5 id="数据的边界未对齐"&gt;数据的边界未对齐
&lt;/h5&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-18_225726.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对存储空间的利用率最高&lt;/li&gt;
&lt;li&gt;存在访问性能问题，例如：
&lt;ul&gt;
&lt;li&gt;变量c的8个字节分布在3个存储单元中（访问该变量需要3个存取周期）&lt;/li&gt;
&lt;li&gt;变量e的2个字节分布在2个存储单元中（访问该变量需要2个存取周期）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="数据的边界对齐-1"&gt;数据的边界对齐
&lt;/h5&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-18_225730.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;有效提升了访问性能，例如：
&lt;ul&gt;
&lt;li&gt;变量c的8个字节分布在2个存储单元中（访问该变量需要2个存取周期）&lt;/li&gt;
&lt;li&gt;变量e的2个字节分布在1个存储单元中（访问该变量需要1个存取周期）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="边界对齐的规则"&gt;边界对齐的规则
&lt;/h5&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-18_230203.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;字节数据&lt;/strong&gt; 不存在边界对齐问题（因为主存空间就是按字节编址的 如char型）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;半字（2字节）&lt;/strong&gt; 数据的起始字节地址的最低1位为0（即地址是2的整数倍 如short型）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;单字（4字节）&lt;/strong&gt; 数据的起始字节地址的最低2位为00（即地址是4的整数倍 如int型）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;双字（8字节）&lt;/strong&gt; 数据的起始字节地址的最低3位为000（即地址是8的整数倍 如double型）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;【2012考研 题15】某计算机存储器按字节编址，采用 &lt;strong&gt;小端方式&lt;/strong&gt; 存放数据。假定编译器规定int型和short型长度分别为32位和16位，并且 &lt;strong&gt;数据按边界对齐&lt;/strong&gt; 存储。某C语言程序段如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;short&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;273&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;若record变量的 &lt;strong&gt;首地址为0xC008&lt;/strong&gt; ，则地址0xC008中内容及record.c的地址分别是（ ）。&lt;/p&gt;
&lt;p&gt;A. 0x00, 0xC00D&lt;/p&gt;
&lt;p&gt;B. 0x00, 0xC00E&lt;/p&gt;
&lt;p&gt;C. 0x11, 0xC00D&lt;/p&gt;
&lt;p&gt;D. 0x11, 0xC00E&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;record.a=273 转化为十六进制数0x00000111&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-18_231756.png" alt="" loading="lazy" /&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id="421-sram-存储元"&gt;4.2.1 SRAM 存储元
&lt;/h3&gt;&lt;h4 id="静态随机存取存储器"&gt;静态随机存取存储器
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;静态随机存取存储器&lt;/strong&gt; 即SRAM (Static Random-Access Memory) 是随机存取存储器的一种
&lt;ul&gt;
&lt;li&gt;所谓 &lt;strong&gt;“静态”&lt;/strong&gt; ，是指这种RAM只要保持通电，其内部所存储的数据就可以保持不变，而 &lt;strong&gt;不需要&lt;/strong&gt; 进行 &lt;strong&gt;周期性地刷新&lt;/strong&gt; 。相比之下，动态随机存取存储器DRAM（Dynamic Random-Access Memory）则需要。&lt;/li&gt;
&lt;li&gt;目前，SRAM内部的存储元（存储1个二进制位的单元）一般采用多个金属-氧化物半导体场效应晶体管MOSFET（Metal-Oxide-Semiconductor Field-Effect Transistor）来构建，MOSFET常简称为 &lt;strong&gt;MOS管&lt;/strong&gt; 。&lt;/li&gt;
&lt;li&gt;一旦断电，SRAM和DRAM内部存储的数据还是会消失的，也就是说 &lt;strong&gt;SRAM和DRAM属于易失性存储器&lt;/strong&gt; ，这与属于非易失性存储器的只读存储器ROM（Read-Only Memory）是不同的。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="工作原理及特点"&gt;工作原理及特点
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-19_225541.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="422-sram-存储元扩展和存储阵列扩展"&gt;4.2.2 SRAM 存储元扩展和存储阵列扩展
&lt;/h3&gt;&lt;h4 id="存储元扩展"&gt;存储元扩展
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-19_230039.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;若想一次访问多个存储元，须 &lt;strong&gt;将多个存储阵列的行选通线并联、列选通线并联&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;同一时刻，只能有一条行选通线和一条列选通线输出有效信号，因此只能有一个存储元被选中，也就是一次只能访问一位数据。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h4 id="存储阵列扩展"&gt;存储阵列扩展
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-19_230836.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="423-sram-存储器结构及其芯片实例"&gt;4.2.3 SRAM 存储器结构及其芯片实例
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-19_231835.png" alt="" loading="lazy" /&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;每个型号的SRAM芯片有其特定的读写周期特性，只有按照其读写周期去访问SRAM芯片，才能保证读写操作的正确性。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;【习题1】某SRAM中每个存储单元为8位，则以下描述正确的是（ B ）。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I. 数据线为8位&lt;/p&gt;
&lt;p&gt;II. 地址线为3位&lt;/p&gt;
&lt;p&gt;III. 存储字长为8位&lt;/p&gt;
&lt;p&gt;IV. 机器字长为8位&lt;/p&gt;
&lt;p&gt;A. 仅I、II B. 仅I、III C. 仅II、III D. 仅I、III、IV&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;本题的 I 和 III 正确，是与存储单元的位数相关&lt;/p&gt;
&lt;p&gt;II 地址线的数量用于和存储单元的数量进行对应，即3位地址线能寻址 $2^3=8$ 个地址，与题目无关&lt;/p&gt;
&lt;p&gt;IV 机器字长通常指的是CPU一次能够处理的数据位数，与题目无关&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;【习题2】某SRAM的存储容量为8K × 8位，则地址线和数据线的数量分别为（ B ）。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A. 8、8&lt;/p&gt;
&lt;p&gt;B. 13、8&lt;/p&gt;
&lt;p&gt;C. 3、3&lt;/p&gt;
&lt;p&gt;D. 8、3&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;存储容量为8K × 8位，意味着有8K个存储单元，每个存储单元8位，数据线的数量为8。&lt;/p&gt;
&lt;p&gt;地址线的数量需要能够寻址到8K个地址，即 $2^{13}=8192$ ，所以地址线数量为13。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;【习题3】某SRAM芯片的容量为256K × 16位，除电源和接地端外，该芯片的引脚的最小数目为（ D ）。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A. 33&lt;/p&gt;
&lt;p&gt;B. 34&lt;/p&gt;
&lt;p&gt;C. 35&lt;/p&gt;
&lt;p&gt;D. 36&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;由上两题的经验易得地址线为18 ( $2^{18}=262144$ )&lt;/p&gt;
&lt;p&gt;数据线为16位，控制信号 &lt;em&gt;WE&lt;/em&gt;和&lt;em&gt;CS&lt;/em&gt; 2个&lt;/p&gt;
&lt;p&gt;加起来为36&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id="431-dram-存储元及其扩展"&gt;4.3.1 DRAM 存储元及其扩展
&lt;/h3&gt;&lt;h4 id="动态随机存取存储器"&gt;动态随机存取存储器
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;动态随机存取存储器，即 &lt;strong&gt;DRAM&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;相较于SRAM，设法 &lt;strong&gt;减少MOS管&lt;/strong&gt; ，通过 &lt;strong&gt;引入存储电容&lt;/strong&gt; 暂存电荷的方式来保存数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;目前在内存中较为常见的结构是 &lt;strong&gt;单MOS管&lt;/strong&gt; 和 &lt;strong&gt;电容&lt;/strong&gt; 构成的DRAM存储元&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="存储元工作原理"&gt;存储元工作原理
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;栅极G和源极S接入高电平为电容充电&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-20_155758.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;此时MOS管打开，栅极G接入高电平而源极没有，则电容通过MOS管放电&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-20_160030.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;上述电容C放电过程，可看作是对存储元的 &lt;strong&gt;读操作&lt;/strong&gt; ，可以发现，读操作会导致原本存储的1读取后变成0。为避免读操作导致的 &lt;strong&gt;数据丢失&lt;/strong&gt; ，数据1读出后应将数据1重新写入，称为&lt;strong&gt;数据恢复&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-20_160226.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;由于MOS管不可能完美关断， &lt;strong&gt;电容C上的电荷会逐渐泄露&lt;/strong&gt; ，数据1只能保存较短的时间。为避免数据丢失，必须定期采用类似“读操作”的方式对电容C补充电荷，称为&lt;strong&gt;刷新&lt;/strong&gt;，这也是动态RAM（DRAM）得名的原因。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="存储元扩展-1"&gt;存储元扩展
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-20_160933.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为了读取一行中某个存储元的信息， &lt;strong&gt;却破坏了这一行中所有存储元的信息&lt;/strong&gt; 。&lt;/li&gt;
&lt;li&gt;因此， &lt;strong&gt;每次读操作过后，必须立即进行写操作&lt;/strong&gt; 。&lt;/li&gt;
&lt;li&gt;灵敏读出/恢复放大器会根据锁存的值，将各条列线拉高到DRAM的工作电压 $V_{CC}$ ，或拉低到 $GND$ ，以恢复各存储元中电容的原本状态（即原本存储的信息）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="读写流程"&gt;读/写流程
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;DRAM的读操作流程：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;预充电操作&lt;/li&gt;
&lt;li&gt;访问操作&lt;/li&gt;
&lt;li&gt;信号检测&lt;/li&gt;
&lt;li&gt;数据恢复&lt;/li&gt;
&lt;li&gt;数据输出&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;DRAM的写操作流程：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;预充电操作&lt;/li&gt;
&lt;li&gt;访问操作&lt;/li&gt;
&lt;li&gt;信号检测&lt;/li&gt;
&lt;li&gt;数据恢复&lt;/li&gt;
&lt;li&gt;数据输入&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;写操作流程需要经历与读操作前4步一样的流程，这样， &lt;strong&gt;写入操作也可以实现和读操作一样的行刷新功能&lt;/strong&gt; 。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="dram和sram的对比"&gt;DRAM和SRAM的对比
&lt;/h4&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;对比项目&lt;/th&gt;
					&lt;th&gt;动态随机存取存储器DRAM&lt;/th&gt;
					&lt;th&gt;静态随机存取存储器SRAM&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;构成存储元的元件&lt;/td&gt;
					&lt;td&gt;1个MOS管 和 1个电容&lt;/td&gt;
					&lt;td&gt;6个MOS管&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;读操作后需要“数据恢复”&lt;/td&gt;
					&lt;td&gt;需要（读操作会改变原本存储的信息）&lt;/td&gt;
					&lt;td&gt;不需要（读操作不改变原本存储的信息）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;需要动态“刷新”&lt;/td&gt;
					&lt;td&gt;需要（电容的电荷会泄露）&lt;/td&gt;
					&lt;td&gt;不需要（功耗管和工作管负责保持存储状态）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;送行列地址&lt;/td&gt;
					&lt;td&gt;分两次送（地址线复用，减少地址线）&lt;/td&gt;
					&lt;td&gt;同时送&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;运行速度&lt;/td&gt;
					&lt;td&gt;较慢&lt;/td&gt;
					&lt;td&gt;快&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;集成度&lt;/td&gt;
					&lt;td&gt;高&lt;/td&gt;
					&lt;td&gt;低&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;发热量&lt;/td&gt;
					&lt;td&gt;小&lt;/td&gt;
					&lt;td&gt;大&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;存储成本&lt;/td&gt;
					&lt;td&gt;低&lt;/td&gt;
					&lt;td&gt;高&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;可保存性&lt;/td&gt;
					&lt;td&gt;易失性存储器（断电后信息丢失）&lt;/td&gt;
					&lt;td&gt;易失性存储器（断电后信息丢失）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;常用应用&lt;/td&gt;
					&lt;td&gt;主存&lt;/td&gt;
					&lt;td&gt;cache&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="432-dram-动态刷新"&gt;4.3.2 DRAM 动态刷新
&lt;/h3&gt;&lt;h4 id="基本概念"&gt;基本概念
&lt;/h4&gt;&lt;h5 id="刷新周期"&gt;刷新周期
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;从数据存入DRAM开始，到数据丢失之前为止的这段时间，称为&lt;strong&gt;最大刷新周期&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;采用不同材料以及不同生产工艺生产的DRAM，其最大刷新周期可能不同，常见的有2ms、4ms、8ms等。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;刷新周期&lt;/strong&gt;是DRAM实际完成两次&lt;strong&gt;完整刷新&lt;/strong&gt;之间的时间间隔。
&lt;ul&gt;
&lt;li&gt;刷新周期 ≤ 最大刷新周期。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="刷新存储元的数量"&gt;刷新存储元的数量
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;DRAM&lt;strong&gt;按行进行&lt;/strong&gt;刷新。
&lt;ul&gt;
&lt;li&gt;为了&lt;strong&gt;缩短刷新周期&lt;/strong&gt;，可&lt;strong&gt;减少&lt;/strong&gt;存储阵列的&lt;strong&gt;行数&lt;/strong&gt;，增加列数。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;刷新操作由内存控制器负责。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="刷新与读操作的区别"&gt;刷新与读操作的区别
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;尽管读操作也具有刷新功能，但读操作与刷新操作又有所不同，&lt;strong&gt;刷新操作只需要给出行地址&lt;/strong&gt;，而不需要给出列地址。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="刷新方式"&gt;刷新方式
&lt;/h4&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;DRAM在刷新时，是不能响应CPU的访问的&lt;/strong&gt;，因此CPU对DRAM进行访问与内存控制器对DRAM进行刷新操作就存在&lt;strong&gt;内存争用问题&lt;/strong&gt;，可采用&lt;strong&gt;集中刷新、分散刷新、异步刷新&lt;/strong&gt;等刷新方式来解决。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;【举例】假设DRAM存储体的结构为128行 × 128列，存取周期为0.5微秒（μs），刷新周期为2毫秒（ms），下面给出集中刷新、分散刷新以及异步刷新三种刷新方式。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;通过上节课的介绍我们知道，&lt;strong&gt;刷新操作与读操作是类似的&lt;/strong&gt;，本例给定存取周期为0.5μs，则&lt;strong&gt;刷新一行所需的时间&lt;/strong&gt;也为0.5μs。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;本例给定&lt;strong&gt;刷新周期&lt;/strong&gt;为2ms，也就是在2ms&lt;strong&gt;内&lt;/strong&gt;，要&lt;strong&gt;完成所有&lt;/strong&gt;128&lt;strong&gt;行的刷新&lt;/strong&gt;。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;综上所述，将2ms（2000μs）划分成4000个0.5μs长的时隙，在这些时隙中选出128个时隙，每个时隙刷新一行即可。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="集中刷新"&gt;集中刷新
&lt;/h5&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-20_163456.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;读写操作期间不受刷新操作的影响，因此这段时间的访问&lt;strong&gt;速度比较快&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;但是，在集中刷新的这128个时隙中，CPU长时间不能访问DRAM，这段时间称为**“死区”时间**。
&lt;ul&gt;
&lt;li&gt;存储体包含的&lt;strong&gt;行数越多，“死区”时间就越长&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="分散刷新"&gt;分散刷新
&lt;/h5&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-20_164107.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;相当于将存取周期加上刷新1行的时长作为新的存取周期，因此&lt;strong&gt;不存在“死区”时间&lt;/strong&gt;。但是，这种方式&lt;strong&gt;刷新过于频繁&lt;/strong&gt;（在2ms所包含的4000个时隙中，有2000个时隙用于刷新，每个时隙刷新1行，共刷新2000行，每刷新128行，就相当于把存储体完整地刷新了1遍，因此在2ms内进行了约15次完整的存储体刷新），&lt;strong&gt;严重影响了系统的速度&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;不适合应用于高速存储器。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="异步刷新"&gt;异步刷新
&lt;/h5&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-20_164352.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;既充分利用了2ms时间，又保持系统高速特性。该方式&lt;strong&gt;缩短了死区时间&lt;/strong&gt;（128个时隙缩短为1个时隙），该方式相对上述两种&lt;strong&gt;效率更高&lt;/strong&gt;，更为常用。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;【习题1】DRAM按（ C ）进行刷新。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A. 存储元
B. 存储体
C. 行
D. 列&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;【习题2】以下DRAM刷新方式中，存在明显“死区”时间的是（ B ）。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A. 异步刷新
B. 集中刷新
C. 分散刷新
D. 以上都不是&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;【习题3】假设DRAM存储体的结构为64行 × 64列，存取周期为0.5μs，刷新周期为2ms，若采用集中刷新方式，则在刷新周期内，可用于读写或保持状态的连续时长为（ C ）。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A. 32μs
B. 64μs
C. 1968μs
D. 3936μs&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;在集中刷新中， $用于读写或保持的时间=刷新周期-刷新时间$&lt;/p&gt;
&lt;p&gt;而 $刷新时间=存取周期 \times 行数$&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id="433-dram-存储器芯片实例及其发展"&gt;4.3.3 DRAM 存储器芯片实例及其发展
&lt;/h3&gt;&lt;h4 id="dram-存储器芯片实例"&gt;DRAM 存储器芯片实例
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-20_165549.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;【习题】某个DRAM芯片，其容量为1K × 1位，采用地址复用技术，读写控制线为一条，除电源和接地引脚外，该芯片的引脚数最小是（B）&lt;/strong&gt;。
A. 8
B. 9
C. 10
D. 11&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;ul&gt;
&lt;li&gt;1K = 2^10 因此共需要10条地址线（例如行地址线和列地址线各5条）
&lt;ul&gt;
&lt;li&gt;题目给定采用&lt;strong&gt;地址复用&lt;/strong&gt;技术，因此&lt;strong&gt;地址线为5条&lt;/strong&gt;，由行地址线和列地址线共同使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;需要行地址选通线$\overline {RAS}$、列地址选通线$\overline {CAS}$、读写控制线$\overline {WE}$各1条。&lt;/li&gt;
&lt;li&gt;还需要&lt;strong&gt;1条数据I/O线&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;【2014考研 题15】某容量为256MB的存储器由若干4M × 8位的芯片构成，该DRAM芯片的地址引脚和数据引脚总数是（A）。&lt;/strong&gt;
A. 19
B. 22
C. 30
D. 36&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;ul&gt;
&lt;li&gt;4M = 2^2 × 2^20 = 2^22 因此共需要22条地址线（例如行地址线和列地址线各11条）
&lt;ul&gt;
&lt;li&gt;由于DRAM采用&lt;strong&gt;地址复用&lt;/strong&gt;技术，因此&lt;strong&gt;地址线为11条&lt;/strong&gt;，由行地址线和列地址线共同使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;还需要&lt;strong&gt;8条数据I/O线&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;【2018考研 题17】 假定DRAM芯片中存储阵列的行数为r、列数为c，对于一个2K × 1位的DRAM芯片，为保证其地址引脚数最少，并尽量减小刷新开销，则r、c的取值分别是（C）。&lt;/strong&gt;
A. 2048、1
B. 64、32
C. 32、64
D. 1、2048&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;ul&gt;
&lt;li&gt;2K = 2 × 2^10 = 2^11&lt;/li&gt;
&lt;li&gt;因此共需要11条地址线&lt;/li&gt;
&lt;li&gt;由于DRAM采用地址复用技术，因此地址线为6条，由行地址线和列地址线共同使用：
&lt;ul&gt;
&lt;li&gt;方案1：若行地址线为6条，则可译码出2^6 = 64条行线；列地址线为5条，则可译码出2^5 = 32条列线。&lt;/li&gt;
&lt;li&gt;方案2：若行地址线为5条，则可译码出2^5 = 32条行线；列地址线为6条，则可译码出2^6 = 64条列线。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;由于DRAM按行刷新，为了减小刷新开销，行数应该减少，而增加列数。&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;h4 id="dram发展"&gt;DRAM发展
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;异步&lt;/strong&gt;DRAM：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1970年代初：传统DRAM&lt;/li&gt;
&lt;li&gt;1990-1995年 486时代和Pentium时代的初期：
&lt;ul&gt;
&lt;li&gt;FPM-DRAM&lt;/li&gt;
&lt;li&gt;EDO-DRAM（1995年 Pentium时代的初期）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;对EDO-RAM的改进 昙花一现：
&lt;ul&gt;
&lt;li&gt;BEDO-DRAM&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;同步&lt;/strong&gt;DRAM：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1996年：SDRAM&lt;/li&gt;
&lt;li&gt;21世纪：DDR SDRAM&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;ul&gt;
&lt;li&gt;&lt;strong&gt;异步DRAM的读写操作与CPU的时钟周期无关&lt;/strong&gt;，在进行读写操作时可能会有更多的等待周期，导致性能上的损失，特别是在CPU的时钟频率很高的情况下。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;同步DRAM的读写操作与CPU的时钟周期同步&lt;/strong&gt;，内存控制器可以在时钟信号的特定边缘（上升沿或下降沿）触发数据传输。&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;h5 id="sdram-读操作"&gt;SDRAM 读操作
&lt;/h5&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-20_171043.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SDRAM自带时钟信号，能&lt;strong&gt;与系统总线频率同步&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;SDRAM可以&lt;strong&gt;突发（Burst）传输&lt;/strong&gt;：第一个列数据就绪后，每经历一个时钟周期就可得到一个数据，有效减少了数据传输的时间延迟。
&lt;ul&gt;
&lt;li&gt;通常SDRAM包含有模式寄存器，可配置&lt;strong&gt;突发传输的长度BL&lt;/strong&gt;(Burst Length)，例如1、2、4、8以及整行字。该长度是同步地向系统总线上发送数据的存储单元的个数。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;ul&gt;
&lt;li&gt;&lt;strong&gt;传统DRAM没有突发传输模式&lt;/strong&gt;，每访问一个数据，就要经历行地址、列地址、访问数据的过程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;传统DRAM属于异步DRAM&lt;/strong&gt;，其读写操作与CPU的时钟周期无关，在进行读写操作时可能会有更多的等待周期，导致性能上的损失，特别是在CPU的时钟频率很高的情况下。&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;h5 id="ddr-sdram"&gt;DDR SDRAM
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在SDRAM之后出现的&lt;strong&gt;DDR SDRAM&lt;/strong&gt;（Double Data Rate SDRAM），其内部采用了2路预取机制，第一个数据输出后，每个时钟周期可传输两次数据，&lt;strong&gt;即在时钟周期的上升沿和下降沿分别进行一次数据传输&lt;/strong&gt;，从而&lt;strong&gt;实现双倍数据传输速率&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在DDR SDRAM之后，又陆续出现了DDR2、DDR3、DDR4，其内部预取分别是4路、8路、16路，即同一个时钟周期可传输4、8、16个数据，可理解成：每个时钟周期传输两次数据，每次传输2个、4个、8个数据。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这就&lt;strong&gt;需要提高数据总线频率&lt;/strong&gt;来实现高速的数据传输，DDR2的数据总线频率是DRAM工作频率的2倍，DDR3则为4倍，DDR4则为8倍。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;【举例】以内存规格DDR4 - 3200为例。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;3200为&lt;strong&gt;等效传输频率&lt;/strong&gt;$f$（单位为MHz）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据位宽&lt;/strong&gt;$w = 8 B$（64b）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内存带宽（传输率）&lt;/strong&gt;= $f × w = (3200 × 10^6) × 8 = 25.6GB/s$&lt;/li&gt;
&lt;li&gt;由于时钟上升沿和下降沿各完成一次数据传输，因此&lt;strong&gt;数据总线频率&lt;/strong&gt; = $3200MHz ÷ 2 = 1600MHz$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DRAM工作频率&lt;/strong&gt; = $1600MHz ÷ 8 = 200MHz$&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="441-rom-只读存储器"&gt;4.4.1 ROM 只读存储器
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;只能&lt;/strong&gt;从其&lt;strong&gt;读出&lt;/strong&gt;信息、而&lt;strong&gt;不能&lt;/strong&gt;向其&lt;strong&gt;随意写入&lt;/strong&gt;信息的存储器，称为只读存储器（Read-only Memory，ROM）。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过特定方式将信息写入&lt;strong&gt;ROM&lt;/strong&gt;后，信息就固定在ROM中，即使电源&lt;strong&gt;断电&lt;/strong&gt;，所保存的&lt;strong&gt;信息也不会丢失&lt;/strong&gt;，也就是说，ROM属于&lt;strong&gt;非易失性存储器&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;按照制造工艺的不同，ROM可分为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;掩膜式只读存储器（Mask ROM，MROM）&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;ul&gt;
&lt;li&gt;待存储信息由芯片制造厂家在生产过程中按用户要求做好，芯片制成后存储信息被固定在芯片中，因而&lt;strong&gt;只能读出，不能修改&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;灵活性差，但所存储的信息固定不变，可靠性高。&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可编程只读存储器（Programmable ROM，PROM）&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;ul&gt;
&lt;li&gt;存储器出厂时，每个存储元存储的数据为“0”，用户可利用编程器进行&lt;strong&gt;一次&lt;/strong&gt;改写。&lt;/li&gt;
&lt;li&gt;PROM克服了MROM使用不便的问题，但&lt;strong&gt;仅能改写一次&lt;/strong&gt;，灵活性还是不够。&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可擦除可编程只读存储器（Erasable Programmable ROM，EPROM）&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;ul&gt;
&lt;li&gt;可&lt;strong&gt;多次写入&lt;/strong&gt;，重新写入时需要&lt;strong&gt;先擦除后写入&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;需要使用紫外线照射来擦除全部存储元的状态。&lt;/li&gt;
&lt;li&gt;EPROM比PROM和MROM使用方便、灵活、经济。&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;电可擦除可编程只读存储器（Electrically Erasable Programmable ROM，EEPROM或E²PROM）&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;ul&gt;
&lt;li&gt;可&lt;strong&gt;多次写入&lt;/strong&gt;，写入方式与EPROM相同，但不需要先擦除后写入。&lt;/li&gt;
&lt;li&gt;因为擦除时不用紫外线照射，采用&lt;strong&gt;电可擦除方式&lt;/strong&gt;（根据命令，内部自动完成），可以&lt;strong&gt;精准地擦除&lt;/strong&gt;某一个存储元，而非全片擦除。&lt;/li&gt;
&lt;li&gt;常用于存储MAC地址、存储BIOS。&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;闪存（Flash Memory）&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;ul&gt;
&lt;li&gt;逻辑结构与EEPROM相似，但存储元的结构和工艺不同。&lt;/li&gt;
&lt;li&gt;EEPROM支持字节级擦写，适合频繁更新小数据量，而闪存&lt;strong&gt;以块为单位擦写&lt;/strong&gt;（先擦后写，因此读快写慢），更&lt;strong&gt;适合存储大量数据&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;常用于SD卡、U盘、SSD、存储BIOS。&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="442-pc中的半导体存储器"&gt;4.4.2 PC中的半导体存储器
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;非易失性存储器：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;主板中的BIOS芯片（&lt;strong&gt;NOR型内存&lt;/strong&gt;或&lt;strong&gt;EEPROM&lt;/strong&gt;）&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;用于存储计算机启动时所执行的固件（例如BIOS或UEFI）的存储器，目前主流为闪存，启动固件负责初始化硬件、硬件检测并加载操作系统到主存中的RAM，以便CPU可以执行操作系统的代码，从而开始操作系统的运行。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SSD的多片存储芯片（&lt;strong&gt;NAND型闪存&lt;/strong&gt;）&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;用于存储操作系统、应用程序、用户数据的闪存，属于辅存（外存）。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;易失性存储器：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;CPU的内部cache（&lt;strong&gt;SRAM静态随机存取器&lt;/strong&gt;）&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;通常采用SRAM（无需动态刷新）作为CPU和主存之间的高速缓存，减少CPU访问主存的次数，提高数据处理速度。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;内存条的多片存储芯片（&lt;strong&gt;DDR4 SDRAM&lt;/strong&gt;）&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;用于存储CPU执行的指令和用户数据的存储器。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="451-主存的扩展及其与cpu的连接-位扩展"&gt;4.5.1 主存的扩展及其与CPU的连接 位扩展
&lt;/h3&gt;&lt;p&gt;由下图CPU可见，&lt;strong&gt;R/W#&lt;strong&gt;的&amp;quot;#&amp;ldquo;表示&lt;/strong&gt;低电平有效&lt;/strong&gt;，也就实现了和 $\overline{WE}$ 引脚的对应&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-20_234201.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="初始状态"&gt;初始状态
&lt;/h4&gt;&lt;p&gt;初始状态时，由于&lt;strong&gt;MREQ#&lt;strong&gt;的输出，存储芯片处于&lt;/strong&gt;不被选中工作&lt;/strong&gt;状态&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-20_234457.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="读操作"&gt;读操作
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;若要进行读操作，CPU的地址总线送出相应位数的地址，各存储芯片通过各自的地址引脚收到地址&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当存储芯片被同时选中工作时，其各自内部该地址所对应的存储单元被同时选中&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;之后，CPU的存储器控制引脚 $MREQ\#$ 输出低电平，各存储芯片的片选引脚 $\overline{CS}$ 收到该有效电平，因此被选中工作&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;由于CPU的输出高电平，各存储芯片将被选中的存储单元存储的1位数据，通过各自的1位数据线，传送到CPU的数据总线中相应的数据线，CPU再通过数据总线读取数据&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-21_002505.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="写操作"&gt;写操作
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;从初始状态进行写操作，从CPU送出待写入主存的数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CPU的地址总线送出相应位数的地址，各存储芯片通过各自的地址引脚收到地址&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当各存储芯片被同时选中工作时，其各自内部该地址所对应的存储单元被同时选中&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;之后，CPU的 $R/W\#$ 输出低电平，各存储芯片的使能引脚 $\overline{WE}$ 收到该低电平，但由于存储芯片不在工作状态，暂不理会此信号&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;之后，CPU的存储器控制引脚 $MREQ\#$ 输出低电平，各存储芯片的片选引脚 $\overline{CS}$ 收到该有效电平，因此被选中工作&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;各存储芯片通过各自的1位数据线，从CPU的数据总线中相应的数据线上，读入一位数据，并写入选中的存储单元&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-21_002412.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="总结"&gt;总结
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;将所有存储芯片的&lt;strong&gt;地址引脚、写使能引脚&lt;/strong&gt; $\overline{WE}$ 分别并联后再分别与CPU的地址引脚和读写控制引脚 $R/W\#$ 连接；&lt;/li&gt;
&lt;li&gt;将各存储芯片的&lt;strong&gt;数据引脚&lt;/strong&gt;依次与CPU的数据引脚进行相应连接；&lt;/li&gt;
&lt;li&gt;将所有存储芯片的&lt;strong&gt;片选引脚&lt;/strong&gt; $\overline{CS}$ 并联后与CPU的存储器请求控制引脚 $MREQ\#$ 相连。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;综上所述，位扩展又称为数据总线扩展或字长扩展。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="452-主存的扩展及其与cpu的连接-字扩展"&gt;4.5.2 主存的扩展及其与CPU的连接 字扩展
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-25_122727.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="初始状态-1"&gt;初始状态
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;CPU的存储器请求控制引脚 $MREQ\#$ 输出无效电平，也就是高电平，使得3-8译码器的8个译码输出全部都为无效电平&lt;/li&gt;
&lt;li&gt;各存储芯片的片选引脚 $\overline{CS}$ 收到该无效电平，因此不被选中工作，进而各自的8位数据总线输出为高阻态&lt;/li&gt;
&lt;li&gt;CPU的读/写控制引脚 $R/W\#$ 输出高电平，各存储芯片的写使能引脚 $\overline{WE}$ 收到该高电平&lt;/li&gt;
&lt;li&gt;由于各存储芯片都未被选择工作，因此不会理会该信号&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-25_123304.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="读操作-1"&gt;读操作
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;CPU的21条地址总线送出21位的地址，其中各存储芯片都会通过各自的18个地址引脚收到这21位地址的低18位&lt;/li&gt;
&lt;li&gt;而3-8译码器的3个译码输入引脚收到高3位地址，假设这个高3位地址为 $000$&lt;/li&gt;
&lt;li&gt;之后CPU的存储器请求控制引脚 $MREQ\#$ 输出低电平，3-8译码器的输出使能引脚 $\overline{OE}$ 收到该低电平时，将3位译码输入，译码成8位译码输出,具体为$Y_0$输出有效信号，也就是低电平，而$Y_1$到$Y_7$仍保持输出无效信号，也就是高电瓶。&lt;/li&gt;
&lt;li&gt;这样,8片存储芯片中，只有片选引脚 $\overline{CS}$ 收到有效电瓶的该存储芯片被选中工作，而该存储芯片通过自身18个地址引脚收到的18位地址所对应的存储芯片内部的那个存储单元被选中。&lt;/li&gt;
&lt;li&gt;由于此时该存储芯片的写使能引脚 $\overline{WE}$ 上的信号是之前由CPU的读写控制引脚 $R/W\#$ 输出的高电平，因此该存储芯片将被选中的存储单元中存储的8位数据，通过自己的8位数据总线传送到CPU的8位数据总线。&lt;/li&gt;
&lt;li&gt;由于此时剩余7片存储芯片都未被选中工作,因此他们各自的8位数据总线处于高阻态,不会对CPU的8位数据总线产生影响。&lt;/li&gt;
&lt;li&gt;之后，CPU通过8位数据总线读取8位数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-25_150003.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="写操作-1"&gt;写操作
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;CPU的21条地址总线送出21位的地址，其中各存储芯片都会通过各自的18个地址引脚收到这21位地址的低18位&lt;/li&gt;
&lt;li&gt;而3-8译码器的3个译码输入引脚收到高3位地址，假设这个高3位地址为 $111$&lt;/li&gt;
&lt;li&gt;之后，CPU的读写控制引脚 $R/W\#$ 输出低电平，各存储芯片的写使能引脚 $\overline{WE}$ 收到该低电平。由于各存储芯片此时都未被选中工作，因此不会理会该信号。&lt;/li&gt;
&lt;li&gt;之后,CPU的存储器请求控制隐角 $MREQ\#$ 输出低电频。3-8译码器的输出使能引脚 $\overline{OE}$ 收到该低电平时，将3位译码输入译码成8位译码输出。&lt;/li&gt;
&lt;li&gt;具体为 $Y_7$ 输出有效信号,也就是低电平。而 $Y_0$ 到 $Y_6$ 仍保持输出无效信号，也就是高电频。&lt;/li&gt;
&lt;li&gt;这样，8片存储芯片中，只有片选引脚 $\overline{CS}$ 收到有效电平的该存储芯片被选中工作。而该存储芯片通过自身18个地址引脚收到的18位地址，所对应的存储芯片内部的那个存储单元被选中。&lt;/li&gt;
&lt;li&gt;由于此时该存储芯片的写使能引脚 $\overline{WE}$ 上的信号是之前由CPU的读写控制隐角 $R/W\#$ 输出的低电平。因此，该存储芯片通过自身的8位数据总线，从CPU的8位数据总线获取到8位数据，并写入所选中的存储单元。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-25_152637.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="寻址"&gt;寻址
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-26_170045.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="总结-1"&gt;总结
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;将所有存储芯片的&lt;strong&gt;数据引脚&lt;/strong&gt;、地址引脚、&lt;strong&gt;写使能引脚&lt;/strong&gt; $\overline{WE}$ 各自并联后再分别与CPU的数据引脚、地址引脚、读写控制引脚 $R/W\#$ 连接；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;各存储芯片的片选引脚 $\overline{CS}$ 可以由CPU多余的地址引脚通过&lt;strong&gt;译码器&lt;/strong&gt;产生。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;综上所述，字扩展又称为容量扩展或地址总线扩展。&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;实际的译码器芯片具有更多的&lt;strong&gt;使能引脚&lt;/strong&gt;，以便更灵活地应用。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="453-主存的扩展及其与cpu的连接-字位同时扩展"&gt;4.5.3 主存的扩展及其与CPU的连接 字/位同时扩展
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;当&lt;strong&gt;存储芯片的数据位宽和存储容量均不能满足存储器的数据位宽和存储总容量要求时&lt;/strong&gt;，采用字位同时扩展。
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;首先&lt;/strong&gt;通过&lt;strong&gt;位扩展&lt;/strong&gt;满足数据位宽的要求。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;再&lt;/strong&gt;通过&lt;strong&gt;字扩展&lt;/strong&gt;满足存储总容量的要求。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;【举例】&lt;/strong&gt; CPU的&lt;strong&gt;数据总线位宽&lt;/strong&gt;为32位，地址总线位宽为21位，SRAM存储芯片的&lt;strong&gt;数据总线位宽&lt;/strong&gt;为8位、容量为256K × 8位，采用字位同时扩展将32片这种SRAM存储芯片组成2M × 32位的存储器并与CPU连接。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-26_172214.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-26_172316.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="454-主存的扩展及其与cpu的连接-习题"&gt;4.5.4 主存的扩展及其与CPU的连接 习题
&lt;/h3&gt;&lt;hr&gt;
&lt;h3 id="461-cache-基本概念"&gt;4.6.1 Cache 基本概念
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;主存一般采用容量大、功耗较小、成本较低的同步动态随机存取存储器SDRAM（目前主流为DDR4或DDR5）。&lt;/li&gt;
&lt;li&gt;静态随机存取存储器SRAM的容量小、功耗大、成本高，但SRAM的访问速度远高于SDRAM。&lt;/li&gt;
&lt;li&gt;因此，为了&lt;strong&gt;提升CPU访问主存的性能&lt;/strong&gt;，通常会在CPU与主存之间添加一个SRAM作为高速缓冲存储器cache。
&lt;ul&gt;
&lt;li&gt;将主存中&lt;strong&gt;经常访问&lt;/strong&gt;或&lt;strong&gt;即将访问&lt;/strong&gt;的数据，复制一份**（调度）到cache&lt;strong&gt;中，使得&lt;/strong&gt;大部分数据访问都可以在cache中进行**，从而提升系统性能。&lt;/li&gt;
&lt;li&gt;采用这种方法的主要原因是CPU执行的程序具有较强的&lt;strong&gt;程序局部性&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="程序局部性"&gt;程序局部性
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;程序局部性是指，&lt;strong&gt;在一段时间内，整个程序的执行仅限于一个较小的局部范围内&lt;/strong&gt;。具体来说，程序的局部性又表现为以下两种：
&lt;ul&gt;
&lt;li&gt;时间局部性：若程序在某个时刻访问了&lt;strong&gt;一个存储位置&lt;/strong&gt;，该位置在&lt;strong&gt;未来可能会被多次访问&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;例如程序中的&lt;strong&gt;循环结构&lt;/strong&gt;和调用过程就很好地体现了时间局部性。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;空间局部性：若程序访问了&lt;strong&gt;某个存储位置&lt;/strong&gt;，则&lt;strong&gt;其附近的存储位置也可能被访问&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;例如程序中的&lt;strong&gt;数组、结构体成员、顺序执行的代码块&lt;/strong&gt;，通常在主存中是按顺序存放的，对它们的访问，就是具有较强的空间局部性。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;【2017年 考研题14】某C语言程序段如下：&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;下列关于数组a的访问局部性的描述中，正确的是（A）。&lt;/strong&gt;
A. 时间局部性和空间局部性皆有
B. 无时间局部性，有空间局部性
C. 有时间局部性，无空间局部性
D. 时间局部性和空间局部性皆无&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;ul&gt;
&lt;li&gt;数组a中的各元素在主存中顺序存放，具有空间局部性；&lt;/li&gt;
&lt;li&gt;数组a的读取序列：a[0]、a[0]、a[1]、a[0]、a[1]、a[2]、&amp;hellip;数组a中的同一元素被多次访问，具有时间局部性。&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;h4 id="cache系统的性能评价"&gt;Cache系统的性能评价
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在CPU和主存之间添加了cache后，CPU不再直接访问慢速的主存，而是通过字节地址访问快速的cache&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-26_233123.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;上述情况下，数据访问时间称为&lt;strong&gt;命中访问时间&lt;/strong&gt;，记为 $t_c$ (cache内的查找时间/cache访问时间)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-26_233444.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;上述情况下，数据访问时间称为&lt;strong&gt;缺失补偿&lt;/strong&gt;，记为 $t_m$ (cache内的查找时间/主存访问时间/cache访问时间)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;为了便于快速查找，主存和cache都被划分成若干个固定大小的&lt;strong&gt;数据块（Block）&lt;/strong&gt;，&lt;strong&gt;每个数据块又包含若干个字。&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;若进行数据访问时出现数据缺失的情况，则需要将缺失数据所在的数据块从慢速主存载入cache中。&lt;/li&gt;
&lt;li&gt;因此，缺失数据相邻的数据也会随着数据块一起载入cache。&lt;/li&gt;
&lt;li&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-26_233838.png" alt="" loading="lazy" /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;上述&lt;strong&gt;预读策略&lt;/strong&gt;可以充分利用程序的&lt;strong&gt;空间局部性&lt;/strong&gt;，提高顺序访问的&lt;strong&gt;命中率&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;然而，&lt;strong&gt;数据块的大小&lt;/strong&gt;对cache有较大影响：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据块过小：无法利用预读策略优化程序的空间局部性。&lt;/li&gt;
&lt;li&gt;数据块过大：将使得替换算法无法充分利用程序的时间局部性。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-26_234002.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;进行数据分块后，需要给主存内的数据块和cache内的数据块分配地址。
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;数据块的地址&lt;/strong&gt;由&lt;strong&gt;块地址&lt;/strong&gt;和&lt;strong&gt;块内偏移地址&lt;/strong&gt;（简称块内偏移Offset）两部分构成。&lt;/li&gt;
&lt;li&gt;由于cache容量比主存容量小很多，因此cache内的块地址长度小于主存内的块地址长度。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="性能评价指标"&gt;性能评价指标
&lt;/h5&gt;&lt;p&gt;某程序运行期间命中cache的次数记为 $n_c$ ，从主存中访问信息的次数记为 $n_m$ ，命中率(Hit Ratio)记为 $h$ :&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;$h$ 越接近于1 性能越好&lt;/p&gt;

 &lt;/blockquote&gt;
$$
h=\frac{n_c}{n_c+n_m}
$$&lt;p&gt;$1-h$ 称为缺失率(Miss Ratio)。命中情况下的访问时间记为 $t_c$ ，数据确实情况下的访问时间记为 $t_m$ ，&lt;/p&gt;
&lt;p&gt;cache/主存系统的平均访问时间记为 $t_a$ :&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;$h$ 越接近于1， $t_a$ 越接近 $t_c$&lt;/p&gt;

 &lt;/blockquote&gt;
$$
t_a=ht_c+(1-h)t_m
$$&lt;p&gt;访问效率记为 $e$ :&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;$h$ 越接近于1， $e$ 越接近1&lt;/p&gt;
&lt;p&gt;$r$ 一般为5~10，不能太大&lt;/p&gt;

 &lt;/blockquote&gt;
$$
e=\frac{t_c}{t_a}=\frac{t_c}{ht_c+(1-h)t_m}=\frac{1}{h+(1-h)\frac{t_m}{t_c}}=\frac{1}{h+(1-h)r}
$$&lt;hr&gt;
&lt;h3 id="462-cache-读写流程"&gt;4.6.2 Cache 读、写流程
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-27_104052.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="读操作-2"&gt;读操作
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-27_104341.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;若是数据命中，则访问时间较快，数据缺失则访问时间较慢&lt;/li&gt;
&lt;li&gt;构建cache系统时，应尽可能&lt;strong&gt;提高命中率&lt;/strong&gt;，以提升读操作性能。
&lt;ul&gt;
&lt;li&gt;通过较好的&lt;strong&gt;替换策略&lt;/strong&gt;，将经常访问的&lt;strong&gt;热数据保留&lt;/strong&gt;在cache中，将不经常访问的&lt;strong&gt;冷数据淘汰&lt;/strong&gt;，来充分&lt;strong&gt;利用时间局部性&lt;/strong&gt;，以提高命中率。&lt;/li&gt;
&lt;li&gt;数据缺失时，会将缺失数据所在数据块中的其他数据一起载入，这种&lt;strong&gt;预读策略&lt;/strong&gt;可以充分&lt;strong&gt;利用空间局部性&lt;/strong&gt;来提高&lt;strong&gt;顺序访问&lt;/strong&gt;的命中率。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="写操作-2"&gt;写操作
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-27_105548.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;写回(Write-back)策略 此时写入操作结束，这种方式&lt;strong&gt;响应速度最快&lt;/strong&gt;，但会产生&lt;strong&gt;不一致性&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-27_105832.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;写穿(Write-through)策略 此时还需要将脏数据写入慢速的主存中才能结束，这种方式&lt;strong&gt;响应速度较慢&lt;/strong&gt;，但&lt;strong&gt;没有脏数据产生&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-27_110853.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;非写分配策略 此时将数据写入慢速主存即可返回。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-27_111341.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;写分配(Write-Allocate)策略&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-27_111608.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;采用&lt;strong&gt;写回策略&lt;/strong&gt;时，将数据写入cache即可返回，写响应时间最短。
&lt;ul&gt;
&lt;li&gt;对于&lt;strong&gt;突发的小数据量写入&lt;/strong&gt;，cache能明显提高写入性能。&lt;/li&gt;
&lt;li&gt;然而，由于cache容量很小，当&lt;strong&gt;cache写满数据后&lt;/strong&gt;，需要将cache中的脏数据淘汰，这就需要先将脏数据迁移到主存中，然后从主存载入新数据块到cache后才能向cache写入新数据，该过程的&lt;strong&gt;写性能比没有采用cache的主存还要慢&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="463-cache-映射"&gt;4.6.3 Cache 映射
&lt;/h3&gt;&lt;p&gt;本节内容整理自B站up主&amp;quot;小狗走两步&amp;quot;的视频&lt;a class="link" href="https://www.bilibili.com/video/BV1N8411y7UF?spm_id_from=333.788.videopod.sections&amp;amp;vd_source=c8beb52bf015e61e5378008c684545a4" target="_blank" rel="noopener"
 &gt;帮你把Cache映射梳理清楚! | 图解cache映射_哔哩哔哩_bilibili&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;每串数据都有相应的一个地址，也就是根据某个地址，可以在主存中找到相应位置的数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;地址的长度，需通过计算机的&lt;strong&gt;编址方式&lt;/strong&gt;得到。比如是&amp;quot;按字节编址&amp;rdquo;，数据就每8bit便分配一个地址(64位架构下)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;或者再通过存储器的容量，来知道地址的个数。比如容量为4MB的主存， $4MB = 4 \times1024KB = 4\times1024\times1024B=2^{22}B$ 按2B编址则为 $2^{21}$ 个地址&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="映射地址结构"&gt;映射地址结构
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-28_195451.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;cache与主存间的映射，是基于两边&lt;strong&gt;块号&lt;/strong&gt;的对应，而并非每个单独地址的对应&lt;/li&gt;
&lt;li&gt;在cache内部，1个cache行其实是一个&lt;strong&gt;块&lt;/strong&gt;，里面有多个地址，主存中的数据也是同样道理，而其中地址的排序是一定的，若已知某个地址在主存中某一行的第几个，就能知道cache里对应的行里该地址的位置&lt;/li&gt;
&lt;li&gt;主存中的物理地址是以 &lt;strong&gt;0x 块号|块内地址&lt;/strong&gt; 的形式存储，低位是块内地址，高位是块号&lt;/li&gt;
&lt;li&gt;分块的过程可理解为&lt;strong&gt;取模&lt;/strong&gt;的过程，例如某主存每一个块能容纳32个地址，每个地址64位，则先用某地址的数对32取模，&lt;strong&gt;余数放在低位&lt;/strong&gt;即块内地址，&lt;strong&gt;商放在高位&lt;/strong&gt;即块号。 $32=2^5$ 因此需要5bit来表示块内地址，剩下的59bit可用来表示&lt;strong&gt;块号&lt;/strong&gt;，即整个主存可分为 $2^{59}$ 个cache块&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="映射方式"&gt;映射方式
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-28_203126.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h5 id="全相联映射"&gt;全相联映射
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;在cache中随机选取任一空的位置存储主存中的块&lt;/li&gt;
&lt;li&gt;用&lt;strong&gt;块号&lt;/strong&gt;作为cache块的标记(tag)，用于对比和找出到底是主存的哪一块在这里，所以每次查找就需要&lt;strong&gt;遍历整个cache&lt;/strong&gt;，时间开销较大&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="直接映射"&gt;直接映射
&lt;/h5&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-28_200458.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;先确定cache的容量和主存的容量，即有多少个块，用主存的块号来对cache的容量块数&lt;strong&gt;取模&lt;/strong&gt;，和上面分块的过程类似&lt;/li&gt;
&lt;li&gt;例如上图的例子，&lt;strong&gt;块号&lt;/strong&gt;的&lt;strong&gt;低位&lt;/strong&gt;(低3位)&lt;strong&gt;表示在cache中的块号&lt;/strong&gt;，&lt;strong&gt;高位&lt;/strong&gt;(高2位)确认该cache块是否为所对应需要的主存中的地址&lt;/li&gt;
&lt;li&gt;每个cache块的内容会&lt;strong&gt;不断的替换&lt;/strong&gt;，如上图cache的第0块，需要不断的在主存第0块、第8块、第16块间替换，空间的利用不足&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="组相联映射"&gt;组相联映射
&lt;/h5&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-28_202346.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;全相联映射和直接映射的结合，&lt;strong&gt;对cache进行分组&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;在&lt;strong&gt;总体上采用直接映射&lt;/strong&gt;的方式，用取模后的低位数来分配具体的组号&lt;/li&gt;
&lt;li&gt;在每个&lt;strong&gt;组内采用全相联映射&lt;/strong&gt;的方法，即组内是随机挑选空位的，查找时只需要在组中遍历&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="464-cache-习题课"&gt;4.6.4 Cache 习题课
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-29_120927.png" alt="" loading="lazy" /&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;首先明确题目目标是要求出tag之后的块号+块内地址的部分&lt;/p&gt;
&lt;p&gt;通过选项可以看出块号+块内地址的大小为14bit(14位)&lt;/p&gt;
&lt;p&gt;再已知cache的容量得出的cache块数量为 $1024=2^{10}$ 个，块号部分大小为10位，则块内地址为 $14-10=4$ 位&lt;/p&gt;
&lt;p&gt;最后将十六进制的主存地址转化为二进制，取最后的14位 $10100011111000$&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-29_123831.png" alt="" loading="lazy" /&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&amp;ldquo;地址映射表&amp;quot;即cache的“标记阵列”，也就是所有标记部分的总和，也就明确了本题先要求出标记位的长度&lt;/p&gt;
&lt;p&gt;cache标记位简单地讲由有效位+脏位+tag组成，其中有效位占1bit，脏位通过观察题目中是否由“回写”判断，那本题没有，接下来的目标就是求出tag部分的长度&lt;/p&gt;
&lt;p&gt;cache有 $64=2^6$ 个块，cache块号部分就长6bit，主存容量为 $64 \times 4096=2^{18}$ 个块，则主存块号长18bit，tag部分就长 $18-6=12$ bit，再加上有效位的1bit长&lt;/p&gt;
&lt;p&gt;最终就是 $64 \times 13$ bit&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-29_134928.png" alt="" loading="lazy" /&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;先得出每个块占用的空间为 $32bit \times 8 = 32B$&lt;/p&gt;
&lt;p&gt;cache容量除以每个cache块的空间得出cache块数量 $16KB \div 32B = 2^9$&lt;/p&gt;
&lt;p&gt;同理，主存中块数量为 $1MB \div 32B = 2^{15}$&lt;/p&gt;
&lt;p&gt;综上得出主存块号15位，cache块号9位，接下来将题目中给出的主存地址转为二进制并取前15位的后九位，即在 $001101010011000$ 中取 $10011000=152$&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-29_141921.png" alt="" loading="lazy" /&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;本题为“组相联映射”，基本思路和前面差不多，但地址的组成有变化，组相联需要在知道块数的情况下得出组数，本题 $2^{13}块 \div 2^3路 = 2^{10}组$ 也就知道了组号为10bit长，块内地址由“每块16B”可知，长4bit&lt;/p&gt;
&lt;p&gt;地址的位数由题目的 $1234567H$ 可以看出有7位十六进制数，即28位二进制数，地址也就长28位&lt;/p&gt;
&lt;p&gt;tag的长度应为 $28-10-4 = 14$ 则取二进制的 $1234567$ 的前14位即可&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-29_161108.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-29_163912.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-29_170223.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="511-指令格式"&gt;5.1.1 指令格式
&lt;/h3&gt;&lt;p&gt;本节内容整理自B站up主&amp;quot;王道计算机教育&amp;quot;的视频&lt;a class="link" href="https://www.bilibili.com/video/BV1ps4y1d73V?spm_id_from=333.788.videopod.sections&amp;amp;vd_source=c8beb52bf015e61e5378008c684545a4&amp;amp;p=45" target="_blank" rel="noopener"
 &gt;4.1.1+2+3_指令的基本格式_哔哩哔哩_bilibili&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-29_221708.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;指令是指示计算机执行某种操作的命令，是计算机运行的最小功能单位。一台计算机的所有指令的集合构成该机的&lt;strong&gt;指令系统&lt;/strong&gt;，也称为&lt;strong&gt;指令集&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-29_223757.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="按操作数地址码分类"&gt;按操作数(地址码)分类
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;指令由&lt;strong&gt;操作码和地址码&lt;/strong&gt;组成，一条指令包含的地址码数量不同。
&lt;ul&gt;
&lt;li&gt;零地址指令
&lt;ul&gt;
&lt;li&gt;不需要操作数，比如空操作、停机、关中断等。或者堆栈计算机，操作数隐含存放。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;一地址指令
&lt;ul&gt;
&lt;li&gt;如只需要单操作数 $OP(A_1) \rightarrow A_1$ 完成一次需要三次访存：取指-&amp;gt;读$A_1$-&amp;gt;写$A_1$&lt;/li&gt;
&lt;li&gt;或需要两个操作数的，但其中一个操作数隐含在某个寄存器 $(ACC)OP(A_1) \rightarrow ACC$ 完成一次需要两次访存：取指-&amp;gt;读$A_1$&lt;/li&gt;
&lt;li&gt;$A_1$指某个主存地址，($A_1$)表示 $A_1$ 所指向的地址中的内容。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;二地址指令
&lt;ul&gt;
&lt;li&gt;常用于需要两个操作数的算术运算、逻辑运算相关指令 $(A_1)OP(A_2) \rightarrow A_1$&lt;/li&gt;
&lt;li&gt;完成一次需要访存4次，取指-&amp;gt;读$A_1$-&amp;gt;读$A_2$-&amp;gt;写$A_1$&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;三地址指令
&lt;ul&gt;
&lt;li&gt;常用于需要两个操作数的算术运算、逻辑运算相关指令 $(A_1)OP(A_2) \rightarrow A_3$&lt;/li&gt;
&lt;li&gt;完成一次需要访存4次，取指-&amp;gt;读$A_1$-&amp;gt;读$A_2$-&amp;gt;写$A_3$&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;四地址指令
&lt;ul&gt;
&lt;li&gt;完成一次需要访存4次，取指-&amp;gt;读$A_1$-&amp;gt;读$A_2$-&amp;gt;写$A_3$&lt;/li&gt;
&lt;li&gt;但与正常情况下，取指令后PC+1指向下一条指令不同，而是在执行指令后，将PC的值修改为$A_4$所指的地址&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="按指令长度分类"&gt;按指令长度分类
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;指令字长：一条指令的总长度（&lt;strong&gt;可能会变&lt;/strong&gt;）&lt;/li&gt;
&lt;li&gt;机器字长：CPU进行一次整数运算所能处理的二进制数据的位数（通常和ALU直接相关）&lt;/li&gt;
&lt;li&gt;存储字长：一个存储单元中的二进制代码位数（通常和MDR位数相同）&lt;/li&gt;
&lt;li&gt;半字长指令、单字长指令、双字长指令——&lt;strong&gt;指令长度是机器字长的多少倍&lt;/strong&gt;，指令字长会影响取指令所需时间。如：机器字长=存储字长=16bit，则取一条双字长指令需要两次访存&lt;/li&gt;
&lt;li&gt;定长指令字结构：指令系统中所有指令的长度都相等&lt;/li&gt;
&lt;li&gt;变长指令字结构：指令系统中各种指令的长度不等&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="按操作码长度分类"&gt;按操作码长度分类
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;定长操作码：指令系统中所有指令的操作码长度都相同
&lt;ul&gt;
&lt;li&gt;n位 -&amp;gt; $2^n$ 条指令&lt;/li&gt;
&lt;li&gt;控制器的译码电路设计简单，但灵活性较低&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;可变长操作码：指令系统中各指令的&lt;strong&gt;操作码长度可变&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;控制器的译码电路设计复杂，但灵活性较高&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;定长指令字结构+可变长操作码 -&amp;gt; 扩展操作码指令格式&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="按操作类型分类"&gt;按操作类型分类
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;数据传送&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;进行&lt;strong&gt;主存与CPU间的数据传送&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LOAD 作用：把存储器中的数据放到寄存器中&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;STORE 作用：把寄存器中的数据放到存储器中&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;算术逻辑操作&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;算术：加、减、乘、除、增1、减1、求补、浮点运算、十进制运算&lt;/li&gt;
&lt;li&gt;逻辑：与、或、非、异或、位操作、位测试、位清除、位求反&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;移位操作&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;算术移位、逻辑移位、循环移位（带进位和不带进位）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;转移操作&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;改变程序执行的顺序&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;无条件转移 JMP&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;条件转移 JZ：结果为0；JO：结果溢出；JC：结果有进位&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;调用和返回 CALL和RETURN&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;陷阱(Trap)与陷阱指令&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;输入输出操作&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;进行&lt;strong&gt;CPU与I/O设备之间的数据传送&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="512-扩展操作码指令格式"&gt;5.1.2 扩展操作码指令格式
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;定长指令字结构+可变长操作码-&amp;gt;扩展操作码指令格式&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不同地址数的指令使用不同长度的操作码&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在设计扩展操作码指令格式时，必须注意以下两点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;不允许短码是长码的前缀&lt;/strong&gt;，即短操作码不能与长操作码的前面部分的代码相同。&lt;/li&gt;
&lt;li&gt;各指令的操作码一定&lt;strong&gt;不能重复&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通常情况下，对使用频率较高的指令，分配较短的操作码；对使用频率较低的指令，分配较长的操作码，从而尽可能减少指令译码和分析的时间。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="扩展操作码举例"&gt;扩展操作码举例
&lt;/h4&gt;&lt;p&gt;指令字长为16位，每个地址码占4位：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-30_162147.png" alt="" loading="lazy" /&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;ul&gt;
&lt;li&gt;前4位为基本操作码字段OP，另有3个4位长的地址字段 $A_1 A_2 A_3$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;4位基本操作码若全部用于三地址指令，则有16条。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;但至少须将1111留作扩展操作码之用，即三地址指令为15条；&lt;/li&gt;
&lt;li&gt;1111 1111留作扩展操作码之用，二地址指令为15条；&lt;/li&gt;
&lt;li&gt;1111 1111 1111留作扩展操作码之用，一地址指令为15条；&lt;/li&gt;
&lt;li&gt;零地址指令为16条。&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;p&gt;再举例，设指令字长固定为16位，试设计一套指令系统满足：有15条三地址指令，有12条二地址指令，有62条一地址指令，有32条零地址指令&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-30_180001.png" alt="" loading="lazy" /&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;ul&gt;
&lt;li&gt;
&lt;p&gt;15条三地址指令，需最前面的四位是从0000~1110共15条，同上例，下个数就为1111&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;到12条二地址指令，前四位为1111，再四位是从0000~1011共12条，下个数为1100&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;由于二地址的设计，前六位为111111留作扩展操作码之用，62条一地址指令需用12位操作码的后六位来表示0&lt;del&gt;61即000000&lt;/del&gt;111101，下个数为111110&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;由于一地址的设计，前十一位为11111111111留作扩展操作码之用，32条零地址指令正好用剩余的五位来表示（零地址指令无需地址码）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;设地址长度为n，上一层留出m种状态，下一层可扩展出 $m \times 2^n$ 种状态&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="定长与不定长操作码的对比"&gt;定长与不定长操作码的对比
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;扩展操作码（不定长操作码）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;全部指令的操作码字段位数不固定，且分散地放在指令字的不同位置上。
&lt;ul&gt;
&lt;li&gt;最常见的变长操作码方法是扩展操作码，使&lt;strong&gt;操作码的长度随地址码的减少而增加&lt;/strong&gt;，不同地址数的指令可以具有不同长度的操作码，从而在满足需要的前提下，有效地缩短指令字长。&lt;/li&gt;
&lt;li&gt;优点：在指令字长有限的前提下仍保持比较&lt;strong&gt;丰富的指令种类&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;缺点：增加了指令译码和分析的难度，使控制器的设计复杂化。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;定长操作码&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在指令字的最高位部分分配固定的若干位（定长）表示操作码。
&lt;ul&gt;
&lt;li&gt;一般n位操作码字段的指令系统最大能够表示 $2^n$ 条指令。&lt;/li&gt;
&lt;li&gt;优点：定长操作码对于简化计算机硬件设计，&lt;strong&gt;提高&lt;/strong&gt;指令译码和识别&lt;strong&gt;速度&lt;/strong&gt;很有利。&lt;/li&gt;
&lt;li&gt;缺点：指令数量增加时会占用更多固定位，留给表示操作数地址的&lt;strong&gt;位数受限&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="521-指令寻址"&gt;5.2.1 指令寻址
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-30_205920.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="顺序寻址"&gt;顺序寻址
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-30_203057.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“主存按字节编址”说明&lt;strong&gt;每一条指令占两个地址&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-30_203827.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“变长指令结构”下，各种指令占用的大小不同，PC的值根据读取命令的字长变化而非固定的变化，同时CPU读取一条指令可能要多次访存&lt;/li&gt;
&lt;li&gt;$(PC)+"1" \rightarrow PC$ 这里的&amp;quot;1&amp;quot;理解为&lt;strong&gt;1个指令字长&lt;/strong&gt;，实际加的值会因指令长度、编址方式而不同&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="跳跃寻址"&gt;跳跃寻址
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-08-30_204700.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;与顺序寻址不同，由&lt;strong&gt;转移指令&lt;/strong&gt;，将PC的值直接进行修改而非顺序执行，便是跳跃寻址。以某个地址作为起点，形式地址视为“偏移量”。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="522-偏移寻址"&gt;5.2.2 偏移寻址
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;基址寻址：以程序的&lt;strong&gt;起始存放地址&lt;/strong&gt;作为“起点”&lt;/li&gt;
&lt;li&gt;变址寻址：程序员自己决定从哪里作为“起点”&lt;/li&gt;
&lt;li&gt;相对寻址：以&lt;strong&gt;程序计数器PC&lt;/strong&gt;所指地址作为“起点”&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="基址寻址"&gt;基址寻址
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;将CPU中&lt;strong&gt;基址寄存器&lt;/strong&gt;（BR base address register）的内容加上指令格式中的形式地址A，而形成操作数的有效地址，即 $EA = (BR) + A$&lt;/li&gt;
&lt;li&gt;但CPU中不一定有专用的基址寄存器，而都是通用寄存器，这时就需要在指令中指明哪个通用寄存器作为基址寄存器使用，要根据通用寄存器总数来判断要用几个bit来指明寄存器。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-01_200023.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如图，BR的地址为&lt;strong&gt;程序开始存放的地址，即第一条指令的地址&lt;/strong&gt;，&amp;ldquo;取数a至ACC&amp;rdquo;&lt;/li&gt;
&lt;li&gt;地址码101即访问地址为5的数据a，但这里都是&lt;strong&gt;相对地址&lt;/strong&gt;而非绝对地址&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-01_200714.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基址寄存器是&lt;strong&gt;面向操作系统&lt;/strong&gt;的，其&lt;strong&gt;内容由操作系统或管理程序确定&lt;/strong&gt;。在程序执行过程中，基址寄存器的内容不变（作为基地址），形式地址可变（作为偏移量）。&lt;/li&gt;
&lt;li&gt;当采用通用寄存器作为基址寄存器时，可由用户决定哪个寄存器作为基址寄存器，但其&lt;strong&gt;内容仍由操作系统确定&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;优点：可&lt;strong&gt;扩大寻址范围&lt;/strong&gt;（基址寄存器的位数大于形式地址A的位数）；用户不必考虑自己的程序存于主存的哪一空间区域，故&lt;strong&gt;有利于多道程序设计&lt;/strong&gt;，以及可用于&lt;strong&gt;编制浮动程序&lt;/strong&gt;（整个程序在内存里边的浮动）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="变址寻址"&gt;变址寻址
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;有效地址EA等于指令字中的形式地址A与&lt;strong&gt;变址寄存器&lt;/strong&gt;（IX index register）的内容相加之和，即$EA = (IX) + A$ ，其中IX可为变址寄存器（专用），也可用通用寄存器作为变址寄存器。&lt;/li&gt;
&lt;li&gt;变址寄存器是&lt;strong&gt;面向用户&lt;/strong&gt;的，在程序执行过程中，&lt;strong&gt;变址寄存器的内容可由用户改变&lt;/strong&gt;（IX作为偏移量），&lt;strong&gt;形式地址A不变&lt;/strong&gt;（作为基地址）。&lt;/li&gt;
&lt;li&gt;如图中的循环累加案例，我们把数组起始的地址作为形式地址，IX看作偏移量，在地址3,4,5的指令，由用户对IX进行操作和比较，从而实现了数组的循环累加，直到IX的值达到数组的最大容量&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-02_133114.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;优点：在数组处理过程中，可设定A为数组的首地址，不断改变变址寄存器IX的内容，便可很容易形成数组中任一数据的地址，特别&lt;strong&gt;适合编制循环程序&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="基址变址复合寻址"&gt;基址变址复合寻址
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-02_134000.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="相对寻址"&gt;相对寻址
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;把&lt;strong&gt;程序计数器PC&lt;/strong&gt;的内容加上指令格式中的形式地址A而形成操作数的有效地址，即 $EA=(PC)+A$ ，其中A是相对于PC所指地址的位移量，&lt;strong&gt;可正可负&lt;/strong&gt;，&lt;strong&gt;补码表示&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;且注意相对寻址是相对于&lt;strong&gt;下一条指令&lt;/strong&gt;的偏移&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-02_134452.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如图中的和之前一样的案例，若是我们将这块循环代码的位置进行变换，则之前用了&lt;strong&gt;直接寻址&lt;/strong&gt;的“条件跳转”指令就会失效，而应该改为&lt;strong&gt;相对寻址&lt;/strong&gt;的方式，同时注意要偏移 $-4$ 因为PC自动 $+1$ 的现象&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-02_135101.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;优点：操作数的地址不是固定的，它随着PC值的变化而变化，并且与指令地址之间总是相差一个固定值，因此便于&lt;strong&gt;程序浮动&lt;/strong&gt;（一段代码在程序内部的浮动）。相对寻址广泛应用于&lt;strong&gt;转移指令&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="硬件如何实现数的比较"&gt;硬件如何实现数的比较
&lt;/h4&gt;&lt;p&gt;在上述各例中的&amp;quot;IX比较&amp;quot;和&amp;quot;条件跳转&amp;quot;指令，都对值进行了比较&lt;/p&gt;
&lt;p&gt;硬件视角：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过“cmp指令”比较a和b（如cmp a，b），实质上是用&lt;strong&gt;a-b相减的结果信息&lt;/strong&gt;会记录在&lt;strong&gt;程序状态字寄存器&lt;/strong&gt;中(PSW)&lt;/li&gt;
&lt;li&gt;根据PSW的某几个标志位进行条件判断，来决定是否转移&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PSW中有几个比特位记录上次运算的结果&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;位/借位标志CF：最高位有进位/借位时CF=1&lt;/li&gt;
&lt;li&gt;零标志ZF：运算结果为0则ZF=1，否则ZF=0&lt;/li&gt;
&lt;li&gt;符号标志SF：运算结果为负，SF=1，否则为0&lt;/li&gt;
&lt;li&gt;溢出标志OF：运算结果有溢出OF=1否则为0&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="523-堆栈寻址"&gt;5.2.3 堆栈寻址
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;操作数存放在堆栈中，隐含使用堆栈指针（SP）作为操作数地址。&lt;/li&gt;
&lt;li&gt;堆栈是存储器（或专用寄存器组）中一块特定的按“后进先出（LIFO）”原则管理的存储区，该存储区中被读/写单元的地址是用一个特定的寄存器给出的，该寄存器称为&lt;strong&gt;堆栈指针&lt;/strong&gt;（SP）。&lt;/li&gt;
&lt;li&gt;数据执行出栈或是入栈指令，都要注意SP的变化&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="硬堆栈"&gt;硬堆栈
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;使用专门的寄存器来作为堆栈，指令执行期间不需访存，运行速度块，成本高&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-02_141620.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="软堆栈"&gt;软堆栈
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;用主存中的一块空间作为堆栈。访存次数多，运行速度慢，成本低，也是普遍的堆栈方式&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="总结-2"&gt;总结
&lt;/h4&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;寻址方式&lt;/th&gt;
					&lt;th&gt;有效地址&lt;/th&gt;
					&lt;th&gt;访存次数(指令执行期间)&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;隐含寻址&lt;/td&gt;
					&lt;td&gt;程序指定&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;立即寻址&lt;/td&gt;
					&lt;td&gt;A即是操作数&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;直接寻址&lt;/td&gt;
					&lt;td&gt;$EA=A$&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;一次间接寻址&lt;/td&gt;
					&lt;td&gt;$EA=(A)$&lt;/td&gt;
					&lt;td&gt;2&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;寄存器寻址&lt;/td&gt;
					&lt;td&gt;$EA=R_i$&lt;/td&gt;
					&lt;td&gt;0&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;寄存器间接一次寻址&lt;/td&gt;
					&lt;td&gt;$EA=(R_i)$&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;相对寻址(转移指令)&lt;/td&gt;
					&lt;td&gt;$EA=(PC)+A$&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;基址寻址(多道程序)&lt;/td&gt;
					&lt;td&gt;$EA=(BR)+A$&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;变址寻址(循环程序)&lt;/td&gt;
					&lt;td&gt;$EA=(IX)+A$&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;堆栈寻址&lt;/td&gt;
					&lt;td&gt;入栈/出栈时EA的确定方式不同&lt;/td&gt;
					&lt;td&gt;硬堆栈不访存，软堆栈访存1次&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="53-cisc和risc"&gt;5.3 CISC和RISC
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;CISC: Complex Instruction Set Computer&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;一条指令完成一个复杂的基本功能，一条指令可以由一个专门的电路完成&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;代表: x86架构&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;RISC: Reduced Instruction Set Computer&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一条指令完成一个基本动作，多条指令组合完成一个复杂的基本功能&lt;/li&gt;
&lt;li&gt;代表: ARM架构&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;对比项目\类别&lt;/th&gt;
					&lt;th&gt;CISC&lt;/th&gt;
					&lt;th&gt;RISC&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;指令系统&lt;/td&gt;
					&lt;td&gt;复杂，庞大&lt;/td&gt;
					&lt;td&gt;简单，精简&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;指令数目&lt;/td&gt;
					&lt;td&gt;一般大于200条&lt;/td&gt;
					&lt;td&gt;一般小于100条&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;指令字长&lt;/td&gt;
					&lt;td&gt;不固定&lt;/td&gt;
					&lt;td&gt;定长&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;可访存指令&lt;/td&gt;
					&lt;td&gt;不加限制&lt;/td&gt;
					&lt;td&gt;只有Load/Store指令&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;各种指令执行时间&lt;/td&gt;
					&lt;td&gt;相差较大&lt;/td&gt;
					&lt;td&gt;绝大多数在一个周期内完成&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;各种指令使用频度&lt;/td&gt;
					&lt;td&gt;相差很大&lt;/td&gt;
					&lt;td&gt;都比较常用&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;通用寄存器数量&lt;/td&gt;
					&lt;td&gt;较少&lt;/td&gt;
					&lt;td&gt;多&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;目标代码&lt;/td&gt;
					&lt;td&gt;难以用优化编译生成高效的目标代码程序&lt;/td&gt;
					&lt;td&gt;采用优化的编译程序，生成代码较为高效&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;控制方式&lt;/td&gt;
					&lt;td&gt;绝大多数为微程序控制&lt;/td&gt;
					&lt;td&gt;绝大多数为组合逻辑控制&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;指令流水线&lt;/td&gt;
					&lt;td&gt;可以通过一定方式实现&lt;/td&gt;
					&lt;td&gt;必须实现&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="61-cpu的功能和结构"&gt;6.1 CPU的功能和结构
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-03_111914.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="cpu的功能"&gt;CPU的功能
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;指令控制&lt;/strong&gt;：完成取指令、分析指令和执行指令的操作，即程序的&lt;strong&gt;顺序控制&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;操作控制&lt;/strong&gt;：一条指令的功能往往是由若干&lt;strong&gt;操作信号&lt;/strong&gt;的组合来实现的。CPU管理并产生由内存取出的每条指令的操作信号，把各种操作信号送往相应的部件，从而控制这些部件按指令的要求进行动作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;时间控制&lt;/strong&gt;：对各种操作加以时间上的控制。时间控制要为每条指令按时间顺序提供应有的控制信号。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据加工&lt;/strong&gt;：对数据进行算术和逻辑运算。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;中断处理&lt;/strong&gt;：对计算机运行过程中出现的&lt;strong&gt;异常情况和特殊请求&lt;/strong&gt;进行处理。&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="运算器和控制器的功能"&gt;运算器和控制器的功能
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;运算器：对数据进行加工。&lt;/li&gt;
&lt;li&gt;控制器：协调并控制计算机各部件执行程序的指令序列，基本功能包括&lt;strong&gt;取指令、分析指令、执行指令&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;取指令&lt;/strong&gt;：自动形成指令地址，自动发出取指令的命令。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分析指令&lt;/strong&gt;：操作码译码（分析本条指令要完成什么操作）产生操作数的有效地址。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;执行指令&lt;/strong&gt;：根据分析指令得到的“操作命令”和“操作数地址”，形成操作信号控制序列，控制运算器、存储器以及I/O设备完成相应的操作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;中断处理&lt;/strong&gt;：管理总线及输入输出，处理异常情况（如掉电）和特殊请求（如打印机请求打印一行字符）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="运算器的基本结构"&gt;运算器的基本结构
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;算术逻辑单元（ALU）&lt;/strong&gt;：主要功能是进行算术/逻辑运算。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;通用寄存器组&lt;/strong&gt;：如AX、BX、CX、DX、SP等（在x86架构下，AH表示A寄存器高位，AL表示A寄存器低位），用于存放操作数（包括源操作数、目的操作数及中间结果）和各种地址信息等。&lt;strong&gt;SP是堆栈指针&lt;/strong&gt;，用于指示栈顶的地址。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;寄存器和ALU有多种连接方式，最直接的就是&lt;strong&gt;专用数据通路方式&lt;/strong&gt;，根据指令执行过程中的数据和地址的流动方向安排连接线路。但是直接用导线连接，&lt;strong&gt;相当于多个寄存器同时并且一直向ALU传输数据&lt;/strong&gt;，但ALU应只能同时处理一对操作数，因此&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;解决方法1：使用&lt;strong&gt;多路选择器&lt;/strong&gt;根据控制信号选择一路输出
&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-03_105320.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;解决方法2：使用&lt;strong&gt;三态门&lt;/strong&gt;可以控制每一路是否输出。比如，$R0_{out}$为1时$R_0$中的数据输出到A端，
$R0_{out}$为0时$R_0$中的数据无法输出到B端
&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-03_105825.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;专用数据通路方式&lt;strong&gt;性能较高，基本不存在数据冲突现象，但结构复杂，硬件量大，不易实现&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;另一种连接方式，即&lt;strong&gt;CPU内部单总线方式&lt;/strong&gt;，首先引入一些新的部件&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;暂存寄存器&lt;/strong&gt;：用于暂存从&lt;strong&gt;主存&lt;/strong&gt;读来的数据，这个数据&lt;strong&gt;不能存放在通用寄存器&lt;/strong&gt;中，否则会破坏其原有内容。&lt;/li&gt;
&lt;li&gt;累加寄存器（ACC）：它是一个通用寄存器，用于暂时存放ALU运算的结果信息，用于实现加法运算。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;程序状态字寄存器（PSW）&lt;/strong&gt;：保留由算术逻辑运算指令或测试指令的结果而建立的&lt;strong&gt;各种状态信息&lt;/strong&gt;，如溢出标志（OP）、符号标志（SF）、零标志（ZF）、进位标志（CP）等。PSW中的这些位参与并决定&lt;strong&gt;微操作&lt;/strong&gt;的形成。&lt;/li&gt;
&lt;li&gt;移位器：对运算结果进行移位运算。&lt;/li&gt;
&lt;li&gt;计数器：控制乘除运算的操作步数。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ALU会通过总线传输运算结果，寄存器也会通过总线向ALU传输操作数，则易发生&lt;strong&gt;数据冲突&lt;/strong&gt;，需要在ALU的输出端加入&lt;strong&gt;暂存寄存器&lt;/strong&gt;和三态门来解决。如，两个操作数分别来自主存和$R_0$，最后结果存回$R_0$，那么从主存中取来的操作数直接放入暂存器，就不会破坏运算前$R_0$的内容。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-03_104710.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CPU内部单总线方式，&lt;strong&gt;结构简单，容易实现，但数据传输存在较多冲突的现象，性能较低&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="控制器的基本结构"&gt;控制器的基本结构
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;程序计数器：用于指出下一条指令在主存中的存放地址。CPU就是根据PC的内容去主存中取指令的。因程序中指令（通常）是顺序执行的，所以PC有自增功能。&lt;/li&gt;
&lt;li&gt;指令寄存器：用于保存当前正在执行的那条指令。&lt;/li&gt;
&lt;li&gt;指令译码器：仅对操作码字段进行译码，向控制器提供特定的操作信号。&lt;/li&gt;
&lt;li&gt;微操作信号发生器：根据IR的内容（指令）、PSW的内容（状态信息）及时序信号，产生控制整个计算机系统所需的各种控制信号，其结构有组合逻辑型和存储逻辑型两种。&lt;/li&gt;
&lt;li&gt;时序系统：用于产生各种时序信号，它们都是由统一时钟（CLOCK）分频得到。&lt;/li&gt;
&lt;li&gt;存储器地址寄存器：用于存放所要访问的主存单元的地址。&lt;/li&gt;
&lt;li&gt;存储器数据寄存器：用于存放向主存写入的信息或从主存中读出的信息。&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;其中，时序系统、微操作信号发生器、指令译码器属于&lt;strong&gt;控制单元CU&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用户可见&lt;/strong&gt;的寄存器：通用寄存器组、程序状态字寄存器PSW、程序计数器PC&lt;/li&gt;
&lt;li&gt;用户不可见的寄存器：MAR、MDR、IR、暂存器&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-03_112027.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-03_130347.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="621-指令周期"&gt;6.2.1 指令周期
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;CPU从主存中每取出并执行一条指令所需的全部时间&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;周期中包括了&lt;strong&gt;取指周期和执行周期&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;取指周期包括&lt;strong&gt;取指令&lt;/strong&gt;，&lt;strong&gt;对指令译码&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;执行周期包括&lt;strong&gt;执行指令&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;指令周期常常用若干&lt;strong&gt;机器周期&lt;/strong&gt;来表示，&lt;strong&gt;机器周期&lt;/strong&gt;又叫&lt;strong&gt;CPU周期&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;取指阶段消耗一个CPU周期&lt;/li&gt;
&lt;li&gt;执行阶段又消耗一个CPU周期&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一个机器周期又包含若干&lt;strong&gt;时钟周期&lt;/strong&gt;（也称为节拍、T周期或CPU时钟周期）它是CPU操作的最基本单位。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如图中所示，取指令的机器周期( $T_0$ ~ $T_3$ ) 包括了4个&lt;strong&gt;微操作&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-06_142738.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个机器周期中的时钟周期数量不一定相等，一个指令周期中的机器周期的数量也不一定相同，所以分为了&lt;strong&gt;定长&lt;/strong&gt;的机器周期和&lt;strong&gt;不定长&lt;/strong&gt;的机器周期
&lt;ul&gt;
&lt;li&gt;如空指令(NOP)的指令周期只有一个机器周期，即&lt;strong&gt;取指周期&lt;/strong&gt;，从主存中取出指令&lt;/li&gt;
&lt;li&gt;如乘法指令的指令周期包含了取指周期，和较长的&lt;strong&gt;执行周期&lt;/strong&gt;，进行指令的执行&lt;/li&gt;
&lt;li&gt;若是具有间接寻址的指令，在取指周期和执行周期间，包含了&lt;strong&gt;间址周期&lt;/strong&gt;，用来将形式地址转化为实际地址，得到操作数的有效地址。有些会在指令周期的最后加入&lt;strong&gt;中断周期&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-06_145052.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="622-指令周期的数据流"&gt;6.2.2 指令周期的数据流
&lt;/h3&gt;&lt;h4 id="取指周期"&gt;取指周期
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-06_145443.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;当前指令地址送至存储器地址寄存器，记做：(PC) → MAR&lt;/li&gt;
&lt;li&gt;CU发出控制信号，经控制总线传到主存，这里是读信号，记做：1 → R&lt;/li&gt;
&lt;li&gt;将MAR所指主存中的内容经数据总线送入MDR，记做：M(MAR) → MDR&lt;/li&gt;
&lt;li&gt;将MDR中的内容(此时是指令)送入IR，记做：MDR → IR&lt;/li&gt;
&lt;li&gt;CU发出信号，形成下一条指令地址，记做：(PC)+1 → PC&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="间址周期"&gt;间址周期
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-06_150323.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;将指令的地址码送入MAR，记做：Ad(IR) → MAR 或Ad(MDR) → MAR&lt;/li&gt;
&lt;li&gt;CU发出信号，启动主存做读操作，记做：1 → R&lt;/li&gt;
&lt;li&gt;将MAR所指主存中的内容经数据总线送入MDR，记做：M(MAR) → MDR&lt;/li&gt;
&lt;li&gt;有效地址送至指令的地址码字段，记做：MDR → Ad(IR)&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="中断周期"&gt;中断周期
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-06_151338.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;中断，暂停当前任务去完成其他任务。为了能够恢复当前任务，需要保存断点。一般使用堆栈来保存断点，这里用SP表示栈顶地址，假设SP指向栈顶元素，进栈操作是先修改指针，后存入数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;CU控制将SP减1，修改后的地址送入MAR 记做：(SP)-1 → SP，(SP) → MAR 本质上是将断点存入某个存储单元，假设其地址为a，故可记做：a → MAR&lt;/li&gt;
&lt;li&gt;CU发出信号，启动主存做写操作， 记做：1 → W&lt;/li&gt;
&lt;li&gt;将断点(PC内容)送入MDR， 记做：(PC) → MDR&lt;/li&gt;
&lt;li&gt;CU控制将中断服务程序的入口地址(由向量地址形成部件产生)送入PC， 记做：向量地址 → PC&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id="623-指令执行方案"&gt;6.2.3 指令执行方案
&lt;/h3&gt;&lt;h4 id="单指令周期"&gt;单指令周期
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;对所有指令都选用&lt;strong&gt;相同的执行时间&lt;/strong&gt;来完成。&lt;/li&gt;
&lt;li&gt;指令之间&lt;strong&gt;串行执行&lt;/strong&gt;；指令周期取决于&lt;strong&gt;执行时间最长的指令&lt;/strong&gt;的执行时间。&lt;/li&gt;
&lt;li&gt;对于那些本来可以在更短时间内完成的指令，要使用这个较长的周期来完成，会&lt;strong&gt;降低整个系统的运行速度&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="多指令周期"&gt;多指令周期
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;对不同类型的指令选用不同的执行步骤来完成。&lt;/li&gt;
&lt;li&gt;指令之间&lt;strong&gt;串行执行&lt;/strong&gt;；可选用&lt;strong&gt;不同个数的时钟周期&lt;/strong&gt;来完成不同指令的执行过程。&lt;/li&gt;
&lt;li&gt;需要&lt;strong&gt;更复杂的硬件设计&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="流水线"&gt;流水线
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;在每一个时钟周期启动一条指令，尽量让&lt;strong&gt;多条指令同时运行&lt;/strong&gt;，但各自处在不同的执行步骤中。&lt;/li&gt;
&lt;li&gt;指令之间&lt;strong&gt;并行执行&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="631-数据通路-单总线结构"&gt;6.3.1 数据通路 单总线结构
&lt;/h3&gt;&lt;h4 id="寄存器之间数据传送"&gt;寄存器之间数据传送
&lt;/h4&gt;&lt;p&gt;比如把PC内容送至MAR，实现传送操作的流程及控制信号为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(PC) → Bus
&lt;ul&gt;
&lt;li&gt;$PC_{out}$有效，PC内容送总线&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Bus → MAR
&lt;ul&gt;
&lt;li&gt;$MAR_{in}$有效，总线内容送MAR&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="主存与cpu之间的数据传送"&gt;主存与CPU之间的数据传送
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-06_155516.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;比如CPU从主存读取指令，实现传送操作的流程及控制信号为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;(PC) → Bus → MAR&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;$PC_{out}$和$MAR_{in}$有效，现行指令地址 → MAR&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;1 → R&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;CU发读命令(通过控制总线发出，图中未画出)&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MEM(MAR) → MDR&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;$MDR_{in}$有效&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MDR → Bus → IR&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;$MDR_{out}$和$IR_{in}$有效，现行指令→IR&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="执行算术或逻辑运算"&gt;执行算术或逻辑运算
&lt;/h4&gt;&lt;p&gt;比如一条加法指令，微操作序列及控制信号为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Ad(IR) → Bus → MAR&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;$MDR_{out}$和$MAR_{in}$有效&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;1 → R&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;CU发读命令&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MEM(MAR) → 数据线 → MDR&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;$MDR_{in}$有效&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MDR → Bus → Y&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;$MDR_{out}$和$Y_{in}$有效，操作数→Y&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;(ACC) + Y → Z&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;$ACC_{out}$和$ALU_{in}$有效，CU向ALU发送加命令&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Z → ACC&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;$Z_{out}$和$ACC_{in}$有效，结果→ACC&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="例题-1"&gt;例题
&lt;/h5&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-06_162632.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;设有如图所示的单总线结构，分析指令ADD (R0),R1 的指令流程和控制信号&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;(R0)是目的操作数，R1是源操作数，R0有括号说明R0中存放的是操作数在主存的地址而非操作数本身，所以要对其进行间接寻址操作&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;分析指令功能和指令周期&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;功能：((R0)) + (R1) → (R0)&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;把计算结果放回R0所指向的存储单元&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;取指周期、间址周期、执行周期&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;取值周期&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;时序&lt;/th&gt;
					&lt;th&gt;微操作&lt;/th&gt;
					&lt;th&gt;有效控制信号&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;(PC) → MAR&lt;/td&gt;
					&lt;td&gt;PCout，MARin&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;M(MAR) → MDR (PC)+1 → PC&lt;/td&gt;
					&lt;td&gt;MemR，MARout，MDRinE&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;(MDR) → IR&lt;/td&gt;
					&lt;td&gt;MDRout，IRin&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;4&lt;/td&gt;
					&lt;td&gt;指令译码&lt;/td&gt;
					&lt;td&gt;-&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;间址周期&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;完成取数操作，被加数在主存中，加数已经放在寄存器R1中&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;时序&lt;/th&gt;
					&lt;th&gt;微操作&lt;/th&gt;
					&lt;th&gt;有效控制信号&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;(R0) → MAR&lt;/td&gt;
					&lt;td&gt;R0out，MARin&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;M(MAR) → MDR&lt;/td&gt;
					&lt;td&gt;MemR，MARout，MDRinE&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;(MDR) → Yin&lt;/td&gt;
					&lt;td&gt;MDRout，Yin&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;执行周期&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;完成取数操作，被加数在主存中，加数已经放在寄存器R1中&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;时序&lt;/th&gt;
					&lt;th&gt;微操作&lt;/th&gt;
					&lt;th&gt;有效控制信号&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;(R1)+(Y)→Z&lt;/td&gt;
					&lt;td&gt;R1out，ALUin，CU向ALU发ADD控制信号&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;(Z)→MDR&lt;/td&gt;
					&lt;td&gt;Zout，MDRin&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;(MDR)→M(MAR)&lt;/td&gt;
					&lt;td&gt;MemW，MDRoute，MARout&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="632-数据通路-专用数据通路"&gt;6.3.2 数据通路 专用数据通路
&lt;/h3&gt;&lt;p&gt;skip&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="641-硬布线控制器"&gt;6.4.1 硬布线控制器
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;微操作控制信号&lt;/strong&gt;由组合逻辑电路根据当前的指令码、状态和时序，即时产生。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="642-微程序控制器的基本原理"&gt;6.4.2 微程序控制器的基本原理
&lt;/h3&gt;&lt;h4 id="设计思路"&gt;设计思路
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-07_160501.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="基本结构"&gt;基本结构
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-07_161535.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;微地址形成部件：微地址即微指令在CM中的存放地址，通过指令操作码形成对应微程序的第一条微指令的存放地址。&lt;/li&gt;
&lt;li&gt;顺序逻辑：根据某些机器标志和时序信息确定下一条微指令的存放地址。&lt;/li&gt;
&lt;li&gt;CMAR（μPC）：微地址寄存器，指明接下来要执行的微指令的存放地址，大致相当于CPU中MAR和PC的组合体。&lt;/li&gt;
&lt;li&gt;地址译码器：将CMAR内的地址信息译码为电信号，控制CM读出微指令。&lt;/li&gt;
&lt;li&gt;控制存储器CM：存放所有指令对应的微程序（微指令序列）用ROM实现，按地址寻址。通常在CPU出厂时就把所有微程序写入。&lt;/li&gt;
&lt;li&gt;CMDR（μIR）：微指令寄存器，用于存放当前要执行的微指令。CM（μPC）→μIR。大致相当于CPU中MDR和IR的组合体。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="工作原理"&gt;工作原理
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;取指周期、间址周期、中断周期的微程序是&lt;strong&gt;可以共享&lt;/strong&gt;的，&lt;strong&gt;控存中只需存储一份&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;故如果某指令系统中有n条机器指令，则CM中&lt;strong&gt;微程序的个数至少是n+1个&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;间址、中断周期可有可无。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;假设接下来执行LDA指令（把主存中的数据放入ACC）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在取指周期的最后，程序不一定需要进入首地址为3的间址周期，而有可能直接进入执行周期，这需要顺序逻辑来指明接下来要执行的地址。中断周期也是同理。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;微周期（微指令周期）：从控存取出一条微指令并执行相应的微操作所需的时间。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="643-微指令的设计"&gt;6.4.3 微指令的设计
&lt;/h3&gt;&lt;h4 id="格式"&gt;格式
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;相容性微命令：可以并行完成的微命令。&lt;/li&gt;
&lt;li&gt;互斥性微命令：不允许并行完成的微命令。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="水平型微指令"&gt;水平型微指令
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;一条微指令能定义&lt;strong&gt;多个&lt;/strong&gt;可并行的微命令。&lt;/li&gt;
&lt;li&gt;基本格式由操作控制和顺序控制组成。&lt;/li&gt;
&lt;li&gt;优点：微程序短的情况，执行速度块。缺点：微指令长的情况，编写微程序较麻烦。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="垂直型微指令"&gt;垂直型微指令
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;一条微指令只能定义&lt;strong&gt;一个&lt;/strong&gt;微命令，由微操作码字段规定具体功能。&lt;/li&gt;
&lt;li&gt;基本格式由微操作码、目的地址和源地址组成。&lt;/li&gt;
&lt;li&gt;优点：微指令短、简单、规整，便于编写微程序。缺点：微程序长，执行速度慢，工作效率低。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="混合型微指令"&gt;混合型微指令
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;在垂直型的基础上增加一些不太复杂的并行操作。&lt;/li&gt;
&lt;li&gt;微指令较短，仍便于编写；微程序也不长，执行速度加快。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="编码方式控制方式"&gt;编码方式（控制方式）
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;微指令的编码方式又称为微指令的控制方式，它是指如何对微指令的控制字段进行编码，以形成控制信号。编码的目标是在保证速度的情况下，尽量缩短微指令字长。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面讨论的均为水平型微指令的编码（控制）方式&lt;/p&gt;
&lt;h5 id="直接编码方式"&gt;直接编码方式
&lt;/h5&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-07_184751.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在微指令的操作控制字段中，&lt;strong&gt;每一位代表一个微操作命令&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;某位为“1”表示该控制信号有效&lt;/li&gt;
&lt;li&gt;优点：简单、直观，执行速度快，操作并行性好。缺点：微指令字长过长，n个微命令就要求微指令的&lt;strong&gt;操作字段有n位&lt;/strong&gt;，造成&lt;strong&gt;控存容量极大&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="字段直接编码方式"&gt;字段直接编码方式
&lt;/h5&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-07_185716.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;将微指令的控制字段分成若干“段”，每段经译码后发出控制信号。微命令字段分段的原则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;互斥性&lt;/strong&gt;微命令分在&lt;strong&gt;同一段内&lt;/strong&gt;，&lt;strong&gt;相容性&lt;/strong&gt;微命令分在&lt;strong&gt;不同段内&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;每个小段&lt;/strong&gt;中包含的&lt;strong&gt;信息位不能太多&lt;/strong&gt;，否则将增加译码线路的复杂性和译码时间。&lt;/li&gt;
&lt;li&gt;一般&lt;strong&gt;每个小段还要留出一个状态&lt;/strong&gt;，表示本字段不发出任何微命令。因此，当某字段的长度为3位时，最多只能表示7个互斥的微命令。&lt;strong&gt;通常用000表示不操作&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;优点：可以缩短微指令字长。缺点：要通过译码电路后再发出微命令，因此比直接编码方式慢。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;例题：某计算机的控制器采用微程序控制方式，微指令中的操作控制字段采用&lt;strong&gt;字段直接编码法&lt;/strong&gt;，共有33个微命令，构成5个互斥类，分别包含7、3、12、5和6个微命令，则操作控制字段至少有多少位？&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;第1个互斥类有7个微命令，要留出1个状态表示不操作，所以需要表示8种不同的状态，故需要3个二进制位。&lt;/p&gt;
&lt;p&gt;以此类推，后面4个互斥类各需要表示4、13、6、7种不同的状态，分别对应2、4、3、3个二进制位。&lt;/p&gt;
&lt;p&gt;故操作控制字段的总位数为 3+2+4+3+3 = 15 位。&lt;/p&gt;
&lt;p&gt;Tips：若采用直接编码方式，则控制字段需要33位。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="字段间接编码方式"&gt;字段间接编码方式
&lt;/h5&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-07_190630.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个字段的某些微命令需由另一个字段中的某些微命令来解释，由于不是靠字段直接译码发出的微命令，故称为字段间接编码，又称隐式编码。&lt;/li&gt;
&lt;li&gt;优点：可进一步缩短微指令字长。缺点：削弱了微指令的并行控制能力，故通常作为字段直接编码方式的一种辅助手段。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="地址形成方式"&gt;地址形成方式
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;微指令的&lt;strong&gt;下地址字段&lt;/strong&gt;指出&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;微指令格式中设置一个下地址字段，由微指令的下地址字段直接指出后继微指令的地址，这种方式又称为&lt;strong&gt;断定方式&lt;/strong&gt;。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;根据机器指令的&lt;strong&gt;操作码&lt;/strong&gt;形成&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;当机器指令取至指令寄存器后，微指令的地址由操作码经微地址形成部件形成。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;增量计数器法&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;(CMAR)+1 → CMAR&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;分支转移&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;指明判别条件和转移成功后的去向&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过测试网络&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;由硬件产生微程序入口地址&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;第一条微指令地址 由专门硬件产生（用专门的硬件记录取指周期微程序首地址）
中断周期 由硬件产生 中断周期微程序首地址（用专门的硬件记录）&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;例题：某计算机采用微程序控制器，共有32条指令，公共的取指令微程序包含2条微指令，各指令对应的微程序平均由4条微指令组成，采用&lt;strong&gt;断定法&lt;/strong&gt;（下地址字段法）确定下条微指令地址，则微指令中下地址字段的位数&lt;strong&gt;至少&lt;/strong&gt;是多少位？&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;“至少”说明不需要间址和中断周期，只需额外计算取指周期的2条&lt;/p&gt;
&lt;p&gt;总共需要存储多少条微指令？ 32×4+2 = 130条&lt;/p&gt;
&lt;p&gt;标注出130个不同的位置至少需要多少个二进制位？ $2^7 = 128$，$2^8 = 256$&lt;/p&gt;
&lt;p&gt;下地址字段的位数至少是8位&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="644-微程序控制单元的设计"&gt;6.4.4 微程序控制单元的设计
&lt;/h3&gt;&lt;h4 id="设计步骤"&gt;设计步骤
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;分析每个阶段的微操作序列&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-09_150241.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;以取值周期为例，相比于硬布线的方式，若要读出微指令以及转入下一个机器周期，都需要多一个节拍&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;取指周期的第一条微指令地址由硬件自动给出，下一条指令的地址在当前执行的指令的下地址字段&lt;/li&gt;
&lt;li&gt;Ad(CMDR)→CMAR 用当前微指令的下地址表示找到下一条微指令&lt;/li&gt;
&lt;li&gt;微地址形成部件→CMAR&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;写出对应机器指令的微操作命令及节拍安排&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;写出每个周期所需要的微操作&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;补充微程序控制器特有的微操作&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;取指周期：Ad(CMDR)→CMAR 每条微指令结束之后都要进行，OP(IR)→微地址形成部件→CMAR 取值周期的最后一条微指令完成后，要根据指令操作码确定其执行周期的微程序首地址&lt;/li&gt;
&lt;li&gt;执行周期：Ad(CMDR)→CMAR 每条微指令结束之后都要进行&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;确定微指令格式&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;根据微操作个数决定采用何种编码方式，以确定微指令的操作控制字段的位数。根据CM中存储的微指令总数，确定微指令的顺序控制字段的位数。最后按操作控制字段位数和顺序控制字段位数就可确定微指令字长。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;编写微指令码点&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;根据操作控制字段每一位代表的微操作命令，编写每一条微指令的码点。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="微程序设计分类"&gt;微程序设计分类
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;静态微程序分类和动态微程序设计
&lt;ul&gt;
&lt;li&gt;静态：微程序无需改变，采用ROM&lt;/li&gt;
&lt;li&gt;动态：通过改变微指令和微程序改变机器指令，有利于仿真，采用EPROM&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;毫微程序设计&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="硬布线与微程序的比较"&gt;硬布线与微程序的比较
&lt;/h4&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;类别&lt;/th&gt;
					&lt;th&gt;微程序控制器&lt;/th&gt;
					&lt;th&gt;硬布线控制器&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;工作原理&lt;/td&gt;
					&lt;td&gt;微操作控制信号以微程序的形式存放在控制存储器中，执行指令时读出即可&lt;/td&gt;
					&lt;td&gt;微操作控制信号由组合逻辑电路根据当前的指令码、状态和时序，即时产生&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;执行速度&lt;/td&gt;
					&lt;td&gt;慢&lt;/td&gt;
					&lt;td&gt;快&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;规整性&lt;/td&gt;
					&lt;td&gt;较规整&lt;/td&gt;
					&lt;td&gt;烦琐、不规整&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;应用场合&lt;/td&gt;
					&lt;td&gt;CISC CPU&lt;/td&gt;
					&lt;td&gt;RISC CPU&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;易扩充性&lt;/td&gt;
					&lt;td&gt;易扩充修改&lt;/td&gt;
					&lt;td&gt;困难&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="651-指令流水线-基本概念和性能指标"&gt;6.5.1 指令流水线 基本概念和性能指标
&lt;/h3&gt;&lt;h4 id="基本概念-1"&gt;基本概念
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;一条指令的执行过程可以分成多个阶段（或过程）。根据计算机的不同，具体的分法也不同。
&lt;ul&gt;
&lt;li&gt;取指：根据PC内容访问主存储器，取出一条指令送到IR中。&lt;/li&gt;
&lt;li&gt;分析：对指令操作码进行译码，按照给定的寻址方式和地址字段中的内容形成操作数的有效地址EA，并从有效地址EA中取出操作数。&lt;/li&gt;
&lt;li&gt;执行：根据操作码字段，完成指令规定的功能，即把运算结果写到通用寄存器或主存中。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;设取指、分析、执行3个阶段的时间都相等，用t表示，按以下几种执行方式分析n条指令的执行时间&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;顺序执行方式&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-09_152404.png" alt="" loading="lazy" /&gt;&lt;/li&gt;
&lt;li&gt;总耗时 $T=n \times 3t = 3nt$&lt;/li&gt;
&lt;li&gt;传统冯·诺依曼机采用顺序执行方式，又称串行执行方式。优点：控制简单，硬件代价小。缺点：执行指令的速度较慢，在任何时刻，处理机中只有一条指令在执行，各功能部件的利用率很低。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;一次重叠执行方式&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-09_152700.png" alt="" loading="lazy" /&gt;&lt;/li&gt;
&lt;li&gt;总耗时 $T=3t+(n-1)\times 2t=(1+2n)t$&lt;/li&gt;
&lt;li&gt;优点：程序的执行时间缩短了1/3，各功能部件的利用率明显提高。缺点：需要付出硬件上较大开销的代价，控制过程也比顺序执行复杂了。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;二次重叠执行方式&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-09_153014.png" alt="" loading="lazy" /&gt;&lt;/li&gt;
&lt;li&gt;总耗时 $T=3t+(n-1) \times t=(2+n)t$&lt;/li&gt;
&lt;li&gt;与顺序执行方式相比，指令的执行时间缩短近2/3。这是一种理想的指令执行方式，在正常情况下，处理机中同时有3条指令在执行。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;除了上面的用指令执行过程图来表示流水线，主要用来分析指令执行过程以及影响流水线的因素。&lt;/p&gt;
&lt;p&gt;还有用时空图来表示流水线，主要用于分析流水线的性能。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-09_153347.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="性能指标"&gt;性能指标
&lt;/h4&gt;&lt;h5 id="吞吐率"&gt;吞吐率
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;吞吐率是指&lt;strong&gt;在单位时间内流水线所完成的任务数量，或是输出结果的数量&lt;/strong&gt;。设任务数为n；处理完成n个任务所用的时间为 $T_k$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;则计算流水线吞吐率(TP)的最基本公式为 $TP=\frac {n}{T_k}$ ， $T_k = (k+n-1)\Delta t$ ，流水线的实际吞吐率为 $TP=\frac{n}{(k+n-1)\Delta t}$ ，当连续输入的任务 $n→\infty$ 时，得最大吞吐率为$TP_{max}=1/\Delta t$ 。&lt;/p&gt;
&lt;p&gt;理想情况下，流水线的时空图如下：
&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-09_210529.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;一条指令的执行分为k个阶段，每个阶段耗时 $\Delta t$ ，一般取 $\Delta t=$ 一个时钟周期&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="加速比"&gt;加速比
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;加速比是完成同样一批任务，&lt;strong&gt;不使用流水线所用的时间与使用流水线所用的时间之比&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;设 $T_0$ 表示不使用流水线时的执行时间，即顺序执行所用的时间；$T_k$ 表示使用流水线时的执行时间。则计算流水线加速比（S）的基本公式为 $S=\frac{T_0}{T_k}$ 当连续输入的任务 $n\rightarrow \infty$ 时，最大加速比为 $S_{max}=k$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;单独完成一个任务耗时为 $k \Delta t$，则顺序完成n个任务耗时 $T_0=nk\Delta t$ ， $T_k=(k+n-1)\Delta t$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;实际加速比为 $S=\frac{nk\Delta t}{(k+n-1)\Delta t}=\frac{kn}{k+n-1}$&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="效率"&gt;效率
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;流水线的设备利用率称为流水线的效率&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在时空图上，流水线的效率定义为&lt;strong&gt;完成n个任务占用的时空区有效面积与n个任务所用的时间与k个流水段所围成的时空区总面积之比&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;理想情况下，流水线的时空图如下：
&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-09_233838.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;则流水线效率（E）的一般公式为
&lt;/p&gt;
$$
 E=\frac{n个任务占用k时空区有效面积}{n个任务所用的时间与k个流水线所围成的时空区总面积}=\frac{T_0}{kT_k}
 $$&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;当连续输入的任务 $n\rightarrow \infty$ 时，最高效率为 $E_{max}=1$&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="652-指令流水线影响因素分类"&gt;6.5.2 指令流水线影响因素分类
&lt;/h3&gt;&lt;p&gt;为方便流水线的设计，将每个阶段的耗时取成一样，以最长耗时为准。&lt;/p&gt;
&lt;p&gt;流水线每一个功能段部件后面都要有一个缓冲寄存器，或称为锁存器，其作用是保存本流水段的执行结果，提供给下一流水段使用。&lt;/p&gt;
&lt;h4 id="结构相关资源冲突"&gt;结构相关（资源冲突）
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-10_100325.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;由于多条指令在&lt;strong&gt;同一时刻争用同一资源&lt;/strong&gt;而形成的冲突称为结构相关。&lt;/li&gt;
&lt;li&gt;如图所示，Load和Instr3在同一时刻访问了主存和寄存器，造成冲突。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解决方法&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;1.后一指令暂停一周期。&lt;/li&gt;
&lt;li&gt;2.数据存储器+指令存储器，分开存储。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="数据相关数据冲突"&gt;数据相关（数据冲突）
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-10_100816.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据相关指在一个程序中，存在必须等前一条指令执行完才能执行后一条指令的情况，则这两条指令即为数据相关。&lt;/li&gt;
&lt;li&gt;如图所示，第一条指令执行 $r1=r2+r3$ 但是在r1被写回寄存器之前，后面的指令在前面的时刻就进行了调用，造成冲突。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解决方法&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;1.把遇到数据相关的指令及其后续指令都暂停一至几个时钟周期，直到数据相关问题消失后再继续执行。可分为硬件阻塞(stall)和软件插入&amp;quot;NOP(空指令)&amp;ldquo;两种方法。&lt;/li&gt;
&lt;li&gt;2.数据旁路技术（转发机制）如在上图，将第一条指令的ALU连接至下一条指令的ALU，在不用写回寄存器的情况下即可使用此操作数。&lt;/li&gt;
&lt;li&gt;3.编译优化，通过编译器调整指令顺序来解决，如将后面无冲突的指令更早运行。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="控制相关控制冲突"&gt;控制相关（控制冲突）
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-10_102445.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当流水线遇到&lt;strong&gt;转移指令&lt;/strong&gt;和其它&lt;strong&gt;改变PC值的指令&lt;/strong&gt;而造成断流时，会引起控制相关。&lt;/li&gt;
&lt;li&gt;如图所示，第一条指令为条件转移，若是不满足条件，指令顺序执行，若是满足条件，可能发生跳转，中间的指令不执行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解决方法&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;1.转移指令分支预测：简单预测（永远猜true或false）动态预测（根据历史情况动态调整）。&lt;/li&gt;
&lt;li&gt;2.预取转移成功和不成功两个控制流方向上的目标指令。&lt;/li&gt;
&lt;li&gt;3.加快和提前形成条件码。&lt;/li&gt;
&lt;li&gt;4.提高转移方向的猜准率。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="71-总线概述"&gt;7.1 总线概述
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-10_125001.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="总线的特点"&gt;总线的特点
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;总线是一组能为多个部件&lt;strong&gt;分时共享&lt;/strong&gt;的公共信息的传送线路。
&lt;ul&gt;
&lt;li&gt;分时是指同一时刻只允许有一个部件向总线发送信息，如果系统中有多个部件，则它们只能分时地向总线发送信息。&lt;/li&gt;
&lt;li&gt;共享是指总线上可以挂接多个部件，各个部件之间互相交换的信息都可以通过这组线路分时共享。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;早期计算机外部设备少时大多采用分散连接方式，不易实现随时增减外部设备。为了更好地解决I/O设备和主机之间连接的灵活性问题，计算机的结构从分散连接发展为总线连接。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="总线的特性"&gt;总线的特性
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;机械特性：尺寸、形状、管脚数、排列顺序&lt;/li&gt;
&lt;li&gt;电气特性：传输方向和有效的电平范围&lt;/li&gt;
&lt;li&gt;功能特性：每根传输线的功能（地址、数据、控制）&lt;/li&gt;
&lt;li&gt;时间特性：信号的时序关系&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="总线的分类"&gt;总线的分类
&lt;/h4&gt;&lt;p&gt;数据通路表示的是数据流经的路径，数据总线是承载的媒介。&lt;/p&gt;
&lt;h5 id="按数据传输格式"&gt;按数据传输格式
&lt;/h5&gt;&lt;p&gt;设备通过串行总线只能一位一位地传输数据，通过并行总线可以同时传输多位数据。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;串行总线&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;优点：只需要一条传输线，成本低廉，广泛应用于长距离传输；应用于计算机内部时，可以节省布线空间。&lt;/li&gt;
&lt;li&gt;缺点：在数据发送和接收的时候要进行拆卸和装配，要考虑串行-并行转换的问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;并行总线&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;优点：总线的逻辑时序比较简单，电路实现起来比较容易。&lt;/li&gt;
&lt;li&gt;缺点：信号线数量多，占用更多的布线空间；远距离传输成本高昂；由于工作频率较高时，并行的信号线之间会产生严重干扰，对每条线等长的要求也越高，所以无法持续提升工作频率。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;速度对比&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;工作频率相同时，串行总线传输速度比并行总线慢。&lt;/li&gt;
&lt;li&gt;并行总线的工作频率无法持续提高，而串行总线可以通过不断提高工作频率来提高传输速度，最终超过并行总线。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="按总线功能"&gt;按总线功能
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;片内总线&lt;/strong&gt;：片内总线是芯片内部的总线。它是CPU芯片内部寄存器之间、寄存器与ALU之间的公共连接线。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;系统总线&lt;/strong&gt;：系统总线是计算机系统内各功能部件（CPU、主存、I/O接口）之间相互连接的总线。按系统总线传输信息内容的不同，又可分为3类：&lt;strong&gt;数据总线、地址总线和控制总线&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-10_175732.png" alt="" loading="lazy" /&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据总线&lt;/strong&gt;用来传输各功能部件之间的数据信息，它是&lt;strong&gt;双向&lt;/strong&gt;传输总线，其位数&lt;strong&gt;与机器字长、存储字长有关&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;地址总线&lt;/strong&gt;用来指出数据总线上的源数据或目的数据所在的主存单元或I/O端口的地址，它是&lt;strong&gt;单向&lt;/strong&gt;传输总线，地址总线的位数&lt;strong&gt;与主存地址空间的大小有关&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;控制总线&lt;/strong&gt;传输的是控制信息，包括&lt;strong&gt;CPU送出的控制命令&lt;/strong&gt;和主存（或外设）&lt;strong&gt;返回CPU的反馈信号&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;通信总线&lt;/strong&gt;：通信总线是用于计算机系统之间或计算机系统与其他系统（如远程通信设备、测试设备）之间信息传送的总线，通信总线也称为外部总线。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id="系统总线的结构"&gt;系统总线的结构
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;单总线结构&lt;/strong&gt;：CPU、主存、I/O设备（通过I/O接口）都连接在一组总线上，允许I/O设备之间、I/O设备和CPU之间或I/O设备与主存之间直接交换信息。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;注：单总线并不是指只有一根信号线，系统总线按传送信息的不同可以细分为地址总线、数据总线和控制总线。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-10_122915.png" alt="" loading="lazy" /&gt;&lt;/li&gt;
&lt;li&gt;优点：结构简单，成本低，易于接入新的设备。&lt;/li&gt;
&lt;li&gt;缺点：带宽低、负载重，多个部件只能争用唯一的总线，且&lt;strong&gt;不支持并发传送操作&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;双总线结构&lt;/strong&gt;：有两条总线，一条是&lt;strong&gt;主存总线&lt;/strong&gt;，用于CPU、主存和通道之间进行数据传送；另一条是&lt;strong&gt;I/O总线&lt;/strong&gt;，用于多个外部设备与通道之间进行数据传送。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-10_123541.png" alt="" loading="lazy" /&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;通道&lt;/strong&gt;是具有特殊功能的&lt;strong&gt;处理器&lt;/strong&gt;，能对&lt;strong&gt;I/O设备&lt;/strong&gt;进行统一管理。通道程序放在主存中。&lt;/li&gt;
&lt;li&gt;优点：将较低速的I/O设备从单总线上分离出来，&lt;strong&gt;实现存储器总线和I/O总线分离&lt;/strong&gt;。支持突发（猝发）传送，即送出一个地址，收到多个地址连续的数据。&lt;/li&gt;
&lt;li&gt;缺点：需要增加通道等硬件设备。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;三总线结构&lt;/strong&gt;：三总线结构是在计算机系统各部件之间采用3条各自独立的总线来构成信息通路，这3条总线分别为&lt;strong&gt;主存总线、I/O总线和直接内存访问DMA总线&lt;/strong&gt;。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;DMA: Direct Memory Access 直接内存访问&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-10_124346.png" alt="" loading="lazy" /&gt;&lt;/li&gt;
&lt;li&gt;优点：提高了I/O设备的性能，使其更快地响应命令，提高系统吞吐量。&lt;/li&gt;
&lt;li&gt;缺点：系统工作效率较低（三条总线只能同时工作一条）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="72-总线的性能指标"&gt;7.2 总线的性能指标
&lt;/h3&gt;&lt;h4 id="传输周期总线周期"&gt;传输周期（总线周期）
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;一次总线操作所需的时间&lt;/strong&gt;（包括申请阶段、寻址阶段、传输阶段和结束阶段），通常由若干个总线时钟周期构成。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="时钟周期"&gt;时钟周期
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;即机器的时钟周期。计算机有一个统一的时钟，以控制整个计算机的各个部件，总线也要受此时钟的控制。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;总线周期与总线时钟周期的关系比较魔幻，大多数情况下，一个总线周期包含多个总线时钟周期。有时候，一个总线周期就是一个总线时钟周期。有时候，一个总线时钟周期可包含多个总线周期。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="工作频率"&gt;工作频率
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;总线上各种操作的频率，&lt;strong&gt;为总线周期的倒数&lt;/strong&gt;。若总线周期=N个时钟周期，则总线的工作频率=时钟频率/N。实际上指一秒内传送几次数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="时钟频率"&gt;时钟频率
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;即机器的时钟频率，&lt;strong&gt;为时钟周期的倒数&lt;/strong&gt;。若时钟周期为T，则时钟频率为 $1/T$ 。实际上指一秒内有多少个时钟周期。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="总线宽度"&gt;总线宽度
&lt;/h4&gt;&lt;p&gt;又称为&lt;strong&gt;总线位宽&lt;/strong&gt;，它是总线上同时能够传输的数据位数，通常是指&lt;strong&gt;数据总线的根数&lt;/strong&gt;，如32根称为32位（bit）总线。&lt;/p&gt;
&lt;h4 id="总线带宽"&gt;总线带宽
&lt;/h4&gt;&lt;p&gt;可理解为总线的数据传输率，即&lt;strong&gt;单位时间内总线上可传输数据的位数&lt;/strong&gt;，通常用每秒钟传送信息的字节数来衡量，单位可用字节/秒（B/s）表示。&lt;/p&gt;
&lt;p&gt;总线带宽是指总线本身所能达到的&lt;strong&gt;最高传输速率&lt;/strong&gt;。在计算实际的&lt;strong&gt;有效数据传输率&lt;/strong&gt;时，要用实际传输的数据量除以耗时。
&lt;/p&gt;
$$
总线带宽=总线工作频率\times 总线宽度(bit/s)=总线工作频率\times (总线宽度/8)(B/s)\\=\frac{总线宽度}{总线周期}(bit/s)=\frac{总线宽度/8}{总线周期}(B/s)
$$&lt;h4 id="总线复用"&gt;总线复用
&lt;/h4&gt;&lt;p&gt;总线复用是指一种信号线在&lt;strong&gt;不同的时间传输不同的信息&lt;/strong&gt;。可以使用较少的线传输更多的信息，从而节省了空间和成本。&lt;/p&gt;
&lt;h4 id="例题-2"&gt;例题
&lt;/h4&gt;&lt;p&gt;同步总线采用&lt;strong&gt;数据线和地址线复用方式&lt;/strong&gt;，其中地址/数据线有&lt;strong&gt;32根&lt;/strong&gt;，总线&lt;strong&gt;时钟频率为66MHz&lt;/strong&gt;，每个时钟周期&lt;strong&gt;传送两次&lt;/strong&gt;数据（上升沿和下降沿&lt;strong&gt;各传送一次&lt;/strong&gt;数据）。
1）该总线的最大数据传输率（总线带宽）是多少？
2）若该总线支持突发（猝发）传输方式，传输一个地址占用一个时钟周期，则一次“主存写”总线事务传输128位数据所需要的时间至少是多少？&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;(1)&amp;ldquo;数据线和地址线复用方式&amp;quot;即地址线先用这32根进行传输，数据线再分时&lt;strong&gt;复用&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;ldquo;每个时钟周期传送两次数据&amp;quot;即一个时钟周期包含两个总线周期，总线工作频率是时钟频率的两倍，$总线工作频率= 2\times 66MHz=132MHz$ $总线宽度=$32bit=4B$&lt;/p&gt;
&lt;p&gt;$总线带宽=总线工作频率\times 总线宽度 = 132MHz \times 4B/s = 528MB/s$&lt;/p&gt;
&lt;p&gt;(2)突发传输方式：一次总线事务中，主设备只需给出一个首地址，从设备就能从首地址开始的若干连续单元读出或写入多个数据。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;发送首地址占用1个时钟周期&lt;/strong&gt;，128位数据需传输4次，占用2个时钟周期&lt;/p&gt;
&lt;p&gt;一个时钟周期 = 1/66MHz ≈ 15ns 总耗时 = (1+2) × 15ns = 45ns&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id="731-程序查询方式"&gt;7.3.1 程序查询方式
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-10_201223.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/computer-organization/Screenshot_2025-09-10_194808.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;独占查询：CPU 100%的时间都在查询I/O状态，完全串行&lt;/li&gt;
&lt;li&gt;定时查询：在保证数据不丢失的情况下，每隔一段时间CPU就查询一次I/O状态，查询的间隔内CPU可以执行其它程序&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="例题-3"&gt;例题
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在&lt;strong&gt;程序查询方式&lt;/strong&gt;的输入/输出系统中，假设不考虑处理时间，每一个查询操作需要100个时钟周期，CPU的&lt;strong&gt;时钟频率&lt;/strong&gt;为50MHz。现有鼠标和硬盘两个设备，而且CPU必须每秒对鼠标进行30次查询，硬盘以32位字长为单位传输数据，即每32位被CPU查询一次，传输率为$2×2^{20}B/s$。求CPU对这两个设备查询所花费的时间比率，由此可得出什么结论？&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;通过时钟频率得出一个时钟周期为 $1/50MHz=20ns$&lt;/p&gt;
&lt;p&gt;则每次查询操作耗时 $100 \times 20ns = 2000ns$&lt;/p&gt;
&lt;p&gt;(1)每秒查询鼠标耗时 $30 \times 2000ns=60000ns$&lt;/p&gt;
&lt;p&gt;查询鼠标所花费的时间比率 $=60000ns/1s=0.006\%$&lt;/p&gt;
&lt;p&gt;则对鼠标的查询基本不影响CPU的性能&lt;/p&gt;
&lt;p&gt;(2)每32位需要查询一次，每秒传送 $2 \times 2^{20}B$&lt;/p&gt;
&lt;p&gt;每秒需要查询 $2 \times 2^{20}B/4B=2^{19}次$&lt;/p&gt;
&lt;p&gt;查询硬盘耗时 $2^{19}\times 2000ns = 512\times 1024\times 2000ns\approx 1.05\times 10^9ns$&lt;/p&gt;
&lt;p&gt;查询硬盘所花费的时间比率$=(1.05\times 10^9ns)/1s=105\%$&lt;/p&gt;
&lt;p&gt;则CPU将全部时间都用于硬盘的查询也不能满足硬盘传输的要求&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="732-dma方式"&gt;7.3.2 DMA方式
&lt;/h3&gt;&lt;hr&gt;</description></item><item><title>Maven 基础</title><link>https://ottercoconut.github.io/p/maven-%E5%9F%BA%E7%A1%80/</link><pubDate>Tue, 01 Apr 2025 14:49:00 +0800</pubDate><guid>https://ottercoconut.github.io/p/maven-%E5%9F%BA%E7%A1%80/</guid><description>&lt;h3 id="参考网站"&gt;参考网站
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://liaoxuefeng.com/books/java/maven/index.html" target="_blank" rel="noopener"
 &gt;Maven基础 - Java教程 - 廖雪峰的官方网站&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="maven-基础"&gt;Maven 基础
&lt;/h2&gt;&lt;h3 id="maven介绍"&gt;maven介绍
&lt;/h3&gt;&lt;p&gt;在了解Maven之前，我们先来看看一个Java项目需要的东西。首先，我们需要确定引入哪些依赖包。例如，如果我们需要用到&lt;a class="link" href="https://commons.apache.org/proper/commons-logging/" target="_blank" rel="noopener"
 &gt;commons logging&lt;/a&gt;，我们就必须把commons logging的jar包放入classpath。如果我们还需要&lt;a class="link" href="https://logging.apache.org/log4j/" target="_blank" rel="noopener"
 &gt;log4j&lt;/a&gt;，就需要把log4j相关的jar包都放到classpath中。这些就是依赖包的管理。&lt;/p&gt;
&lt;p&gt;其次，我们要确定项目的目录结构。例如，&lt;code&gt;src&lt;/code&gt;目录存放Java源码，&lt;code&gt;resources&lt;/code&gt;目录存放配置文件，&lt;code&gt;bin&lt;/code&gt;目录存放编译生成的&lt;code&gt;.class&lt;/code&gt;文件。&lt;/p&gt;
&lt;p&gt;此外，我们还需要配置环境，例如JDK的版本，编译打包的流程，当前代码的版本号。&lt;/p&gt;
&lt;p&gt;最后，除了使用Eclipse这样的IDE进行编译外，我们还必须能通过命令行工具进行编译，才能够让项目在一个独立的服务器上编译、测试、部署。&lt;/p&gt;
&lt;p&gt;这些工作难度不大，但是非常琐碎且耗时。如果每一个项目都自己搞一套配置，肯定会一团糟。我们需要的是一个标准化的Java项目管理和构建工具。&lt;/p&gt;
&lt;p&gt;Maven就是是专门为Java项目打造的管理和构建工具，它的主要功能有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提供了一套标准化的项目结构；&lt;/li&gt;
&lt;li&gt;提供了一套标准化的构建流程（编译，测试，打包，发布……）；&lt;/li&gt;
&lt;li&gt;提供了一套依赖管理机制。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="maven项目结构"&gt;Maven项目结构
&lt;/h4&gt;&lt;p&gt;一个使用Maven管理的普通的Java项目，它的目录结构默认如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;a-maven-project
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── pom.xml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── src
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── main
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │ ├── java
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │ └── resources
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── test
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── java
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── resources
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── target
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;项目的根目录&lt;code&gt;a-maven-project&lt;/code&gt;是项目名，它有一个项目描述文件&lt;code&gt;pom.xml&lt;/code&gt;，存放Java源码的目录是&lt;code&gt;src/main/java&lt;/code&gt;，存放资源文件的目录是&lt;code&gt;src/main/resources&lt;/code&gt;，存放测试源码的目录是&lt;code&gt;src/test/java&lt;/code&gt;，存放测试资源的目录是&lt;code&gt;src/test/resources&lt;/code&gt;，最后，所有编译、打包生成的文件都放在&lt;code&gt;target&lt;/code&gt;目录里。这些就是一个Maven项目的标准目录结构。&lt;/p&gt;
&lt;p&gt;所有的目录结构都是约定好的标准结构，我们千万不要随意修改目录结构。使用标准结构不需要做任何配置，Maven就可以正常使用。&lt;/p&gt;
&lt;p&gt;我们再来看最关键的一个项目描述文件&lt;code&gt;pom.xml&lt;/code&gt;，它的内容长得像下面：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;project&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="nt"&gt;&amp;lt;modelVersion&amp;gt;&lt;/span&gt;4.0.0&lt;span class="nt"&gt;&amp;lt;/modelVersion&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.itranswarp.learnjava&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;hello&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="nt"&gt;&amp;lt;packaging&amp;gt;&lt;/span&gt;jar&lt;span class="nt"&gt;&amp;lt;/packaging&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="nt"&gt;&amp;lt;properties&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;project.build.sourceEncoding&amp;gt;&lt;/span&gt;UTF-8&lt;span class="nt"&gt;&amp;lt;/project.build.sourceEncoding&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;		&lt;span class="nt"&gt;&amp;lt;maven.compiler.release&amp;gt;&lt;/span&gt;17&lt;span class="nt"&gt;&amp;lt;/maven.compiler.release&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="nt"&gt;&amp;lt;/properties&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.slf4j&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;slf4j-simple&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.0.16&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/project&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;其中，&lt;code&gt;groupId&lt;/code&gt;类似于Java的包名，通常是公司或组织名称，&lt;code&gt;artifactId&lt;/code&gt;类似于Java的类名，通常是项目名称，再加上&lt;code&gt;version&lt;/code&gt;，一个Maven工程就是由&lt;code&gt;groupId&lt;/code&gt;，&lt;code&gt;artifactId&lt;/code&gt;和&lt;code&gt;version&lt;/code&gt;作为唯一标识。&lt;/p&gt;
&lt;p&gt;我们在引用其他第三方库的时候，也是通过这3个变量确定。例如，依赖&lt;code&gt;org.slfj4:slf4j-simple:2.0.16&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.slf4j&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;slf4j-simple&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.0.16&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;使用&lt;code&gt;&amp;lt;dependency&amp;gt;&lt;/code&gt;声明一个依赖后，Maven就会自动下载这个依赖包并把它放到classpath中。&lt;/p&gt;
&lt;p&gt;另外，注意到&lt;code&gt;&amp;lt;properties&amp;gt;&lt;/code&gt;定义了一些属性，常用的属性有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;project.build.sourceEncoding&lt;/code&gt;：表示项目源码的字符编码，通常应设定为&lt;code&gt;UTF-8&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maven.compiler.release&lt;/code&gt;：表示使用的JDK版本，例如&lt;code&gt;21&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maven.compiler.source&lt;/code&gt;：表示Java编译器读取的源码版本；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maven.compiler.target&lt;/code&gt;：表示Java编译器编译的Class版本。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从Java 9开始，推荐使用&lt;code&gt;maven.compiler.release&lt;/code&gt;属性，保证编译时输入的源码和编译输出版本一致。如果源码和输出版本不同，则应该分别设置&lt;code&gt;maven.compiler.source&lt;/code&gt;和&lt;code&gt;maven.compiler.target&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;通过&lt;code&gt;&amp;lt;properties&amp;gt;&lt;/code&gt;定义的属性，就可以固定JDK版本，防止同一个项目的不同的开发者各自使用不同版本的JDK。&lt;/p&gt;
&lt;h4 id="小结"&gt;小结
&lt;/h4&gt;&lt;p&gt;Maven是一个Java项目的管理和构建工具：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Maven使用&lt;code&gt;pom.xml&lt;/code&gt;定义项目内容，并使用预设的目录结构；&lt;/li&gt;
&lt;li&gt;在Maven中声明一个依赖项可以自动下载并导入classpath；&lt;/li&gt;
&lt;li&gt;Maven使用&lt;code&gt;groupId&lt;/code&gt;，&lt;code&gt;artifactId&lt;/code&gt;和&lt;code&gt;version&lt;/code&gt;唯一定位一个依赖。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="依赖管理"&gt;依赖管理
&lt;/h3&gt;&lt;p&gt;如果我们的项目依赖第三方的jar包，例如commons logging，那么问题来了：commons logging发布的jar包在哪下载？&lt;/p&gt;
&lt;p&gt;如果我们还希望依赖log4j，那么使用log4j需要哪些jar包？&lt;/p&gt;
&lt;p&gt;类似的依赖还包括：JUnit，JavaMail，MySQL驱动等等，一个可行的方法是通过搜索引擎搜索到项目的官网，然后手动下载zip包，解压，放入classpath。但是，这个过程非常繁琐。&lt;/p&gt;
&lt;p&gt;Maven解决了依赖管理问题。例如，我们的项目依赖&lt;code&gt;abc&lt;/code&gt;这个jar包，而&lt;code&gt;abc&lt;/code&gt;又依赖&lt;code&gt;xyz&lt;/code&gt;这个jar包：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌──────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│Sample Project│
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└──────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ▼
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌──────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ abc │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└──────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ▼
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌──────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ xyz │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└──────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;当我们声明了&lt;code&gt;abc&lt;/code&gt;的依赖时，Maven自动把&lt;code&gt;abc&lt;/code&gt;和&lt;code&gt;xyz&lt;/code&gt;都加入了我们的项目依赖，不需要我们自己去研究&lt;code&gt;abc&lt;/code&gt;是否需要依赖&lt;code&gt;xyz&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;因此，Maven的第一个作用就是解决依赖管理。我们声明了自己的项目需要&lt;code&gt;abc&lt;/code&gt;，Maven会自动导入&lt;code&gt;abc&lt;/code&gt;的jar包，再判断出&lt;code&gt;abc&lt;/code&gt;需要&lt;code&gt;xyz&lt;/code&gt;，又会自动导入&lt;code&gt;xyz&lt;/code&gt;的jar包，这样，最终我们的项目会依赖&lt;code&gt;abc&lt;/code&gt;和&lt;code&gt;xyz&lt;/code&gt;两个jar包。&lt;/p&gt;
&lt;p&gt;我们来看一个复杂依赖示例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-web&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.4.2.RELEASE&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;当我们声明一个&lt;code&gt;spring-boot-starter-web&lt;/code&gt;依赖时，Maven会自动解析并判断最终需要大概二三十个其他依赖：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;spring-boot-starter-web
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; spring-boot-starter
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; spring-boot
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sprint-boot-autoconfigure
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; spring-boot-starter-logging
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; logback-classic
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; logback-core
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; slf4j-api
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; jcl-over-slf4j
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; slf4j-api
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; jul-to-slf4j
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; slf4j-api
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; log4j-over-slf4j
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; slf4j-api
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; spring-core
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; snakeyaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; spring-boot-starter-tomcat
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; tomcat-embed-core
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; tomcat-embed-el
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; tomcat-embed-websocket
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; tomcat-embed-core
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; jackson-databind
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果我们自己去手动管理这些依赖是非常费时费力的，而且出错的概率很大。&lt;/p&gt;
&lt;h3 id="依赖关系"&gt;依赖关系
&lt;/h3&gt;&lt;p&gt;Maven定义了几种依赖关系，分别是&lt;code&gt;compile&lt;/code&gt;、&lt;code&gt;test&lt;/code&gt;、&lt;code&gt;runtime&lt;/code&gt;和&lt;code&gt;provided&lt;/code&gt;：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;scope&lt;/th&gt;
					&lt;th&gt;说明&lt;/th&gt;
					&lt;th&gt;示例&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;compile&lt;/td&gt;
					&lt;td&gt;编译时需要用到该jar包（默认）&lt;/td&gt;
					&lt;td&gt;commons-logging&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;test&lt;/td&gt;
					&lt;td&gt;编译Test时需要用到该jar包&lt;/td&gt;
					&lt;td&gt;junit&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;runtime&lt;/td&gt;
					&lt;td&gt;编译时不需要，但运行时需要用到&lt;/td&gt;
					&lt;td&gt;mysql&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;provided&lt;/td&gt;
					&lt;td&gt;编译时需要用到，但运行时由JDK或某个服务器提供&lt;/td&gt;
					&lt;td&gt;servlet-api&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;其中，默认的&lt;code&gt;compile&lt;/code&gt;是最常用的，Maven会把这种类型的依赖直接放入classpath。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;test&lt;/code&gt;依赖表示仅在测试时使用，正常运行时并不需要。最常用的&lt;code&gt;test&lt;/code&gt;依赖就是JUnit：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.junit.jupiter&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;junit-jupiter-api&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;5.3.2&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;runtime&lt;/code&gt;依赖表示编译时不需要，但运行时需要。最典型的&lt;code&gt;runtime&lt;/code&gt;依赖是JDBC驱动，例如MySQL驱动：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;mysql&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;mysql-connector-java&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;5.1.48&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;runtime&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;provided&lt;/code&gt;依赖表示编译时需要，但运行时不需要。最典型的&lt;code&gt;provided&lt;/code&gt;依赖是Servlet API，编译的时候需要，但是运行时，Servlet服务器内置了相关的jar，所以运行期不需要：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;jakarta.servlet&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;jakarta.servlet-api&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;4.0.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;provided&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;最后一个问题是，Maven如何知道从何处下载所需的依赖？也就是相关的jar包？答案是Maven维护了一个中央仓库（&lt;a class="link" href="https://repo1.maven.org/" target="_blank" rel="noopener"
 &gt;repo1.maven.org&lt;/a&gt;），所有第三方库将自身的jar以及相关信息上传至中央仓库，Maven就可以从中央仓库把所需依赖下载到本地。&lt;/p&gt;
&lt;p&gt;Maven并不会每次都从中央仓库下载jar包。一个jar包一旦被下载过，就会被Maven自动缓存在本地目录（用户主目录的&lt;code&gt;.m2&lt;/code&gt;目录），所以，除了第一次编译时因为下载需要时间会比较慢，后续过程因为有本地缓存，并不会重复下载相同的jar包。&lt;/p&gt;
&lt;h4 id="唯一id"&gt;唯一ID
&lt;/h4&gt;&lt;p&gt;对于某个依赖，Maven只需要3个变量即可唯一确定某个jar包：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;groupId：属于组织的名称，类似Java的包名；&lt;/li&gt;
&lt;li&gt;artifactId：该jar包自身的名称，类似Java的类名；&lt;/li&gt;
&lt;li&gt;version：该jar包的版本。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通过上述3个变量，即可唯一确定某个jar包。Maven通过对jar包进行PGP签名确保任何一个jar包一经发布就无法修改。修改已发布jar包的唯一方法是发布一个新版本。&lt;/p&gt;
&lt;p&gt;因此，某个jar包一旦被Maven下载过，即可永久地安全缓存在本地。&lt;/p&gt;
&lt;p&gt;注：只有以&lt;code&gt;-SNAPSHOT&lt;/code&gt;结尾的版本号会被Maven视为开发版本，开发版本每次都会重复下载，这种SNAPSHOT版本只能用于内部私有的Maven repo，公开发布的版本不允许出现SNAPSHOT。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;后续我们在表示Maven依赖时，使用简写形式groupId:artifactId:version，例如：org.slf4j:slf4j-api:2.0.4。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h4 id="maven镜像"&gt;Maven镜像
&lt;/h4&gt;&lt;p&gt;除了可以从Maven的中央仓库下载外，还可以从Maven的镜像仓库下载。如果访问Maven的中央仓库非常慢，我们可以选择一个速度较快的Maven的镜像仓库。Maven镜像仓库定期从中央仓库同步：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; slow ┌───────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ┌─────────────▶│Maven Central Repo.│
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ └───────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ │sync
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ▼
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌───────┐ fast ┌───────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ User │─────────▶│Maven Mirror Repo. │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└───────┘ └───────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;中国区用户可以使用阿里云提供的Maven镜像仓库。使用Maven镜像仓库需要一个配置，在用户主目录下进入&lt;code&gt;.m2&lt;/code&gt;目录，创建一个&lt;code&gt;settings.xml&lt;/code&gt;配置文件，内容如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-xml" data-lang="xml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;settings&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;mirrors&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;mirror&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;aliyun&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;aliyun&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;mirrorOf&amp;gt;&lt;/span&gt;central&lt;span class="nt"&gt;&amp;lt;/mirrorOf&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c"&gt;&amp;lt;!-- 国内推荐阿里云的Maven镜像 --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;url&amp;gt;&lt;/span&gt;https://maven.aliyun.com/repository/central&lt;span class="nt"&gt;&amp;lt;/url&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/mirror&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;lt;/mirrors&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;lt;/settings&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;配置镜像仓库后，Maven的下载速度就会非常快。&lt;/p&gt;
&lt;h4 id="搜索第三方组件"&gt;搜索第三方组件
&lt;/h4&gt;&lt;p&gt;最后一个问题：如果我们要引用一个第三方组件，比如&lt;code&gt;okhttp&lt;/code&gt;，如何确切地获得它的&lt;code&gt;groupId&lt;/code&gt;、&lt;code&gt;artifactId&lt;/code&gt;和&lt;code&gt;version&lt;/code&gt;？方法是通过&lt;a class="link" href="https://search.maven.org/" target="_blank" rel="noopener"
 &gt;search.maven.org&lt;/a&gt;搜索关键字，找到对应的组件后，直接复制&lt;/p&gt;
&lt;h4 id="命令行编译"&gt;命令行编译
&lt;/h4&gt;&lt;p&gt;在命令中，进入到&lt;code&gt;pom.xml&lt;/code&gt;所在目录，输入以下命令：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-plain" data-lang="plain"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mvn clean package
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果一切顺利，即可在&lt;code&gt;target&lt;/code&gt;目录下获得编译后自动打包的jar。&lt;/p&gt;
&lt;h4 id="在ide中使用maven"&gt;在IDE中使用Maven
&lt;/h4&gt;&lt;p&gt;几乎所有的IDE都内置了对Maven的支持。在Eclipse中，可以直接创建或导入Maven项目。如果导入后的Maven项目有错误，可以尝试选择项目后点击右键，选择Maven - Update Project&amp;hellip;更新&lt;/p&gt;
&lt;h4 id="小结-1"&gt;小结
&lt;/h4&gt;&lt;p&gt;Maven通过解析依赖关系确定项目所需的jar包，常用的4种&lt;code&gt;scope&lt;/code&gt;有：&lt;code&gt;compile&lt;/code&gt;（默认），&lt;code&gt;test&lt;/code&gt;，&lt;code&gt;runtime&lt;/code&gt;和&lt;code&gt;provided&lt;/code&gt;；&lt;/p&gt;
&lt;p&gt;Maven从中央仓库下载所需的jar包并缓存在本地；&lt;/p&gt;
&lt;p&gt;可以通过镜像仓库加速下载。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="构建流程"&gt;构建流程
&lt;/h3&gt;&lt;p&gt;Maven不但有标准化的项目结构，而且还有一套标准化的构建流程，可以自动化实现编译，打包，发布，等等。&lt;/p&gt;
&lt;h4 id="lifecycle和phase"&gt;Lifecycle和Phase
&lt;/h4&gt;&lt;p&gt;使用Maven时，我们首先要了解什么是Maven的生命周期（lifecycle）。&lt;/p&gt;
&lt;p&gt;Maven的生命周期由一系列阶段（phase）构成，以内置的生命周期&lt;code&gt;default&lt;/code&gt;为例，它包含以下phase：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;validate 校验&lt;/li&gt;
&lt;li&gt;initialize 初始化&lt;/li&gt;
&lt;li&gt;generate-sources 生成源码&lt;/li&gt;
&lt;li&gt;process-sources 处理源码&lt;/li&gt;
&lt;li&gt;generate-resources 生成资源&lt;/li&gt;
&lt;li&gt;process-resources 处理资源&lt;/li&gt;
&lt;li&gt;compile 编译&lt;/li&gt;
&lt;li&gt;process-classes 处理-classes&lt;/li&gt;
&lt;li&gt;generate-test-sources 生成测试源码&lt;/li&gt;
&lt;li&gt;process-test-sources 处理测试源码&lt;/li&gt;
&lt;li&gt;generate-test-resources 生成测试资源&lt;/li&gt;
&lt;li&gt;process-test-resources 处理测试资源&lt;/li&gt;
&lt;li&gt;test-compile 测试编译&lt;/li&gt;
&lt;li&gt;process-test-classes 处理测试-classes&lt;/li&gt;
&lt;li&gt;test 测试&lt;/li&gt;
&lt;li&gt;prepare-package 准备打包&lt;/li&gt;
&lt;li&gt;package 打包&lt;/li&gt;
&lt;li&gt;pre-integration-test 预综合测试&lt;/li&gt;
&lt;li&gt;integration-test 综合测试&lt;/li&gt;
&lt;li&gt;post-integration-test 综合测试之后&lt;/li&gt;
&lt;li&gt;verify 核实&lt;/li&gt;
&lt;li&gt;install 安装&lt;/li&gt;
&lt;li&gt;deploy 部署&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果我们运行&lt;code&gt;mvn package&lt;/code&gt;，Maven就会执行&lt;code&gt;default&lt;/code&gt;生命周期，它会从开始一直运行到&lt;code&gt;package&lt;/code&gt;这个phase为止：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;validate&lt;/li&gt;
&lt;li&gt;initialize&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;li&gt;prepare-package&lt;/li&gt;
&lt;li&gt;package&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果我们运行&lt;code&gt;mvn compile&lt;/code&gt;，Maven也会执行&lt;code&gt;default&lt;/code&gt;生命周期，但这次它只会运行到&lt;code&gt;compile&lt;/code&gt;，即以下几个phase：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;validate&lt;/li&gt;
&lt;li&gt;initialize&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;li&gt;process-resources&lt;/li&gt;
&lt;li&gt;compile&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Maven另一个常用的生命周期是&lt;code&gt;clean&lt;/code&gt;，它会执行3个phase：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pre-clean&lt;/li&gt;
&lt;li&gt;clean （注意这个clean不是lifecycle而是phase）&lt;/li&gt;
&lt;li&gt;post-clean&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，我们使用&lt;code&gt;mvn&lt;/code&gt;这个命令时，后面的参数是phase，Maven自动根据生命周期运行到指定的phase。&lt;/p&gt;
&lt;p&gt;更复杂的例子是指定多个phase，例如，运行&lt;code&gt;mvn clean package&lt;/code&gt;，Maven先执行&lt;code&gt;clean&lt;/code&gt;生命周期并运行到&lt;code&gt;clean&lt;/code&gt;这个phase，然后执行&lt;code&gt;default&lt;/code&gt;生命周期并运行到&lt;code&gt;package&lt;/code&gt;这个phase，实际执行的phase如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pre-clean&lt;/li&gt;
&lt;li&gt;clean （注意这个clean是phase）&lt;/li&gt;
&lt;li&gt;validate （开始执行default生命周期的第一个phase）&lt;/li&gt;
&lt;li&gt;initialize&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;li&gt;prepare-package&lt;/li&gt;
&lt;li&gt;package&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在实际开发过程中，经常使用的命令有：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mvn clean&lt;/code&gt;：清理所有生成的class和jar；&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mvn clean compile&lt;/code&gt;：先清理，再执行到&lt;code&gt;compile&lt;/code&gt;；&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mvn clean test&lt;/code&gt;：先清理，再执行到&lt;code&gt;test&lt;/code&gt;，因为执行&lt;code&gt;test&lt;/code&gt;前必须执行&lt;code&gt;compile&lt;/code&gt;，所以这里不必指定&lt;code&gt;compile&lt;/code&gt;；&lt;/p&gt;
&lt;p&gt;&lt;code&gt;mvn clean package&lt;/code&gt;：先清理，再执行到&lt;code&gt;package&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;大多数phase在执行过程中，因为我们通常没有在&lt;code&gt;pom.xml&lt;/code&gt;中配置相关的设置，所以这些phase什么事情都不做。&lt;/p&gt;
&lt;p&gt;经常用到的phase其实只有几个：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;clean：清理&lt;/li&gt;
&lt;li&gt;compile：编译&lt;/li&gt;
&lt;li&gt;test：运行测试&lt;/li&gt;
&lt;li&gt;package：打包&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="goal"&gt;Goal
&lt;/h4&gt;&lt;p&gt;执行一个phase又会触发一个或多个goal：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;执行的Phase&lt;/th&gt;
					&lt;th&gt;对应执行的Goal&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;compile&lt;/td&gt;
					&lt;td&gt;compiler:compile&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;test&lt;/td&gt;
					&lt;td&gt;compiler:testCompile surefire:test&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;goal的命名总是&lt;code&gt;abc:xyz&lt;/code&gt;这种形式。&lt;/p&gt;
&lt;p&gt;其实我们类比一下就明白了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;lifecycle相当于Java的package，它包含一个或多个phase；&lt;/li&gt;
&lt;li&gt;phase相当于Java的class，它包含一个或多个goal；&lt;/li&gt;
&lt;li&gt;goal相当于class的method，它其实才是真正干活的。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;大多数情况，我们只要指定phase，就默认执行这些phase默认绑定的goal，只有少数情况，我们可以直接指定运行一个goal，例如，启动Tomcat服务器：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-plain" data-lang="plain"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ mvn tomcat:run
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="小结-2"&gt;小结
&lt;/h4&gt;&lt;p&gt;Maven通过lifecycle、phase和goal来提供标准的构建流程。&lt;/p&gt;
&lt;p&gt;最常用的构建命令是指定phase，然后让Maven执行到指定的phase：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;mvn clean&lt;/li&gt;
&lt;li&gt;mvn clean compile&lt;/li&gt;
&lt;li&gt;mvn clean test&lt;/li&gt;
&lt;li&gt;mvn clean package&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通常情况，我们总是执行phase默认绑定的goal，因此不必指定goal。&lt;/p&gt;
&lt;hr&gt;</description></item><item><title>Java 多线程</title><link>https://ottercoconut.github.io/p/java-%E5%A4%9A%E7%BA%BF%E7%A8%8B/</link><pubDate>Fri, 21 Mar 2025 14:50:07 +0800</pubDate><guid>https://ottercoconut.github.io/p/java-%E5%A4%9A%E7%BA%BF%E7%A8%8B/</guid><description>&lt;h3 id="参考网站"&gt;参考网站
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://liaoxuefeng.com/books/java/threading/index.html" target="_blank" rel="noopener"
 &gt;多线程 - Java教程 - 廖雪峰的官方网站&lt;/a&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;多数参考了廖老师的博客 非常好教程&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;a class="link" href="https://segmentfault.com/a/1190000023960592" target="_blank" rel="noopener"
 &gt;万字图解Java多线程 - 个人文章 - SegmentFault 思否&lt;/a&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;相对没那么详细，就讲到同步锁和线程池，简洁清晰&lt;/p&gt;
&lt;p&gt;也补充了一些知识，例如线程状态，同步锁，生产者消费者模型&amp;hellip;&amp;hellip;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="java-多线程"&gt;Java 多线程
&lt;/h2&gt;&lt;h4 id="进程线程"&gt;进程/线程
&lt;/h4&gt;&lt;p&gt;进程和线程的关系： &lt;strong&gt;一个进程可以包含一个或多个线程&lt;/strong&gt; ，但至少会有一个线程。&lt;/p&gt;
&lt;p&gt;操作系统调度的 &lt;strong&gt;最小任务单位&lt;/strong&gt; 其实不是进程，而是线程。常用的Windows、Linux等操作系统都采用抢占式多任务，如何调度线程完全由操作系统决定，程序自己不能决定什么时候执行，以及执行多长时间。&lt;/p&gt;
&lt;p&gt;多任务既可以由多进程实现，也可以由单进程内的多线程实现，还可以混合多进程＋多线程&lt;/p&gt;
&lt;p&gt;和多线程相比，多进程的缺点在于：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;创建进程比创建线程 &lt;strong&gt;开销&lt;/strong&gt; 大，尤其是在Windows系统上&lt;/li&gt;
&lt;li&gt;进程间通信比线程间通信要慢，因为线程间通信就是读写同一个变量，速度很快&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;多进程的优点在于：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;多进程 &lt;strong&gt;稳定性&lt;/strong&gt; 比多线程高，因为在多进程的情况下，一个进程崩溃不会影响其他进程&lt;/li&gt;
&lt;li&gt;在多线程的情况下，任何一个线程崩溃会直接导致整个进程崩溃&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="多线程"&gt;多线程
&lt;/h4&gt;&lt;p&gt;Java语言内置了多线程支持：一个Java程序实际上是一个 &lt;strong&gt;JVM进程&lt;/strong&gt; ，JVM进程用一个主线程来执行&lt;code&gt;main()&lt;/code&gt;方法，在&lt;code&gt;main()&lt;/code&gt;方法内部，我们又可以启动多个线程。此外，JVM还有负责垃圾回收的其他工作线程等。&lt;/p&gt;
&lt;p&gt;和单线程相比，多线程编程的特点在于：多线程经常需要 &lt;strong&gt;读写共享数据，并且需要同步&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;例如，播放电影时，就必须由一个线程播放视频，另一个线程播放音频，两个线程需要协调运行，否则画面和声音就不同步。因此，多线程编程的复杂度高，调试更困难。&lt;/p&gt;
&lt;h3 id="创建多线程"&gt;创建多线程
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://liaoxuefeng.com/books/java/threading/new-thread/index.html" target="_blank" rel="noopener"
 &gt;创建新线程 - Java教程 - 廖雪峰的官方网站&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;要创建一个新线程非常容易，我们需要实例化一个&lt;code&gt;Thread&lt;/code&gt;实例，然后调用它的&lt;code&gt;start()&lt;/code&gt;方法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;令新线程能执行指定的代码，有以下几种方法：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;方法一&lt;/strong&gt; ：从&lt;code&gt;Thread&lt;/code&gt;派生一个自定义类，然后覆写&lt;code&gt;run()&lt;/code&gt;方法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyThread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Overread&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; 	&lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;start new thread!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;执行上述代码，注意到&lt;code&gt;start()&lt;/code&gt;方法会在内部自动调用实例的&lt;code&gt;run()&lt;/code&gt;方法。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;方法二&lt;/strong&gt; ：创建&lt;code&gt;Thread&lt;/code&gt;实例时，传入一个&lt;code&gt;Runnable&lt;/code&gt;实例&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MyRunnable&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 启动新线程&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyRunnable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Runnable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;start new thread!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;或者用Java 8引入的lambda语法进一步简写为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;start new thread!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 启动新线程&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;但是，直接调用 &lt;code&gt;run()&lt;/code&gt; 方法，并不能实现多线程，当前线程也不会改变，而只是执行 &lt;code&gt;run()&lt;/code&gt; 方法&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;必须调用&lt;code&gt;Thread&lt;/code&gt;实例的&lt;code&gt;start()&lt;/code&gt;方法才能启动新线程，如果我们查看&lt;code&gt;Thread&lt;/code&gt;类的源代码，会看到&lt;code&gt;start()&lt;/code&gt;方法内部调用了一个&lt;code&gt;private native void start0()&lt;/code&gt;方法，&lt;code&gt;native&lt;/code&gt;修饰符表示这个方法是由JVM虚拟机内部的C代码实现的，不是由Java代码实现的。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;使用线程和直接在 &lt;code&gt;main()&lt;/code&gt; 方法中执行的 &lt;strong&gt;区别&lt;/strong&gt; ：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-Java" data-lang="Java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;main start...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;thread run...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;thread end.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;main end...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;main&lt;/code&gt; 中命令执行顺序：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;打印 &lt;code&gt;main start...&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;创建 &lt;code&gt;Thread&lt;/code&gt; 对象&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;start&lt;/code&gt; 启动新线程&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;

 &lt;blockquote&gt;
 &lt;p&gt;当&lt;code&gt;start()&lt;/code&gt;方法被调用时，JVM就创建了一个新线程，我们通过实例变量&lt;code&gt;t&lt;/code&gt;来表示这个新线程对象，并开始执行。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;打印 &lt;code&gt;main end...&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但是，在 &lt;code&gt;t&lt;/code&gt; 线程开始运行后， &lt;code&gt;main&lt;/code&gt; 和 &lt;code&gt;t&lt;/code&gt; 就 &lt;strong&gt;同时运行&lt;/strong&gt; 了，此时程序本身无法确定线程的调度顺序&lt;/p&gt;
&lt;p&gt;要模拟并发执行的效果，我们可以在线程中调用&lt;code&gt;Thread.sleep()&lt;/code&gt;，参数的单位是毫秒， &lt;code&gt;sleep()&lt;/code&gt; 强迫当前线程 &lt;strong&gt;暂停&lt;/strong&gt; 一段时间：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;main start...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;thread run...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;thread end.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;main end...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="线程的优先级"&gt;线程的优先级
&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPriority&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//默认为5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;JVM自动把1（低）~10（高）的优先级映射到操作系统实际优先级上（不同操作系统有不同的优先级数量）。优先级高的线程被操作系统调度的优先级较高，操作系统对高优先级线程可能调度更频繁，但我们 &lt;strong&gt;决不能通过设置优先级来确保高优先级的线程一定会先执行&lt;/strong&gt; 。cpu比较忙时，优先级高的线程获取更多的时间片，cpu比较闲时，优先级设置基本没用&lt;/p&gt;
&lt;p&gt;&lt;code&gt;yield()&lt;/code&gt; 方法会让运行中的线程切换到就绪状态，重新争抢cpu的时间片，争抢时是否获取到时间片看cpu的分配。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;native&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Runnable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(;;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;---- 1&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Runnable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(;;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34; ---- 2&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;t1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;t2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// 运行结果
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;11:49:15.796 &lt;span class="o"&gt;[&lt;/span&gt;t1&lt;span class="o"&gt;]&lt;/span&gt; INFO thread.TestYield - ---- 1&amp;gt;129504
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;11:49:15.796 &lt;span class="o"&gt;[&lt;/span&gt;t1&lt;span class="o"&gt;]&lt;/span&gt; INFO thread.TestYield - ---- 1&amp;gt;129505
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;11:49:15.796 &lt;span class="o"&gt;[&lt;/span&gt;t1&lt;span class="o"&gt;]&lt;/span&gt; INFO thread.TestYield - ---- 1&amp;gt;129506
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;11:49:15.796 &lt;span class="o"&gt;[&lt;/span&gt;t1&lt;span class="o"&gt;]&lt;/span&gt; INFO thread.TestYield - ---- 1&amp;gt;129507
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;11:49:15.796 &lt;span class="o"&gt;[&lt;/span&gt;t1&lt;span class="o"&gt;]&lt;/span&gt; INFO thread.TestYield - ---- 1&amp;gt;129508
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;11:49:15.796 &lt;span class="o"&gt;[&lt;/span&gt;t1&lt;span class="o"&gt;]&lt;/span&gt; INFO thread.TestYield - ---- 1&amp;gt;129509
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;11:49:15.796 &lt;span class="o"&gt;[&lt;/span&gt;t1&lt;span class="o"&gt;]&lt;/span&gt; INFO thread.TestYield - ---- 1&amp;gt;129510
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;11:49:15.796 &lt;span class="o"&gt;[&lt;/span&gt;t1&lt;span class="o"&gt;]&lt;/span&gt; INFO thread.TestYield - ---- 1&amp;gt;129511
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;11:49:15.796 &lt;span class="o"&gt;[&lt;/span&gt;t1&lt;span class="o"&gt;]&lt;/span&gt; INFO thread.TestYield - ---- 1&amp;gt;129512
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;11:49:15.798 &lt;span class="o"&gt;[&lt;/span&gt;t2&lt;span class="o"&gt;]&lt;/span&gt; INFO thread.TestYield - ---- 2&amp;gt;293
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;11:49:15.798 &lt;span class="o"&gt;[&lt;/span&gt;t1&lt;span class="o"&gt;]&lt;/span&gt; INFO thread.TestYield - ---- 1&amp;gt;129513
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;11:49:15.798 &lt;span class="o"&gt;[&lt;/span&gt;t1&lt;span class="o"&gt;]&lt;/span&gt; INFO thread.TestYield - ---- 1&amp;gt;129514
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;11:49:15.798 &lt;span class="o"&gt;[&lt;/span&gt;t1&lt;span class="o"&gt;]&lt;/span&gt; INFO thread.TestYield - ---- 1&amp;gt;129515
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;11:49:15.798 &lt;span class="o"&gt;[&lt;/span&gt;t1&lt;span class="o"&gt;]&lt;/span&gt; INFO thread.TestYield - ---- 1&amp;gt;129516
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;11:49:15.798 &lt;span class="o"&gt;[&lt;/span&gt;t1&lt;span class="o"&gt;]&lt;/span&gt; INFO thread.TestYield - ---- 1&amp;gt;129517
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;11:49:15.798 &lt;span class="o"&gt;[&lt;/span&gt;t1&lt;span class="o"&gt;]&lt;/span&gt; INFO thread.TestYield - ---- 1&amp;gt;129518
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如上述结果所示，t2线程每次执行时进行了yield()，线程1执行的机会明显比线程2要多。&lt;/p&gt;
&lt;h4 id="小结"&gt;小结
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;Java用&lt;code&gt;Thread&lt;/code&gt;对象表示一个线程，通过调用&lt;code&gt;start()&lt;/code&gt;启动一个新线程&lt;/li&gt;
&lt;li&gt;一个线程对象只能调用一次&lt;code&gt;start()&lt;/code&gt;方法&lt;/li&gt;
&lt;li&gt;线程的执行代码写在&lt;code&gt;run()&lt;/code&gt;方法中&lt;/li&gt;
&lt;li&gt;线程调度由操作系统决定，程序本身无法决定调度顺序&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Thread.sleep()&lt;/code&gt;可以把当前线程暂停一段时间&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="线程的阻塞"&gt;线程的阻塞
&lt;/h3&gt;&lt;p&gt;使得线程阻塞的方式有下面几种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;BIO阻塞，即使用了阻塞式的io流&lt;/li&gt;
&lt;li&gt;sleep(long time) 让线程休眠进入阻塞状态&lt;/li&gt;
&lt;li&gt;a.join() 调用该方法的线程进入阻塞，等待a线程执行完恢复运行&lt;/li&gt;
&lt;li&gt;sychronized或ReentrantLock 造成线程未获得锁进入阻塞状态&lt;/li&gt;
&lt;li&gt;获得锁之后调用wait()方法 也会让线程进入阻塞状态&lt;/li&gt;
&lt;li&gt;LockSupport.park() 让线程进入阻塞状态&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="threadsleep"&gt;&lt;code&gt;Thread.sleep()&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;使线程休眠，会将运行中的线程进入阻塞状态。当休眠时间结束后，重新争抢cpu的时间片继续运行&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 方法的定义 native方法&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;native&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;throws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 休眠2秒&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 该方法会抛出 InterruptedException异常 即休眠过程中可被中断，被中断后抛出异常&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InterruptedException异常&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 使用TimeUnit的api可替代 Thread.sleep &lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TimeUnit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="threadjoin"&gt;&lt;code&gt;Thread.join()&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;一个线程还可以等待另一个线程直到其运行结束。例如，&lt;code&gt;main&lt;/code&gt;线程在启动&lt;code&gt;t&lt;/code&gt;线程后，可以通过&lt;code&gt;t.join()&lt;/code&gt;等待&lt;code&gt;t&lt;/code&gt;线程结束后再继续运行：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;throws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;span class="w"&gt;	&lt;/span&gt;&lt;span class="c1"&gt;//java8 lambda方式&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;start&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 启动t线程&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 此处main线程会等待t结束&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;end&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;当&lt;code&gt;main&lt;/code&gt;线程对线程对象&lt;code&gt;t&lt;/code&gt;调用&lt;code&gt;join()&lt;/code&gt;方法时，主线程将等待变量&lt;code&gt;t&lt;/code&gt;表示的线程运行结束，即&lt;code&gt;join&lt;/code&gt;就是指等待该线程结束， &lt;strong&gt;然后才继续往下执行自身线程&lt;/strong&gt; 。所以，上述代码打印顺序可以肯定是&lt;code&gt;main&lt;/code&gt;线程先打印&lt;code&gt;start&lt;/code&gt;，&lt;code&gt;t&lt;/code&gt;线程再打印&lt;code&gt;hello&lt;/code&gt;，&lt;code&gt;main&lt;/code&gt;线程最后再打印&lt;code&gt;end&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;如果&lt;code&gt;t&lt;/code&gt;线程已经结束，对实例&lt;code&gt;t&lt;/code&gt;调用&lt;code&gt;join()&lt;/code&gt;会立刻返回。此外，&lt;code&gt;join(long)&lt;/code&gt;的重载方法也可以指定一个等待时间，超过等待时间后就不再继续等待。&lt;/p&gt;
&lt;h4 id="小结-1"&gt;小结
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;线程阻塞的常见方式&lt;/strong&gt;：BIO阻塞、&lt;code&gt;sleep()&lt;/code&gt;、&lt;code&gt;join()&lt;/code&gt;、未获取锁（&lt;code&gt;synchronized&lt;/code&gt;/&lt;code&gt;ReentrantLock&lt;/code&gt;）、&lt;code&gt;wait()&lt;/code&gt;、&lt;code&gt;LockSupport.park()&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sleep()&lt;/code&gt; ：让线程休眠指定时间，可被中断，推荐用&lt;code&gt;TimeUnit&lt;/code&gt;增强可读性。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;join()&lt;/code&gt; ：让当前线程等待目标线程执行完毕，常用于控制线程执行顺序。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;阻塞与恢复&lt;/strong&gt;：线程进入阻塞后，需等待特定条件（如时间结束、锁释放、目标线程完成）才能恢复运行。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="中断线程"&gt;中断线程
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://liaoxuefeng.com/books/java/threading/interrupt/index.html" target="_blank" rel="noopener"
 &gt;中断线程 - Java教程 - 廖雪峰的官方网站&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;如果线程需要执行一个长时间任务，就可能需要能中断线程。中断线程就是其他线程给该线程发一个信号，该线程收到信号后结束执行&lt;code&gt;run()&lt;/code&gt;方法，使得自身线程能立刻结束运行。&lt;/p&gt;
&lt;p&gt;例如，从网络下载一个100M的文件，如果网速很慢，用户等得不耐烦，就可能在下载过程中点“取消”，这时，程序就需要中断下载线程的执行。&lt;/p&gt;
&lt;h4 id="threadinterrupt"&gt;&lt;code&gt;Thread.interrupt&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;中断一个线程非常简单，只需要在其他线程中对目标线程调用&lt;code&gt;interrupt()&lt;/code&gt;方法，目标线程需要反复检测自身状态是否是interrupted状态， &lt;strong&gt;如果是，就立刻结束运行&lt;/strong&gt; 。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;throws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MyThread&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 暂停1毫秒&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;interrupt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 中断t线程&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 等待t线程结束&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;end&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyThread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;isInterrupted&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34; hello!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;上述代码，&lt;code&gt;main&lt;/code&gt;线程通过调用&lt;code&gt;t.interrupt()&lt;/code&gt;方法中断&lt;code&gt;t&lt;/code&gt;线程，但是要注意，&lt;code&gt;interrupt()&lt;/code&gt;方法 &lt;strong&gt;仅仅向&lt;code&gt;t&lt;/code&gt;线程发出了“中断请求”&lt;/strong&gt; ，至于&lt;code&gt;t&lt;/code&gt;线程 &lt;strong&gt;是否能立刻响应，要看具体代码&lt;/strong&gt; 。而&lt;code&gt;t&lt;/code&gt;线程的&lt;code&gt;while&lt;/code&gt;循环会检测&lt;code&gt;isInterrupted()&lt;/code&gt;，所以上述代码能正确响应&lt;code&gt;interrupt()&lt;/code&gt;请求，使得自身立刻结束运行&lt;code&gt;run()&lt;/code&gt;方法。&lt;/p&gt;
&lt;p&gt;如果线程处于等待状态，例如，&lt;code&gt;t.join()&lt;/code&gt;会让&lt;code&gt;main&lt;/code&gt;线程进入等待状态，此时，如果对&lt;code&gt;main&lt;/code&gt;线程调用&lt;code&gt;interrupt()&lt;/code&gt;， &lt;strong&gt;&lt;code&gt;join()&lt;/code&gt;方法会立刻抛出&lt;code&gt;InterruptedException&lt;/code&gt;&lt;/strong&gt; ，因此，目标线程只要捕获到&lt;code&gt;join()&lt;/code&gt;方法抛出的&lt;code&gt;InterruptedException&lt;/code&gt;，就说明有其他线程对其调用了&lt;code&gt;interrupt()&lt;/code&gt;方法，通常情况下该线程应该立刻结束运行。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;throws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MyThread&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;interrupt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 中断t线程&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 等待t线程结束&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;end&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyThread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HelloThread&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 启动hello线程&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 等待hello线程结束&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;interrupted!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;interrupt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HelloThread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isInterrupted&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34; hello!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;main&lt;/code&gt;线程通过调用&lt;code&gt;t.interrupt()&lt;/code&gt;从而通知&lt;code&gt;t&lt;/code&gt;线程中断&lt;/li&gt;
&lt;li&gt;此时&lt;code&gt;t&lt;/code&gt;线程正位于&lt;code&gt;hello.join()&lt;/code&gt;的等待中，此方法会立刻结束等待并抛出&lt;code&gt;InterruptedException&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;在&lt;code&gt;t&lt;/code&gt;线程中捕获了&lt;code&gt;InterruptedException&lt;/code&gt;，准备结束该线程&lt;/li&gt;
&lt;li&gt;&lt;code&gt;t&lt;/code&gt;线程结束前，对&lt;code&gt;hello&lt;/code&gt;线程也进行了&lt;code&gt;interrupt()&lt;/code&gt;调用通知其中断&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="running标志位"&gt;&lt;code&gt;running&lt;/code&gt;标志位
&lt;/h4&gt;&lt;p&gt;另一个常用的中断线程的方法是设置标志位。我们通常会用一个&lt;code&gt;running&lt;/code&gt;标志位来标识线程是否应该继续运行，在外部线程中，通过把&lt;code&gt;HelloThread.running&lt;/code&gt;置为&lt;code&gt;false&lt;/code&gt;，就可以让线程结束：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;throws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HelloThread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HelloThread&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;running&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 标志位置为false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HelloThread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;volatile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;boolean&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34; hello!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;end!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;注意到&lt;code&gt;HelloThread&lt;/code&gt;的标志位&lt;code&gt;boolean running&lt;/code&gt;是一个 &lt;strong&gt;线程间共享的变量&lt;/strong&gt; 。线程间共享变量需要使用&lt;code&gt;volatile&lt;/code&gt;关键字标记，确保 &lt;strong&gt;每个线程都能读取到更新后的变量值&lt;/strong&gt; 。&lt;/p&gt;
&lt;h4 id="volatile-的用处"&gt;&lt;code&gt;volatile&lt;/code&gt; 的用处
&lt;/h4&gt;&lt;p&gt;为什么要对线程间共享的变量用关键字&lt;code&gt;volatile&lt;/code&gt;声明？这涉及到Java的内存模型。在Java虚拟机中，变量的值保存在主内存中，但是，当线程访问变量时，它会先获取一个副本，并保存在自己的工作内存中。如果线程修改了变量的值，虚拟机会在某个时刻把修改后的值回写到主内存，但是， &lt;strong&gt;这个时间是不确定的&lt;/strong&gt; ！&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 这图画得真有水平罢 &lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;┌&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;┐&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Memory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;┌───────┐┌───────┐┌───────┐&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;││&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;││&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;└───────┘└───────┘└───────┘&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;▲&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;▲&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─│─│─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─│─│─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;┌&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;┼&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;┼&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;┐&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;┌&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;┼&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;┼&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;┐&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;▼&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;▼&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;┌───────┐&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;┌───────┐&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;└───────┘&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;└───────┘&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;└&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;┘&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;└&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;─&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;┘&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这会导致如果一个线程更新了某个变量，另一个线程读取的值可能还是更新前的。&lt;/p&gt;
&lt;p&gt;例如，主内存的变量&lt;code&gt;a = true&lt;/code&gt;，线程1执行&lt;code&gt;a = false&lt;/code&gt;时，它在此刻仅仅是把变量&lt;code&gt;a&lt;/code&gt;的副本变成了&lt;code&gt;false&lt;/code&gt;，主内存的变量&lt;code&gt;a&lt;/code&gt;还是&lt;code&gt;true&lt;/code&gt;，在JVM把修改后的&lt;code&gt;a&lt;/code&gt;回写到主内存之前，其他线程读取到的&lt;code&gt;a&lt;/code&gt;的值仍然是&lt;code&gt;true&lt;/code&gt;，这就造成了 &lt;strong&gt;多线程之间共享的变量不一致&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;因此，&lt;code&gt;volatile&lt;/code&gt;关键字的目的是告诉虚拟机：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每次访问变量时，总是获取主内存的最新值；&lt;/li&gt;
&lt;li&gt;每次修改变量后，立刻回写到主内存。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;volatile&lt;/code&gt;关键字解决的是可见性问题：当一个线程 &lt;strong&gt;修改了某个共享变量的值，其他线程能够立刻看到修改后的值&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;如果我们去掉&lt;code&gt;volatile&lt;/code&gt;关键字，运行上述程序，发现效果和带&lt;code&gt;volatile&lt;/code&gt;差不多，这是因为在x86的架构下，JVM回写主内存的速度非常快，但是，换成ARM的架构，就会有显著的延迟。&lt;/p&gt;
&lt;h4 id="小结-2"&gt;小结
&lt;/h4&gt;&lt;p&gt;对目标线程调用&lt;code&gt;interrupt()&lt;/code&gt;方法可以请求中断一个线程，目标线程通过检测&lt;code&gt;isInterrupted()&lt;/code&gt;标志获取自身是否已中断。如果目标线程处于等待状态，该线程会捕获到&lt;code&gt;InterruptedException&lt;/code&gt;；&lt;/p&gt;
&lt;p&gt;目标线程检测到&lt;code&gt;isInterrupted()&lt;/code&gt;为&lt;code&gt;true&lt;/code&gt;或者捕获了&lt;code&gt;InterruptedException&lt;/code&gt;都应该立刻结束自身线程；&lt;/p&gt;
&lt;p&gt;通过标志位判断需要正确使用&lt;code&gt;volatile&lt;/code&gt;关键字；&lt;/p&gt;
&lt;p&gt;&lt;code&gt;volatile&lt;/code&gt;关键字解决了共享变量在线程间的可见性问题。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="线程状态"&gt;线程状态
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://segmentfault.com/a/1190000023960592#item-2" target="_blank" rel="noopener"
 &gt;万字图解Java多线程 - 个人文章 - SegmentFault 思否&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://liaoxuefeng.com/books/java/threading/state/index.html" target="_blank" rel="noopener"
 &gt;线程的状态 - Java教程 - 廖雪峰的官方网站&lt;/a&gt;&lt;/p&gt;
&lt;h4 id="系统---五种状态"&gt;系统 - 五种状态
&lt;/h4&gt;&lt;p&gt;线程的状态可从 操作系统层面分为五种状态&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/java-multithreading/thread-status-1.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;初始状态：创建线程对象时的状态&lt;/li&gt;
&lt;li&gt;可运行状态(就绪状态)：调用 &lt;code&gt;start()&lt;/code&gt; 方法后进入就绪状态，也就是准备好被cpu调度执行&lt;/li&gt;
&lt;li&gt;运行状态：线程获取到cpu的时间片， 执行 &lt;code&gt;run()&lt;/code&gt; 方法的逻辑&lt;/li&gt;
&lt;li&gt;阻塞状态: 线程被阻塞，放弃cpu的时间片，等待解除阻塞重新回到就绪状态争抢时间片&lt;/li&gt;
&lt;li&gt;终止状态: 线程执行完成或抛出异常后的状态&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="java---六种状态"&gt;Java - 六种状态
&lt;/h4&gt;&lt;p&gt;在Java程序中，一个线程对象只能调用一次&lt;code&gt;start()&lt;/code&gt;方法启动新线程，并在新线程中执行&lt;code&gt;run()&lt;/code&gt;方法。一旦&lt;code&gt;run()&lt;/code&gt;方法执行完毕，线程就结束了。因此，Java线程的状态有以下几种：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/java-multithreading/thread-status-2.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;NEW 线程对象被创建&lt;/li&gt;
&lt;li&gt;Runnable 线程调用了 &lt;code&gt;start()&lt;/code&gt; 方法后进入该状态，该状态包含了三种情况
&lt;ol&gt;
&lt;li&gt;就绪状态 :等待cpu分配时间片&lt;/li&gt;
&lt;li&gt;运行状态:进入Runnable方法执行任务&lt;/li&gt;
&lt;li&gt;阻塞状态:BIO 执行阻塞式io流时的状态&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Blocked 没获取到锁时的阻塞状态(同步锁章节会细说)&lt;/li&gt;
&lt;li&gt;WAITING 调用 &lt;code&gt;wait()&lt;/code&gt; &lt;code&gt;join()&lt;/code&gt; 等方法后的状态&lt;/li&gt;
&lt;li&gt;TIMED_WAITING 调用 &lt;code&gt;sleep(time)&lt;/code&gt; &lt;code&gt;wait(time)&lt;/code&gt; &lt;code&gt;join(time)&lt;/code&gt; 等方法后的状态&lt;/li&gt;
&lt;li&gt;TERMINATED 线程执行完成或抛出异常后的状态&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/java-multithreading/thread-status-3.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;当线程启动后，它可以在&lt;code&gt;Runnable&lt;/code&gt;、&lt;code&gt;Blocked&lt;/code&gt;、&lt;code&gt;Waiting&lt;/code&gt;和&lt;code&gt;Timed Waiting&lt;/code&gt;这几个状态之间切换，直到最后变成&lt;code&gt;Terminated&lt;/code&gt;状态，线程终止。&lt;/p&gt;
&lt;p&gt;线程终止的原因有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;线程正常终止：&lt;code&gt;run()&lt;/code&gt;方法执行到&lt;code&gt;return&lt;/code&gt;语句返回；&lt;/li&gt;
&lt;li&gt;线程意外终止：&lt;code&gt;run()&lt;/code&gt;方法因为未捕获的异常导致线程终止；&lt;/li&gt;
&lt;li&gt;对某个线程的&lt;code&gt;Thread&lt;/code&gt;实例调用&lt;code&gt;stop()&lt;/code&gt;方法强制终止（强烈不推荐使用）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="thread类中的核心方法"&gt;Thread类中的核心方法
&lt;/h4&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;方法名称&lt;/th&gt;
					&lt;th&gt;是否static&lt;/th&gt;
					&lt;th&gt;方法说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;start()&lt;/td&gt;
					&lt;td&gt;否&lt;/td&gt;
					&lt;td&gt;让线程启动，进入就绪状态,等待cpu分配时间片&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;run()&lt;/td&gt;
					&lt;td&gt;否&lt;/td&gt;
					&lt;td&gt;重写Runnable接口的方法,线程获取到cpu时间片时执行的具体逻辑&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;yield()&lt;/td&gt;
					&lt;td&gt;是&lt;/td&gt;
					&lt;td&gt;线程的礼让，使得获取到cpu时间片的线程进入就绪状态，重新争抢时间片&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;sleep(time)&lt;/td&gt;
					&lt;td&gt;是&lt;/td&gt;
					&lt;td&gt;线程休眠固定时间，进入阻塞状态，休眠时间完成后重新争抢时间片,休眠可被打断&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;join()/join(time)&lt;/td&gt;
					&lt;td&gt;否&lt;/td&gt;
					&lt;td&gt;调用线程对象的join方法，调用者线程进入阻塞,等待线程对象执行完或者到达指定时间才恢复，重新争抢时间片&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;isInterrupted()&lt;/td&gt;
					&lt;td&gt;否&lt;/td&gt;
					&lt;td&gt;获取线程的打断标记，true:被打断，false：没有被打断。调用后不会修改打断标记&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;interrupt()&lt;/td&gt;
					&lt;td&gt;否&lt;/td&gt;
					&lt;td&gt;打断线程，抛出InterruptedException异常的方法均可被打断，但是打断后不会修改打断标记，正常执行的线程被打断后会修改打断标记&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;interrupted()&lt;/td&gt;
					&lt;td&gt;否&lt;/td&gt;
					&lt;td&gt;获取线程的打断标记。调用后会清空打断标记&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;stop()&lt;/td&gt;
					&lt;td&gt;否&lt;/td&gt;
					&lt;td&gt;停止线程运行 不推荐&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;suspend()&lt;/td&gt;
					&lt;td&gt;否&lt;/td&gt;
					&lt;td&gt;挂起线程 不推荐&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;resume()&lt;/td&gt;
					&lt;td&gt;否&lt;/td&gt;
					&lt;td&gt;恢复线程运行 不推荐&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;currentThread()&lt;/td&gt;
					&lt;td&gt;是&lt;/td&gt;
					&lt;td&gt;获取当前线程&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Object中与线程相关方法&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;方法名称&lt;/th&gt;
					&lt;th&gt;方法说明&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;wait()/wait(long timeout)&lt;/td&gt;
					&lt;td&gt;获取到锁的线程进入阻塞状态&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;notify()&lt;/td&gt;
					&lt;td&gt;随机唤醒被wait()的一个线程&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;notifyAll();&lt;/td&gt;
					&lt;td&gt;唤醒被wait()的所有线程，重新争抢时间片&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="守护线程"&gt;守护线程
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://liaoxuefeng.com/books/java/threading/daemon/index.html" target="_blank" rel="noopener"
 &gt;守护线程 - Java教程 - 廖雪峰的官方网站&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Java程序入口就是由JVM启动&lt;code&gt;main&lt;/code&gt;线程，&lt;code&gt;main&lt;/code&gt;线程又可以启动其他线程。当所有线程都运行结束时，JVM退出，进程结束。&lt;/p&gt;
&lt;p&gt;如果有一个线程没有退出，JVM进程就不会退出。所以，必须保证所有线程都能及时结束。&lt;/p&gt;
&lt;p&gt;但是有一种线程的目的就是无限循环，例如，一个定时触发任务的线程：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TimerThread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LocalTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果这个线程不结束，JVM进程就无法结束。问题是，由谁负责结束这个线程？&lt;/p&gt;
&lt;p&gt;然而这类线程经常没有负责人来负责结束它们。但是，当其他线程结束时，JVM进程又必须要结束，怎么办？&lt;/p&gt;
&lt;p&gt;答案是使用守护线程（Daemon Thread）。&lt;/p&gt;
&lt;p&gt;守护线程是指为其他线程服务的线程。在JVM中， &lt;strong&gt;所有非守护线程都执行完毕后&lt;/strong&gt; ，无论有没有守护线程，虚拟机都会自动退出。&lt;/p&gt;
&lt;p&gt;因此，JVM退出时，不必关心守护线程是否已结束。&lt;/p&gt;
&lt;p&gt;如何创建守护线程呢？方法和普通线程一样，只是在调用&lt;code&gt;start()&lt;/code&gt;方法前， &lt;strong&gt;调用&lt;code&gt;setDaemon(true)&lt;/code&gt;把该线程标记为守护线程&lt;/strong&gt; ：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MyThread&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDaemon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;在守护线程中，编写代码要注意： &lt;strong&gt;守护线程不能持有任何需要关闭的资源&lt;/strong&gt; ，例如打开文件等，因为虚拟机退出时，守护线程没有任何机会来关闭文件，这会导致数据丢失。&lt;/p&gt;
&lt;h4 id="小结-3"&gt;小结
&lt;/h4&gt;&lt;p&gt;守护线程是为其他线程服务的线程；&lt;/p&gt;
&lt;p&gt;所有非守护线程都执行完毕后，虚拟机退出，守护线程随之结束；&lt;/p&gt;
&lt;p&gt;守护线程不能持有需要关闭的资源（如打开文件等）。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="线程同步"&gt;线程同步
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://liaoxuefeng.com/books/java/threading/synchronize/index.html" target="_blank" rel="noopener"
 &gt;线程同步 - Java教程 - 廖雪峰的官方网站&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;当多个线程同时运行时，线程的调度由操作系统决定，程序本身无法决定。因此，任何一个线程都有可能在任何指令处被操作系统暂停，然后在某个时间段后继续执行。&lt;/p&gt;
&lt;p&gt;这个时候，有个单线程模型下不存在的问题就来了：如果多个线程同时读写共享变量，会出现数据不一致的问题。&lt;/p&gt;
&lt;p&gt;我们来看一个例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 多线程&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;throws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AddThread&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DecThread&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AddThread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DecThread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;上面的代码很简单，两个线程同时对一个&lt;code&gt;int&lt;/code&gt;变量进行操作，一个加10000次，一个减10000次，最后结果应该是0，但是，每次运行，结果实际上都是不一样的。&lt;/p&gt;
&lt;p&gt;这是因为对变量进行读取和写入时，结果要正确， &lt;strong&gt;必须保证是原子操作&lt;/strong&gt; 。原子操作是指不能被中断的一个或一系列操作。&lt;/p&gt;
&lt;p&gt;例如，对于语句：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;看上去是一行语句，实际上对应了3条指令：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ILOAD&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;IADD&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ISTORE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;我们假设&lt;code&gt;n&lt;/code&gt;的值是&lt;code&gt;100&lt;/code&gt;，如果两个线程同时执行&lt;code&gt;n = n + 1&lt;/code&gt;，得到的结果很可能不是&lt;code&gt;102&lt;/code&gt;，而是&lt;code&gt;101&lt;/code&gt;，原因在于：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;┌───────┐&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;┌───────┐&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="n"&gt;Thread1&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="n"&gt;Thread2&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;└───┬───┘&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;└───┬───┘&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="n"&gt;ILOAD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="n"&gt;ILOAD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="n"&gt;IADD&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="n"&gt;ISTORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;101&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="n"&gt;IADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="n"&gt;ISTORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;101&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;▼&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;▼&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果线程1在执行&lt;code&gt;ILOAD&lt;/code&gt;后被操作系统中断，此刻如果线程2被调度执行，它执行&lt;code&gt;ILOAD&lt;/code&gt;后获取的值仍然是&lt;code&gt;100&lt;/code&gt;，最终结果被两个线程的&lt;code&gt;ISTORE&lt;/code&gt;写入后变成了&lt;code&gt;101&lt;/code&gt;，而不是期待的&lt;code&gt;102&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这说明多线程模型下，要保证逻辑正确，对共享变量进行读写时， &lt;strong&gt;必须保证一组指令以原子方式执行：即某一个线程执行时，其他线程必须等待&lt;/strong&gt; ：&lt;/p&gt;
&lt;h4 id="synchronized-同步锁"&gt;&lt;code&gt;synchronized 同步锁&lt;/code&gt;
&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;┌───────┐&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;┌───────┐&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="n"&gt;Thread1&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="n"&gt;Thread2&lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;└───┬───┘&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;└───┬───┘&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="n"&gt;ILOAD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="n"&gt;IADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="n"&gt;ISTORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;101&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unlock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="n"&gt;ILOAD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;101&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="n"&gt;IADD&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="n"&gt;ISTORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;102&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unlock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;▼&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;▼&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;通过加锁和解锁的操作，就能保证3条指令总是在一个线程执行期间，不会有其他线程会进入此指令区间。即使在执行期线程被操作系统中断执行，其他线程也会因为无法获得锁导致无法进入此指令区间。只有执行线程将锁释放后，其他线程才有机会获得锁并执行。这种加锁和解锁之间的代码块我们称之为临界区(Critical Section)，任何时候临界区最多只有一个线程能执行。&lt;/p&gt;
&lt;p&gt;可见， &lt;strong&gt;保证一段代码的原子性就是通过加锁和解锁实现的&lt;/strong&gt; 。Java程序使用&lt;code&gt;synchronized&lt;/code&gt;关键字对一个对象进行加锁：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;synchronized&lt;/code&gt;保证了代码块在 &lt;strong&gt;任意时刻最多只有一个线程能执行&lt;/strong&gt; 。我们把上面的代码用&lt;code&gt;synchronized&lt;/code&gt;改写如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 多线程&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;throws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AddThread&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DecThread&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AddThread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DecThread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;注意到代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 获取锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 释放锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;它表示用&lt;code&gt;Counter.lock&lt;/code&gt;实例作为锁，两个线程在执行各自的&lt;code&gt;synchronized(Counter.lock) { ... }&lt;/code&gt;代码块时，必须先获得锁，才能进入代码块进行。执行结束后，在&lt;code&gt;synchronized&lt;/code&gt;语句块结束会自动释放锁。这样一来，对&lt;code&gt;Counter.count&lt;/code&gt;变量进行读写就不可能同时进行。上述代码无论运行多少次，最终结果都是0。&lt;/p&gt;
&lt;p&gt;使用&lt;code&gt;synchronized&lt;/code&gt;解决了多线程同步访问共享变量的正确性问题。但是，它的缺点是带来了性能下降。因为&lt;code&gt;synchronized&lt;/code&gt;代码块无法并发执行。此外，加锁和解锁需要消耗一定的时间，所以，&lt;code&gt;synchronized&lt;/code&gt;会降低程序的执行效率。&lt;/p&gt;
&lt;p&gt;我们来概括一下如何使用&lt;code&gt;synchronized&lt;/code&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;找出修改共享变量的线程代码块；&lt;/li&gt;
&lt;li&gt;选择一个共享实例作为锁；&lt;/li&gt;
&lt;li&gt;使用&lt;code&gt;synchronized(lockObject) { ... }&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在使用&lt;code&gt;synchronized&lt;/code&gt;的时候， &lt;strong&gt;不必担心抛出异常&lt;/strong&gt; 。因为无论是否有异常，都会在&lt;code&gt;synchronized&lt;/code&gt;结束处正确释放锁：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;throw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RuntimeException&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 无论有无异常，都会在此释放锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;此外，多个线程各自都可以同时获得锁：因为JVM只保证同一个锁在任意时刻只能被一个线程获取， &lt;strong&gt;但两个不同的锁在同一时刻可以被两个线程分别获取&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;因此，使用&lt;code&gt;synchronized&lt;/code&gt;的时候， &lt;strong&gt;获取到的是哪个锁非常重要&lt;/strong&gt; 。锁对象如果不对，代码逻辑就不对。&lt;/p&gt;
&lt;p&gt;下面是应用了两个不同的锁来提升效率的示例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;span class="lnt"&gt;53
&lt;/span&gt;&lt;span class="lnt"&gt;54
&lt;/span&gt;&lt;span class="lnt"&gt;55
&lt;/span&gt;&lt;span class="lnt"&gt;56
&lt;/span&gt;&lt;span class="lnt"&gt;57
&lt;/span&gt;&lt;span class="lnt"&gt;58
&lt;/span&gt;&lt;span class="lnt"&gt;59
&lt;/span&gt;&lt;span class="lnt"&gt;60
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;throws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AddStudentThread&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DecStudentThread&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AddTeacherThread&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DecTeacherThread&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;studentCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;teacherCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lockStudent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lockTeacher&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;studentCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;teacherCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AddStudentThread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lockStudent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;studentCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DecStudentThread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lockStudent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;studentCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AddTeacherThread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lockTeacher&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;teacherCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DecTeacherThread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lockTeacher&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;teacherCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="不需要-synchronized-的操作"&gt;不需要 &lt;code&gt;synchronized&lt;/code&gt; 的操作
&lt;/h4&gt;&lt;p&gt;JVM规范定义了几种原子操作：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基本类型（&lt;code&gt;long&lt;/code&gt;和&lt;code&gt;double&lt;/code&gt;除外）赋值，例如：&lt;code&gt;int n = m&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;引用类型赋值，例如：&lt;code&gt;List&amp;lt;String&amp;gt; list = anotherList&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;long&lt;/code&gt;和&lt;code&gt;double&lt;/code&gt;是64位数据，JVM没有明确规定64位赋值操作是不是一个原子操作，不过在x64平台的JVM是把&lt;code&gt;long&lt;/code&gt;和&lt;code&gt;double&lt;/code&gt;的赋值作为原子操作实现的。&lt;/p&gt;
&lt;p&gt;单条原子操作的语句不需要同步。例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;就不需要同步。&lt;/p&gt;
&lt;p&gt;对引用也是类似。例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;上述 &lt;strong&gt;赋值语句&lt;/strong&gt; 并不需要同步。&lt;/p&gt;
&lt;p&gt;但是，如果是 &lt;strong&gt;多行赋值语句，就必须保证是同步操作&lt;/strong&gt; ，例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Point&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;上面的读写，即( set(), get() )需要同步，在读的时候若是不同步，会造成程序的逻辑错误：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;2&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;假定当前坐标是&lt;code&gt;(100, 200)&lt;/code&gt;，那么当设置新坐标为&lt;code&gt;(110, 220)&lt;/code&gt;时，上述未同步的多线程读到的值可能有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(100, 200)：x，y更新前；&lt;/li&gt;
&lt;li&gt;(110, 200)：x更新后，y更新前；&lt;/li&gt;
&lt;li&gt;(110, 220)：x，y更新后。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果读取到&lt;code&gt;(110, 200)&lt;/code&gt;，即读到了更新后的x，更新前的y，无法保证读取的多个变量状态保持一致。&lt;/p&gt;
&lt;p&gt;有些时候，通过一些巧妙的转换，可以把非原子操作变为原子操作。例如，上述代码如果改造成：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Point&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;就不再需要写同步，因为&lt;code&gt;this.ps = ps&lt;/code&gt;是引用赋值的原子操作。而语句：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这里的&lt;code&gt;ps&lt;/code&gt;是方法内部定义的局部变量，每个线程都会有各自的局部变量，互不影响，并且互不可见，并不需要同步。&lt;/p&gt;
&lt;p&gt;不过要注意，读方法在复制&lt;code&gt;int[]&lt;/code&gt;数组的过程中仍然需要同步。&lt;/p&gt;
&lt;h4 id="不可变对象无需同步"&gt;不可变对象无需同步
&lt;/h4&gt;&lt;p&gt;不可变对象是指&lt;strong&gt;创建后状态不能被修改的对象&lt;/strong&gt;。在 Java 中，典型的不可变对象包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;String&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;List.of()&lt;/code&gt; 创建的不可变集合（Java 9+）&lt;/li&gt;
&lt;li&gt;基本类型的包装类（如 &lt;code&gt;Integer&lt;/code&gt;, &lt;code&gt;Long&lt;/code&gt; 等）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果多线程读写的是一个不可变对象，那么无需同步，因为不会修改对象的状态：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;names&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;names&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;注意到&lt;code&gt;set()&lt;/code&gt;方法内部创建了一个不可变&lt;code&gt;List&lt;/code&gt;，这个&lt;code&gt;List&lt;/code&gt;包含的对象也是不可变对象&lt;code&gt;String&lt;/code&gt;，因此，整个&lt;code&gt;List&amp;lt;String&amp;gt;&lt;/code&gt;对象都是不可变的，因此读写均无需同步。&lt;/p&gt;
&lt;p&gt;分析变量是否能被多线程访问时，首先要理清概念，多线程同时执行的是方法。对于下面这个例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;names&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StatusRecord&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StatusRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;names&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果有A、B两个线程，同时执行是指：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可能同时执行set()；&lt;/li&gt;
&lt;li&gt;可能同时执行get()；&lt;/li&gt;
&lt;li&gt;可能A执行set()，同时B执行get()。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;类的成员变量&lt;code&gt;names&lt;/code&gt;、&lt;code&gt;x&lt;/code&gt;、&lt;code&gt;y&lt;/code&gt;显然能被多线程同时读写，但局部变量（包括方法参数）如果没有“逃逸”，那么只有当前线程可见。局部变量&lt;code&gt;step&lt;/code&gt;仅在&lt;code&gt;set()&lt;/code&gt;方法内部使用，因此每个线程同时执行set时都有一份独立的step存储在线程的栈上，互不影响，&lt;/p&gt;
&lt;p&gt;局部变量&lt;code&gt;ns&lt;/code&gt;虽然每个线程也各有一份，但后续赋值&lt;code&gt; this.names = ns&lt;/code&gt; 对其他线程就变成可见了。对&lt;code&gt;set()&lt;/code&gt;方法同步时，如果要最小化&lt;code&gt;synchronized&lt;/code&gt;代码块，可以改写如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 局部变量其他线程不可见:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;names&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ns&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;因此，深入理解多线程还需理解变量在栈上的存储方式，基本类型和引用类型的存储方式也不同。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th style="text-align: left"&gt;场景&lt;/th&gt;
					&lt;th style="text-align: left"&gt;是否需要同步&lt;/th&gt;
					&lt;th style="text-align: left"&gt;原因&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;不可变对象（如 &lt;code&gt;List.of()&lt;/code&gt;）&lt;/td&gt;
					&lt;td style="text-align: left"&gt;否&lt;/td&gt;
					&lt;td style="text-align: left"&gt;对象不可变，多线程只能读取，无竞态条件。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;局部变量（如 &lt;code&gt;step&lt;/code&gt;）&lt;/td&gt;
					&lt;td style="text-align: left"&gt;否&lt;/td&gt;
					&lt;td style="text-align: left"&gt;线程私有，栈封闭。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;成员变量赋值（如 &lt;code&gt;this.names&lt;/code&gt;）&lt;/td&gt;
					&lt;td style="text-align: left"&gt;是&lt;/td&gt;
					&lt;td style="text-align: left"&gt;引用可能被多线程同时修改，需同步或 &lt;code&gt;volatile&lt;/code&gt;。&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td style="text-align: left"&gt;复合操作（如 &lt;code&gt;x += step&lt;/code&gt;）&lt;/td&gt;
					&lt;td style="text-align: left"&gt;是&lt;/td&gt;
					&lt;td style="text-align: left"&gt;非原子操作（读取-修改-写入），需同步。&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id="小结-4"&gt;小结
&lt;/h4&gt;&lt;p&gt;多线程同时读写共享变量时，可能会造成逻辑错误，因此需要通过&lt;code&gt;synchronized&lt;/code&gt;同步；&lt;/p&gt;
&lt;p&gt;同步的本质就是给指定对象加锁，加锁后才能继续执行后续代码；&lt;/p&gt;
&lt;p&gt;注意加锁对象必须是同一个实例；&lt;/p&gt;
&lt;p&gt;对JVM定义的单个原子操作不需要同步。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="线程同步方法"&gt;线程同步方法
&lt;/h3&gt;&lt;h4 id="线程安全"&gt;线程安全
&lt;/h4&gt;&lt;p&gt;如果一个类被设计为允许多线程正确访问，我们就说这个类就是“线程安全”的（thread-safe），Java标准库的&lt;code&gt;java.lang.StringBuffer&lt;/code&gt;也是线程安全的。&lt;/p&gt;
&lt;p&gt;还有一些 &lt;strong&gt;不变类&lt;/strong&gt; ，例如&lt;code&gt;String&lt;/code&gt;，&lt;code&gt;Integer&lt;/code&gt;，&lt;code&gt;LocalDate&lt;/code&gt;，它们的所有成员变量都是&lt;code&gt;final&lt;/code&gt;，多线程同时访问时只能读不能写，这些不变类也是线程安全的。&lt;/p&gt;
&lt;p&gt;最后，类似&lt;code&gt;Math&lt;/code&gt;这些 &lt;strong&gt;只提供静态方法，没有成员变量的类&lt;/strong&gt; ，也是线程安全的。&lt;/p&gt;
&lt;p&gt;除了上述几种少数情况，大部分类，例如&lt;code&gt;ArrayList&lt;/code&gt;，都是 &lt;strong&gt;非线程安全的类&lt;/strong&gt; ，我们不能在多线程中修改它们。但是，如果所有线程都 &lt;strong&gt;只读取，不写入&lt;/strong&gt; ，那么&lt;code&gt;ArrayList&lt;/code&gt;是可以安全地在线程间共享的。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;没有特殊说明时，一个类 &lt;strong&gt;默认是非线程安全的&lt;/strong&gt; 。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;例如下面的Counter类：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;dec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这样一来，线程调用&lt;code&gt;add()&lt;/code&gt;、&lt;code&gt;dec()&lt;/code&gt;方法时，它不必关心同步逻辑，因为&lt;code&gt;synchronized&lt;/code&gt;代码块在&lt;code&gt;add()&lt;/code&gt;、&lt;code&gt;dec()&lt;/code&gt;方法内部。并且，我们注意到，&lt;strong&gt;&lt;code&gt;synchronized&lt;/code&gt;锁住的对象是&lt;code&gt;this&lt;/code&gt;，即当前实例，这又使得创建多个&lt;code&gt;Counter&lt;/code&gt;实例的时候，它们之间互不影响，可以并发执行&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id="synchronized-修饰"&gt;&lt;code&gt;synchronized&lt;/code&gt; 修饰
&lt;/h4&gt;&lt;p&gt;我们再观察&lt;code&gt;Counter&lt;/code&gt;的代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;当我们锁住的是&lt;code&gt;this&lt;/code&gt;实例时，实际上可以用&lt;code&gt;synchronized&lt;/code&gt;修饰这个方法。下面两种写法是等价的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 锁住this&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 解锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;写法二：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 锁住this&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 解锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;因此， &lt;strong&gt;用&lt;code&gt;synchronized&lt;/code&gt;修饰的方法就是同步方法&lt;/strong&gt; ，它表示整个方法都必须用&lt;code&gt;this&lt;/code&gt;实例加锁。&lt;/p&gt;
&lt;p&gt;对于&lt;code&gt;static&lt;/code&gt;方法，是没有&lt;code&gt;this&lt;/code&gt;实例的，因为&lt;code&gt;static&lt;/code&gt;方法是针对类而不是实例。但是我们注意到任何一个类都有一个由JVM自动创建的&lt;code&gt;Class&lt;/code&gt;实例，因此， &lt;strong&gt;对&lt;code&gt;static&lt;/code&gt;方法添加&lt;code&gt;synchronized&lt;/code&gt;，锁住的是该类的&lt;code&gt;Class&lt;/code&gt;实例&lt;/strong&gt; 。上述&lt;code&gt;synchronized static&lt;/code&gt;方法实际上相当于：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="小结-5"&gt;小结
&lt;/h4&gt;&lt;p&gt;用&lt;code&gt;synchronized&lt;/code&gt;修饰方法可以把整个方法变为同步代码块，&lt;code&gt;synchronized&lt;/code&gt;方法加锁对象是&lt;code&gt;this&lt;/code&gt;；&lt;/p&gt;
&lt;p&gt;通过合理的设计和数据封装可以让一个类变为“线程安全”；&lt;/p&gt;
&lt;p&gt;一个类没有特殊说明，默认不是thread-safe；&lt;/p&gt;
&lt;p&gt;多线程能否安全访问某个非线程安全的实例，需要具体问题具体分析。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="死锁"&gt;死锁
&lt;/h3&gt;&lt;h4 id="可重入锁"&gt;可重入锁
&lt;/h4&gt;&lt;p&gt;Java的线程锁是可重入的锁。&lt;/p&gt;
&lt;p&gt;什么是可重入的锁？我们还是来看例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;dec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;执行流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;调用&lt;code&gt;add(-1)&lt;/code&gt;：
&lt;ul&gt;
&lt;li&gt;获取&lt;code&gt;this&lt;/code&gt;锁：计数器=1，持有线程=当前线程&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;进入&lt;code&gt;add&lt;/code&gt;方法后调用&lt;code&gt;dec(1)&lt;/code&gt;：
&lt;ul&gt;
&lt;li&gt;再次获取&lt;code&gt;this&lt;/code&gt;锁：发现当前线程已持有，计数器增加到2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;退出&lt;code&gt;dec&lt;/code&gt;方法：
&lt;ul&gt;
&lt;li&gt;计数器减到1&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;退出&lt;code&gt;add&lt;/code&gt;方法：
&lt;ul&gt;
&lt;li&gt;计数器减到0，真正释放锁&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;观察&lt;code&gt;synchronized&lt;/code&gt;修饰的&lt;code&gt;add()&lt;/code&gt;方法，一旦线程执行到&lt;code&gt;add()&lt;/code&gt;方法内部，说明它已经获取了当前实例的&lt;code&gt;this&lt;/code&gt;锁。如果传入的&lt;code&gt;n &amp;lt; 0&lt;/code&gt;，将在&lt;code&gt;add()&lt;/code&gt;方法内部调用&lt;code&gt;dec()&lt;/code&gt;方法。由于&lt;code&gt;dec()&lt;/code&gt;方法也需要获取&lt;code&gt;this&lt;/code&gt;锁，现在问题来了：&lt;/p&gt;
&lt;p&gt;对同一个线程，能否在获取到锁以后继续获取同一个锁？&lt;/p&gt;
&lt;p&gt;答案是肯定的。 &lt;strong&gt;JVM允许同一个线程重复获取同一个锁&lt;/strong&gt; ，这种能被同一个线程反复获取的锁，就叫做&lt;strong&gt;可重入锁&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;由于Java的线程锁是可重入锁，所以，获取锁的时候，不但要判断是否是第一次获取，还要记录这是第几次获取。每获取一次锁，记录+1，每退出&lt;code&gt;synchronized&lt;/code&gt;块，记录-1，减到0的时候，才会真正释放锁。&lt;/p&gt;
&lt;h4 id="死锁-1"&gt;死锁
&lt;/h4&gt;&lt;p&gt;一个线程可以获取一个锁后，再继续获取另一个锁。例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lockA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 获得lockA的锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lockB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 获得lockB的锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;another&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 释放lockB的锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 释放lockA的锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;dec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lockB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 获得lockB的锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;another&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lockA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 获得lockA的锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 释放lockA的锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 释放lockB的锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;在获取多个锁的时候，不同线程获取多个不同对象的锁可能导致死锁。对于上述代码，线程1和线程2如果分别执行&lt;code&gt;add()&lt;/code&gt;和&lt;code&gt;dec()&lt;/code&gt;方法时：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;线程1：进入&lt;code&gt;add()&lt;/code&gt;，获得&lt;code&gt;lockA&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;线程2：进入&lt;code&gt;dec()&lt;/code&gt;，获得&lt;code&gt;lockB&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;随后：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;线程1：准备获得&lt;code&gt;lockB&lt;/code&gt;，失败，等待中；&lt;/li&gt;
&lt;li&gt;线程2：准备获得&lt;code&gt;lockA&lt;/code&gt;，失败，等待中。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;此时，两个线程各自持有不同的锁，然后各自试图获取对方手里的锁，造成了双方无限等待下去，这就是死锁。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;死锁发生后，没有任何机制能解除死锁，只能强制结束JVM进程。&lt;/p&gt;
&lt;p&gt;因此，在编写多线程应用时，要特别注意防止死锁。因为死锁一旦形成，就只能强制结束进程。&lt;/p&gt;
&lt;p&gt;那么我们应该如何避免死锁呢？答案是： &lt;strong&gt;线程获取锁的顺序要一致&lt;/strong&gt; 。即严格按照先获取&lt;code&gt;lockA&lt;/code&gt;，再获取&lt;code&gt;lockB&lt;/code&gt;的顺序，改写&lt;code&gt;dec()&lt;/code&gt;方法如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;dec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lockA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 获得lockA的锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lockB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 获得lockB的锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;another&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 释放lockB的锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 释放lockA的锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="小结-6"&gt;小结
&lt;/h4&gt;&lt;p&gt;Java的&lt;code&gt;synchronized&lt;/code&gt;锁是可重入锁；&lt;/p&gt;
&lt;p&gt;死锁产生的条件是多线程各自持有不同的锁，并互相试图获取对方已持有的锁，导致无限等待；&lt;/p&gt;
&lt;p&gt;避免死锁的方法是多线程获取锁的顺序要一致。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="线程通信"&gt;线程通信
&lt;/h3&gt;&lt;p&gt;在Java程序中，&lt;code&gt;synchronized&lt;/code&gt;解决了多线程竞争的问题。例如，对于一个任务管理器，多个线程同时往队列中添加任务，可以用&lt;code&gt;synchronized&lt;/code&gt;加锁：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TaskQueue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LinkedList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;addTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;但是&lt;code&gt;synchronized&lt;/code&gt;并没有解决多线程协调的问题。&lt;/p&gt;
&lt;p&gt;仍然以上面的&lt;code&gt;TaskQueue&lt;/code&gt;为例，我们再编写一个&lt;code&gt;getTask()&lt;/code&gt;方法取出队列的第一个任务：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TaskQueue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LinkedList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;addTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;getTask&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;上述代码看上去没有问题：&lt;code&gt;getTask()&lt;/code&gt;内部先判断队列是否为空，如果为空，就循环等待，直到另一个线程往队列中放入了一个任务，&lt;code&gt;while()&lt;/code&gt;循环退出，就可以返回队列的元素了。&lt;/p&gt;
&lt;p&gt;但实际上&lt;code&gt;while()&lt;/code&gt;循环永远不会退出。因为线程在执行&lt;code&gt;while()&lt;/code&gt;循环时，已经在&lt;code&gt;getTask()&lt;/code&gt;入口获取了&lt;code&gt;this&lt;/code&gt;锁，其他线程根本无法调用&lt;code&gt;addTask()&lt;/code&gt;，因为&lt;code&gt;addTask()&lt;/code&gt;执行条件也是获取&lt;code&gt;this&lt;/code&gt;锁。&lt;/p&gt;
&lt;p&gt;因此，执行上述代码，线程会在&lt;code&gt;getTask()&lt;/code&gt;中因为死循环而100%占用CPU资源。&lt;/p&gt;
&lt;p&gt;如果深入思考一下，我们想要的执行效果是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;线程1可以调用&lt;code&gt;addTask()&lt;/code&gt;不断往队列中添加任务；&lt;/li&gt;
&lt;li&gt;线程2可以调用&lt;code&gt;getTask()&lt;/code&gt;从队列中获取任务。如果队列为空，则&lt;code&gt;getTask()&lt;/code&gt;应该等待，直到队列中至少有一个任务时再返回。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;因此，多线程协调运行的原则就是：当条件不满足时，线程进入等待状态；当条件满足时，线程被唤醒，继续执行任务。&lt;/strong&gt;&lt;/p&gt;
&lt;h4 id="wait"&gt;&lt;code&gt;wait()&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;对于上述&lt;code&gt;TaskQueue&lt;/code&gt;，我们先改造&lt;code&gt;getTask()&lt;/code&gt;方法，在条件不满足时，线程进入等待状态：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;getTask&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;当一个线程执行到&lt;code&gt;getTask()&lt;/code&gt;方法内部的&lt;code&gt;while&lt;/code&gt;循环时，它必定已经获取到了&lt;code&gt;this&lt;/code&gt;锁，此时，线程执行&lt;code&gt;while&lt;/code&gt;条件判断，如果条件成立（队列为空），线程将执行&lt;code&gt;this.wait()&lt;/code&gt;，进入等待状态。&lt;/p&gt;
&lt;p&gt;这里的关键是：&lt;code&gt;wait()&lt;/code&gt;方法必须在 &lt;strong&gt;当前获取的锁对象&lt;/strong&gt; 上调用，这里获取的是&lt;code&gt;this&lt;/code&gt;锁，因此调用&lt;code&gt;this.wait()&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;调用&lt;code&gt;wait()&lt;/code&gt;方法后，线程进入等待状态，&lt;code&gt;wait()&lt;/code&gt;方法不会返回，直到将来某个时刻， &lt;strong&gt;线程从等待状态被其他线程唤醒后&lt;/strong&gt; ，&lt;code&gt;wait()&lt;/code&gt;方法才会返回，然后，继续执行下一条语句。&lt;/p&gt;
&lt;p&gt;有些仔细的童鞋会指出：即使线程在&lt;code&gt;getTask()&lt;/code&gt;内部等待，其他线程如果拿不到&lt;code&gt;this&lt;/code&gt;锁，照样无法执行&lt;code&gt;addTask()&lt;/code&gt;，肿么办？&lt;/p&gt;
&lt;p&gt;这个问题的关键就在于&lt;code&gt;wait()&lt;/code&gt;方法的执行机制非常复杂。首先，它不是一个普通的Java方法，而是定义在&lt;code&gt;Object&lt;/code&gt;类的一个&lt;code&gt;native&lt;/code&gt;方法，也就是由JVM的C代码实现的。其次，必须在&lt;code&gt;synchronized&lt;/code&gt;块中才能调用&lt;code&gt;wait()&lt;/code&gt;方法， &lt;strong&gt;因为&lt;code&gt;wait()&lt;/code&gt;方法调用时，会释放线程获得的锁&lt;/strong&gt; ，&lt;code&gt;wait()&lt;/code&gt;方法返回时，线程又会重新试图获得锁。&lt;/p&gt;
&lt;p&gt;因此，只能在锁对象上调用&lt;code&gt;wait()&lt;/code&gt;方法。因为在&lt;code&gt;getTask()&lt;/code&gt;中，我们获得了&lt;code&gt;this&lt;/code&gt;锁，因此，只能在&lt;code&gt;this&lt;/code&gt;对象上调用&lt;code&gt;wait()&lt;/code&gt;方法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;getTask&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 释放this锁:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 重新获取this锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;当一个线程在&lt;code&gt;this.wait()&lt;/code&gt;等待时，它就会释放&lt;code&gt;this&lt;/code&gt;锁，从而使得其他线程能够在&lt;code&gt;addTask()&lt;/code&gt;方法获得&lt;code&gt;this&lt;/code&gt;锁。&lt;/p&gt;
&lt;h4 id="notify"&gt;&lt;code&gt;notify()&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;现在我们面临第二个问题：如何让等待的线程被 &lt;strong&gt;重新唤醒&lt;/strong&gt; ，然后从&lt;code&gt;wait()&lt;/code&gt;方法返回？答案是在相同的锁对象上调用&lt;code&gt;notify()&lt;/code&gt;方法。我们修改&lt;code&gt;addTask()&lt;/code&gt;如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;addTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 唤醒在this锁等待的线程&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;注意到在往队列中添加了任务后，线程立刻对&lt;code&gt;this&lt;/code&gt;锁对象调用&lt;code&gt;notify()&lt;/code&gt;方法，这个方法会唤醒一个正在&lt;code&gt;this&lt;/code&gt;锁等待的线程（就是在&lt;code&gt;getTask()&lt;/code&gt;中位于&lt;code&gt;this.wait()&lt;/code&gt;的线程），从而使得等待线程从&lt;code&gt;this.wait()&lt;/code&gt;方法返回。&lt;/p&gt;
&lt;p&gt;我们来看一个完整的例子(这也是一个生产者消费者模型)：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;span class="lnt"&gt;53
&lt;/span&gt;&lt;span class="lnt"&gt;54
&lt;/span&gt;&lt;span class="lnt"&gt;55
&lt;/span&gt;&lt;span class="lnt"&gt;56
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;java.util.*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;throws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TaskQueue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 执行task:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTask&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;execute task: &amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 放入task:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;t-&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;random&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;add task: &amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;interrupt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TaskQueue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LinkedList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;addTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;notifyAll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;getTask&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;throws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这个例子中，我们重点关注&lt;code&gt;addTask()&lt;/code&gt;方法，内部调用了&lt;code&gt;this.notifyAll()&lt;/code&gt;而不是&lt;code&gt;this.notify()&lt;/code&gt;，使用&lt;code&gt;notifyAll()&lt;/code&gt;将唤醒所有当前正在&lt;code&gt;this&lt;/code&gt;锁等待的线程，而&lt;code&gt;notify()&lt;/code&gt;只会 &lt;strong&gt;唤醒其中一个&lt;/strong&gt; （具体哪个依赖操作系统，有一定的 &lt;strong&gt;随机性&lt;/strong&gt;）。这是因为可能有多个线程正在&lt;code&gt;getTask()&lt;/code&gt;方法内部的&lt;code&gt;wait()&lt;/code&gt;中等待，使用&lt;code&gt;notifyAll()&lt;/code&gt;将 &lt;strong&gt;一次性全部唤醒&lt;/strong&gt; 。通常来说，&lt;code&gt;notifyAll()&lt;/code&gt;更安全。有些时候，如果我们的代码逻辑考虑不周，用&lt;code&gt;notify()&lt;/code&gt;会导致只唤醒了一个线程，而其他线程可能永远等待下去醒不过来了。&lt;/p&gt;
&lt;p&gt;但是，注意到&lt;code&gt;wait()&lt;/code&gt;方法返回时需要 &lt;em&gt;重新&lt;/em&gt; 获得&lt;code&gt;this&lt;/code&gt;锁。假设当前有3个线程被唤醒，唤醒后，首先要等待执行&lt;code&gt;addTask()&lt;/code&gt;的线程结束此方法后，才能释放&lt;code&gt;this&lt;/code&gt;锁，随后，这3个线程中只能有一个获取到&lt;code&gt;this&lt;/code&gt;锁，剩下两个将继续等待。&lt;/p&gt;
&lt;p&gt;再注意到我们在&lt;code&gt;while()&lt;/code&gt;循环中调用&lt;code&gt;wait()&lt;/code&gt;，而不是&lt;code&gt;if&lt;/code&gt;语句：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;getTask&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;throws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这种写法实际上是错误的，因为线程被唤醒时，需要再次获取&lt;code&gt;this&lt;/code&gt;锁。多个线程被唤醒后，只有一个线程能获取&lt;code&gt;this&lt;/code&gt;锁，此刻，该线程执行&lt;code&gt;queue.remove()&lt;/code&gt;可以获取到队列的元素，然而，剩下的线程如果获取&lt;code&gt;this&lt;/code&gt;锁后执行&lt;code&gt;queue.remove()&lt;/code&gt;，此刻队列可能已经没有任何元素了，所以，要始终在&lt;code&gt;while&lt;/code&gt;循环中&lt;code&gt;wait()&lt;/code&gt;，并且每次被唤醒后拿到&lt;code&gt;this&lt;/code&gt;锁就必须再次判断：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="小结-7"&gt;小结
&lt;/h4&gt;&lt;p&gt;&lt;code&gt;wait&lt;/code&gt;和&lt;code&gt;notify&lt;/code&gt;用于多线程协调运行：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在&lt;code&gt;synchronized&lt;/code&gt;内部可以调用&lt;code&gt;wait()&lt;/code&gt;使线程进入等待状态；&lt;/li&gt;
&lt;li&gt;必须在已获得的锁对象上调用&lt;code&gt;wait()&lt;/code&gt;方法；&lt;/li&gt;
&lt;li&gt;在&lt;code&gt;synchronized&lt;/code&gt;内部可以调用&lt;code&gt;notify()&lt;/code&gt;或&lt;code&gt;notifyAll()&lt;/code&gt;唤醒其他等待线程；&lt;/li&gt;
&lt;li&gt;必须在已获得的锁对象上调用&lt;code&gt;notify()&lt;/code&gt;或&lt;code&gt;notifyAll()&lt;/code&gt;方法；&lt;/li&gt;
&lt;li&gt;已唤醒的线程还需要重新获得锁后才能继续执行。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="生产者消费者模型"&gt;生产者消费者模型
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://www.bilibili.com/video/BV1tX4y1S7Hz/?spm_id_from=333.1007.top_right_bar_window_history.content.click&amp;amp;vd_source=c8beb52bf015e61e5378008c684545a4" target="_blank" rel="noopener"
 &gt;Java生产者消费者模式的实现和解析_哔哩哔哩_bilibili&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;下面是从B站找来的简单的生产者消费者模型的示例，并不如上面线程通信中的示例以及下面的消息队列模型示例，这三个示例我想就能拿下该模型罢&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Demo1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * 交替执行两个线程
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * 一个输出“1,2,3,...”
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * 一个输出“a,b,c,...”
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Factory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Runnable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;26&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Runnable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;z&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;consume&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;t2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Factory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * 0: 生产者正在生成，消费者正在等待，生产者结束生产后告知消费者进行消费
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * 1: 消费者正在消费，生产者正在等待，消费者结束消费后高职生产者进行生产
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sign&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;	&lt;/span&gt;&lt;span class="c1"&gt;//状态值&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sign&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;printStackTrace&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sign&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;consume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sign&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;printStackTrace&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sign&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;线程的运行有一定随机性，往往用户无法决定，但是生产者消费者模型，能实现两个线程的“交替”运行&lt;/p&gt;
&lt;p&gt;注释里的内容不再概述，我们来分析一下：&lt;/p&gt;
&lt;p&gt;假设线程 &lt;code&gt;t1&lt;/code&gt; 先被调用，由于 &lt;code&gt;sign = 0&lt;/code&gt; ，所以打印字符 &lt;code&gt;1&lt;/code&gt; ， &lt;code&gt;sign&lt;/code&gt; 变为1。下面有两种可能，调用线程 &lt;code&gt;t1&lt;/code&gt; 或 &lt;code&gt;t2&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;调用 &lt;code&gt;t1&lt;/code&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sign = 1&lt;/code&gt; 进入 &lt;code&gt;try/catch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;同步锁的对象 &lt;code&gt;this。wait()&lt;/code&gt; 也就是进入 &lt;strong&gt;“等待”&lt;/strong&gt; 状态&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wait()&lt;/code&gt; 会 &lt;strong&gt;释放锁&lt;/strong&gt; ，线程 &lt;code&gt;t2&lt;/code&gt; 执行，运行 &lt;code&gt;consume()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;notfiy()&lt;/code&gt; &lt;strong&gt;唤醒&lt;/strong&gt; &lt;code&gt;this&lt;/code&gt; 中等待的线程 &lt;code&gt;t1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sign&lt;/code&gt; 被赋值0，周而复始&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;调用 &lt;code&gt;t2&lt;/code&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;线程 &lt;code&gt;t2&lt;/code&gt; 执行，运行 &lt;code&gt;consume()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;notify&lt;/code&gt; 不唤醒任一线程(因为无线程处于等待状态)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sign&lt;/code&gt; 被赋值0，周而复始&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="示例分析"&gt;示例分析
&lt;/h4&gt;&lt;p&gt;下面是较复杂(贴切实际)的一种，思想和上面简单的例子差不多的&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;关于下面示例中 &lt;code&gt;lambda&lt;/code&gt; 表达式创建线程的方式，需要补充几点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;new Thread()&lt;/code&gt; - 创建新线程&lt;/li&gt;
&lt;li&gt;&lt;code&gt;() -&amp;gt; {...}&lt;/code&gt; - Lambda表达式定义线程任务&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;生产者&amp;quot; + i&lt;/code&gt; - 线程命名&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.start()&lt;/code&gt; - 启动线程&lt;/li&gt;
&lt;/ul&gt;

 &lt;/blockquote&gt;
&lt;p&gt;这里通过循环来创建线程，所以用循环的参数为其命名&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;span class="lnt"&gt;53
&lt;/span&gt;&lt;span class="lnt"&gt;54
&lt;/span&gt;&lt;span class="lnt"&gt;55
&lt;/span&gt;&lt;span class="lnt"&gt;56
&lt;/span&gt;&lt;span class="lnt"&gt;57
&lt;/span&gt;&lt;span class="lnt"&gt;58
&lt;/span&gt;&lt;span class="lnt"&gt;59
&lt;/span&gt;&lt;span class="lnt"&gt;60
&lt;/span&gt;&lt;span class="lnt"&gt;61
&lt;/span&gt;&lt;span class="lnt"&gt;62
&lt;/span&gt;&lt;span class="lnt"&gt;63
&lt;/span&gt;&lt;span class="lnt"&gt;64
&lt;/span&gt;&lt;span class="lnt"&gt;65
&lt;/span&gt;&lt;span class="lnt"&gt;66
&lt;/span&gt;&lt;span class="lnt"&gt;67
&lt;/span&gt;&lt;span class="lnt"&gt;68
&lt;/span&gt;&lt;span class="lnt"&gt;69
&lt;/span&gt;&lt;span class="lnt"&gt;70
&lt;/span&gt;&lt;span class="lnt"&gt;71
&lt;/span&gt;&lt;span class="lnt"&gt;72
&lt;/span&gt;&lt;span class="lnt"&gt;73
&lt;/span&gt;&lt;span class="lnt"&gt;74
&lt;/span&gt;&lt;span class="lnt"&gt;75
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;throws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MessageQueue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MessageQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 三个生产者向队列里存值&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;值&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;生产者&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 一个消费者不停的从队列里取值&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;take&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;消费者&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 消息队列被生产者和消费者持有&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MessageQueue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LinkedList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LinkedList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 容量&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;MessageQueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;capacity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//生产者&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;队列已满，生产者等待&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;printStackTrace&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addLast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;生产消息:{}&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 生产后通知消费者&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;notifyAll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//消费者&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;队列已空，消费者等待&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;printStackTrace&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;removeFirst&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;//从队列头部取出消息&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;消费消息:{}&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 消费后通知生产者&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;notifyAll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 消息&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;主函数:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;创建了一个容量为2的消息队列&lt;code&gt;MessageQueue&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;启动3个生产者线程，每个生产者向队列中放入一条消息&lt;/li&gt;
&lt;li&gt;主线程休眠1秒，让生产者有足够时间开始工作&lt;/li&gt;
&lt;li&gt;启动一个消费者线程，不断从队列中取出消息&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;生产者:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用&lt;code&gt;synchronized&lt;/code&gt;块获取&lt;code&gt;list&lt;/code&gt;对象的锁&lt;/li&gt;
&lt;li&gt;检查队列是否已满（&lt;code&gt;while&lt;/code&gt;循环防止虚假唤醒）&lt;/li&gt;
&lt;li&gt;如果队列已满，调用&lt;code&gt;wait()&lt;/code&gt;释放锁并等待&lt;/li&gt;
&lt;li&gt;当队列有空闲时，添加消息到队列尾部&lt;/li&gt;
&lt;li&gt;调用&lt;code&gt;notifyAll()&lt;/code&gt;唤醒可能正在等待的消费者线程&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;消费者:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用&lt;code&gt;synchronized&lt;/code&gt;块获取&lt;code&gt;list&lt;/code&gt;对象的锁&lt;/li&gt;
&lt;li&gt;检查队列是否为空（&lt;code&gt;while&lt;/code&gt;循环防止虚假唤醒）&lt;/li&gt;
&lt;li&gt;如果队列为空，调用&lt;code&gt;wait()&lt;/code&gt;释放锁并等待&lt;/li&gt;
&lt;li&gt;当队列有消息时，从队列头部取出消息&lt;/li&gt;
&lt;li&gt;调用&lt;code&gt;notifyAll()&lt;/code&gt;唤醒可能正在等待的生产者线程&lt;/li&gt;
&lt;li&gt;返回取出的消息&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="小结-8"&gt;小结
&lt;/h4&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;同步机制&lt;/strong&gt;：使用&lt;code&gt;synchronized&lt;/code&gt;保证对队列操作的原子性&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;等待/通知机制&lt;/strong&gt;：使用&lt;code&gt;wait()&lt;/code&gt;和&lt;code&gt;notifyAll()&lt;/code&gt;实现线程间通信&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;循环检查条件&lt;/strong&gt;：使用&lt;code&gt;while&lt;/code&gt;而非&lt;code&gt;if&lt;/code&gt;检查条件，防止虚假唤醒&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;容量限制&lt;/strong&gt;：控制队列大小，防止内存耗尽&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id="可重入锁-1"&gt;可重入锁
&lt;/h3&gt;&lt;p&gt;从Java 5开始，引入了一个高级的处理并发的&lt;code&gt;java.util.concurrent&lt;/code&gt;包，它提供了大量更高级的并发功能，能大大简化多线程程序的编写。&lt;/p&gt;
&lt;p&gt;我们知道Java语言直接提供了&lt;code&gt;synchronized&lt;/code&gt;关键字用于加锁，但这种锁一是很重，二是获取时必须一直等待，没有额外的尝试机制。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;java.util.concurrent.locks&lt;/code&gt;包提供的&lt;code&gt;ReentrantLock&lt;/code&gt;用于替代&lt;code&gt;synchronized&lt;/code&gt;加锁，我们来看一下传统的&lt;code&gt;synchronized&lt;/code&gt;代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;synchronized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果用&lt;code&gt;ReentrantLock&lt;/code&gt;替代，可以把代码改造为：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ReentrantLock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unlock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;因为&lt;code&gt;synchronized&lt;/code&gt;是Java语言层面提供的语法，所以我们不需要考虑异常，而&lt;code&gt;ReentrantLock&lt;/code&gt;是Java代码实现的锁，我们就必须先获取锁，然后在&lt;code&gt;finally&lt;/code&gt;中正确释放锁。&lt;/p&gt;
&lt;p&gt;顾名思义，&lt;code&gt;ReentrantLock&lt;/code&gt;是可重入锁，它和&lt;code&gt;synchronized&lt;/code&gt;一样，一个线程可以多次获取同一个锁。&lt;/p&gt;
&lt;p&gt;和&lt;code&gt;synchronized&lt;/code&gt;不同的是，&lt;code&gt;ReentrantLock&lt;/code&gt;可以尝试获取锁：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tryLock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TimeUnit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unlock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;上述代码在尝试获取锁的时候，最多等待1秒。如果1秒后仍未获取到锁，&lt;code&gt;tryLock()&lt;/code&gt;返回&lt;code&gt;false&lt;/code&gt;，程序就可以做一些额外处理，而不是无限等待下去。&lt;/p&gt;
&lt;p&gt;所以，使用&lt;code&gt;ReentrantLock&lt;/code&gt;比直接使用&lt;code&gt;synchronized&lt;/code&gt;更安全，线程在&lt;code&gt;tryLock()&lt;/code&gt;失败的时候不会导致死锁。&lt;/p&gt;
&lt;p&gt;下面来介绍一下它的各种方法，以及一个较复杂的案例&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 默认非公平锁，参数传true 表示未公平锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ReentrantLock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ReentrantLock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 尝试获取锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 释放锁 应放在finally块中 必须执行到&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 获取锁时可被打断,阻塞中的线程可被打断&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LOCK&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lockInterruptibly&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 尝试获取锁 获取不到就返回false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;LOCK&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tryLock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 支持超时时间 一段时间没获取到就返回false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;tryLock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TimeUnit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 指定条件变量 休息室 一个锁可以创建多个休息室&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Condition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;waitSet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ROOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newCondition&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 释放锁 进入waitSet等待 释放后其他线程可以抢锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;yanWaitSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;await&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 唤醒具体休息室的线程 唤醒后 重写竞争锁&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;yanWaitSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;span class="lnt"&gt;48
&lt;/span&gt;&lt;span class="lnt"&gt;49
&lt;/span&gt;&lt;span class="lnt"&gt;50
&lt;/span&gt;&lt;span class="lnt"&gt;51
&lt;/span&gt;&lt;span class="lnt"&gt;52
&lt;/span&gt;&lt;span class="lnt"&gt;53
&lt;/span&gt;&lt;span class="lnt"&gt;54
&lt;/span&gt;&lt;span class="lnt"&gt;55
&lt;/span&gt;&lt;span class="lnt"&gt;56
&lt;/span&gt;&lt;span class="lnt"&gt;57
&lt;/span&gt;&lt;span class="lnt"&gt;58
&lt;/span&gt;&lt;span class="lnt"&gt;59
&lt;/span&gt;&lt;span class="lnt"&gt;60
&lt;/span&gt;&lt;span class="lnt"&gt;61
&lt;/span&gt;&lt;span class="lnt"&gt;62
&lt;/span&gt;&lt;span class="lnt"&gt;63
&lt;/span&gt;&lt;span class="lnt"&gt;64
&lt;/span&gt;&lt;span class="lnt"&gt;65
&lt;/span&gt;&lt;span class="lnt"&gt;66
&lt;/span&gt;&lt;span class="lnt"&gt;67
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AwaitSignal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;awaitSignal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AwaitSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 构建三个条件变量&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Condition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;awaitSignal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newCondition&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Condition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;awaitSignal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newCondition&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Condition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;awaitSignal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newCondition&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 开启三个线程&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;awaitSignal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;a&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;awaitSignal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;b&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;awaitSignal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;c&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;printStackTrace&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;awaitSignal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 先唤醒a&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;awaitSignal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unlock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AwaitSignal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ReentrantLock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 循环次数&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;loopNumber&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;AwaitSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;loopNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loopNumber&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;loopNumber&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * @param print 输出的字符
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * @param current 当前条件变量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * @param next 下一个条件变量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Condition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Condition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;loopNumber&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 获取锁之后等待&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;await&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unlock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;流程分析：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;初始化&lt;/strong&gt; ：&lt;/li&gt;
&lt;li&gt;主线程创建了 &lt;code&gt;AwaitSignal&lt;/code&gt; 对象，设置循环次数为 5。&lt;/li&gt;
&lt;li&gt;创建了三个 &lt;code&gt;Condition&lt;/code&gt; 对象：a、b、c，分别对应三个线程。&lt;/li&gt;
&lt;li&gt;三个线程启动，分别调用 &lt;code&gt;print(&amp;quot;a&amp;quot;, a, b)&lt;/code&gt; 、 &lt;code&gt;print(&amp;quot;b&amp;quot;, b, c)&lt;/code&gt; 、 &lt;code&gt;print(&amp;quot;c&amp;quot;, c, a)&lt;/code&gt; 。&lt;/li&gt;
&lt;li&gt;主线程休眠 1 秒后，获取锁并通过 &lt;code&gt;a.signal()&lt;/code&gt; 唤醒线程 A。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;线程启动后&lt;/strong&gt; ：&lt;/li&gt;
&lt;li&gt;每个线程进入 &lt;code&gt;print&lt;/code&gt; 方法，执行 &lt;code&gt;lock()&lt;/code&gt; 获取锁。由于 &lt;code&gt;ReentrantLock&lt;/code&gt; 是互斥锁，同一时刻只有一个线程能持有锁。&lt;/li&gt;
&lt;li&gt;假设线程 A 先获取锁，它调用 &lt;code&gt;a.await()&lt;/code&gt; ，释放锁并进入等待状态（等待 &lt;code&gt;Condition a&lt;/code&gt; 的信号）。&lt;/li&gt;
&lt;li&gt;其他线程（B 和 C）尝试 &lt;code&gt;lock()&lt;/code&gt; ，但锁被占用，它们会阻塞在 &lt;code&gt;lock()&lt;/code&gt; 上。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;主线程唤醒线程A&lt;/strong&gt; ：&lt;/li&gt;
&lt;li&gt;主线程在 &lt;code&gt;try { Thread.sleep(1000); }&lt;/code&gt; 后执行 &lt;code&gt;awaitSignal.lock()&lt;/code&gt; ，获取锁。&lt;/li&gt;
&lt;li&gt;调用 &lt;code&gt;a.signal()&lt;/code&gt; ，唤醒等待在 &lt;code&gt;Condition a&lt;/code&gt; 上的线程 A。&lt;/li&gt;
&lt;li&gt;主线程执行 &lt;code&gt;unlock()&lt;/code&gt; ，释放锁。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;线程A被唤醒后&lt;/strong&gt; ：&lt;/li&gt;
&lt;li&gt;线程 A 从 &lt;code&gt;a.await()&lt;/code&gt; 返回，但它需要重新获取锁才能继续执行。&lt;/li&gt;
&lt;li&gt;因为主线程已经释放锁（ &lt;code&gt;unlock()&lt;/code&gt; ），线程 A 成功重新获取锁。&lt;/li&gt;
&lt;li&gt;线程 A 打印 &amp;ldquo;a&amp;rdquo;，然后调用 &lt;code&gt;b.signal()&lt;/code&gt; 唤醒线程 B。&lt;/li&gt;
&lt;li&gt;线程 A 执行 &lt;code&gt;unlock()&lt;/code&gt; ，释放锁。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;线程B被唤醒后&lt;/strong&gt; ：&lt;/li&gt;
&lt;li&gt;线程 B 在 &lt;code&gt;b.await()&lt;/code&gt; 上等待，收到 &lt;code&gt;b.signal()&lt;/code&gt; 后被唤醒。&lt;/li&gt;
&lt;li&gt;线程 B 尝试重新获取锁。由于线程 A 已释放锁，线程 B 获取锁成功。&lt;/li&gt;
&lt;li&gt;线程 B 打印 &amp;ldquo;b&amp;rdquo;，调用 &lt;code&gt;c.signal()&lt;/code&gt; 唤醒线程 C，然后释放锁。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="小结-9"&gt;小结
&lt;/h4&gt;&lt;p&gt;&lt;code&gt;ReentrantLock&lt;/code&gt;可以替代&lt;code&gt;synchronized&lt;/code&gt;进行同步；&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ReentrantLock&lt;/code&gt;获取锁更安全；&lt;/p&gt;
&lt;p&gt;必须先获取到锁，再进入&lt;code&gt;try {...}&lt;/code&gt;代码块，最后使用&lt;code&gt;finally&lt;/code&gt;保证释放锁；&lt;/p&gt;
&lt;p&gt;可以使用&lt;code&gt;tryLock()&lt;/code&gt;尝试获取锁。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="线程池"&gt;线程池
&lt;/h3&gt;&lt;p&gt;（线程池感觉都写的不是很明白）&lt;/p&gt;
&lt;p&gt;Java语言虽然内置了多线程支持，启动一个新线程非常方便，但是，创建线程需要操作系统资源（线程资源，栈空间等），频繁创建和销毁大量线程需要消耗大量时间。&lt;/p&gt;
&lt;p&gt;如果可以复用一组线程：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌─────┐ execute ┌──────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│Task1│─────────▶│ThreadPool │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├─────┤ │┌───────┐┌───────┐│
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│Task2│ ││Thread1││Thread2││
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├─────┤ │└───────┘└───────┘│
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│Task3│ │┌───────┐┌───────┐│
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├─────┤ ││Thread3││Thread4││
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│Task4│ │└───────┘└───────┘│
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├─────┤ └──────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│Task5│
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├─────┤
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│Task6│
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└─────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;那么我们就可以把很多小任务让一组线程来执行，而不是一个任务对应一个新线程。这种能接收大量小任务并进行分发处理的就是线程池。&lt;/p&gt;
&lt;p&gt;简单地说，线程池内部维护了若干个线程，没有任务的时候，这些线程都处于等待状态。如果有新任务，就分配一个空闲线程执行。如果所有线程都处于忙碌状态，新任务要么放入队列等待，要么增加一个新线程进行处理。&lt;/p&gt;
&lt;p&gt;Java标准库提供了&lt;code&gt;ExecutorService&lt;/code&gt;接口表示线程池，它的典型用法如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 创建固定大小的线程池:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ExecutorService&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Executors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newFixedThreadPool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 提交任务:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;因为&lt;code&gt;ExecutorService&lt;/code&gt;只是接口，Java标准库提供的几个常用实现类有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FixedThreadPool：线程数固定的线程池；&lt;/li&gt;
&lt;li&gt;CachedThreadPool：线程数根据任务动态调整的线程池；&lt;/li&gt;
&lt;li&gt;SingleThreadExecutor：仅单线程执行的线程池。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;创建这些线程池的方法都被封装到&lt;code&gt;Executors&lt;/code&gt;这个类中。我们以&lt;code&gt;FixedThreadPool&lt;/code&gt;为例，看看线程池的执行逻辑：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// thread-pool&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;java.util.concurrent.*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 创建一个固定大小的线程池:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ExecutorService&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;es&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Executors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newFixedThreadPool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;es&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 关闭线程池:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;es&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;shutdown&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Task&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Runnable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@Override&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;start task &amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InterruptedException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;end task &amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;我们观察执行结果，一次性放入6个任务，由于线程池只有固定的4个线程，因此，前4个任务会同时执行，等到有线程空闲后，才会执行后面的两个任务。&lt;/p&gt;
&lt;p&gt;线程池在程序结束的时候要关闭。使用&lt;code&gt;shutdown()&lt;/code&gt;方法关闭线程池的时候，它会等待正在执行的任务先完成，然后再关闭。&lt;code&gt;shutdownNow()&lt;/code&gt;会立刻停止正在执行的任务，&lt;code&gt;awaitTermination()&lt;/code&gt;则会等待指定的时间让线程池关闭。&lt;/p&gt;
&lt;p&gt;如果我们把线程池改为&lt;code&gt;CachedThreadPool&lt;/code&gt;，由于这个线程池的实现会根据任务数量动态调整线程池的大小，所以6个任务可一次性全部同时执行。&lt;/p&gt;
&lt;p&gt;如果我们想把线程池的大小限制在4～10个之间动态调整怎么办？我们查看&lt;code&gt;Executors.newCachedThreadPool()&lt;/code&gt;方法的源码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ExecutorService&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;newCachedThreadPool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ThreadPoolExecutor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MAX_VALUE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;60L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TimeUnit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SynchronousQueue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Runnable&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;因此，想创建指定动态范围的线程池，可以这么写：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ExecutorService&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;es&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ThreadPoolExecutor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;60L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TimeUnit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SynchronousQueue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Runnable&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="scheduledthreadpool"&gt;ScheduledThreadPool
&lt;/h4&gt;&lt;p&gt;还有一种任务，需要定期反复执行，例如，每秒刷新证券价格。这种任务本身固定，需要反复执行的，可以使用&lt;code&gt;ScheduledThreadPool&lt;/code&gt;。放入&lt;code&gt;ScheduledThreadPool&lt;/code&gt;的任务可以定期反复执行。&lt;/p&gt;
&lt;p&gt;创建一个&lt;code&gt;ScheduledThreadPool&lt;/code&gt;仍然是通过&lt;code&gt;Executors&lt;/code&gt;类：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ScheduledExecutorService&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Executors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newScheduledThreadPool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;我们可以提交一次性任务，它会在指定延迟后只执行一次：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 1秒后执行一次性任务:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;one-time&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TimeUnit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果任务以固定的每3秒执行，我们可以这样写：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 2秒后开始执行定时任务，每3秒执行:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;scheduleAtFixedRate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;fixed-rate&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TimeUnit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果任务以固定的3秒为间隔执行，我们可以这样写：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 2秒后开始执行定时任务，以3秒为间隔执行:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;scheduleWithFixedDelay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;fixed-delay&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TimeUnit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SECONDS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;注意FixedRate和FixedDelay的区别。FixedRate是指任务总是以固定时间间隔触发，不管任务执行多长时间：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│░░░░ │░░░░░░ │░░░ │░░░░░ │░░░ 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├───────┼───────┼───────┼───────┼────▶
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│◀─────▶│◀─────▶│◀─────▶│◀─────▶│
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;而FixedDelay是指，上一次任务执行完毕后，等待固定的时间间隔，再执行下一次任务：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│░░░│ │░░░░░│ │░░│ │░
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└───┼───────┼─────┼───────┼──┼───────┼──▶
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │◀─────▶│ │◀─────▶│ │◀─────▶│
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;因此，使用&lt;code&gt;ScheduledThreadPool&lt;/code&gt;时，我们要根据需要选择执行一次、FixedRate执行还是FixedDelay执行。&lt;/p&gt;
&lt;p&gt;还可以思考下面的问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在FixedRate模式下，假设每秒触发，如果某次任务执行时间超过1秒，后续任务会不会并发执行？&lt;/li&gt;
&lt;li&gt;如果任务抛出了异常，后续任务是否继续执行？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Java标准库还提供了一个&lt;code&gt;java.util.Timer&lt;/code&gt;类，这个类也可以定期执行任务，但是，一个&lt;code&gt;Timer&lt;/code&gt;会对应一个&lt;code&gt;Thread&lt;/code&gt;，所以，一个&lt;code&gt;Timer&lt;/code&gt;只能定期执行一个任务，多个定时任务必须启动多个&lt;code&gt;Timer&lt;/code&gt;，而一个&lt;code&gt;ScheduledThreadPool&lt;/code&gt;就可以调度多个定时任务，所以，我们完全可以用&lt;code&gt;ScheduledThreadPool&lt;/code&gt;取代旧的&lt;code&gt;Timer&lt;/code&gt;。&lt;/p&gt;
&lt;h4 id="小结-10"&gt;小结
&lt;/h4&gt;&lt;p&gt;JDK提供了&lt;code&gt;ExecutorService&lt;/code&gt;实现了线程池功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;线程池内部维护一组线程，可以高效执行大量小任务；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Executors&lt;/code&gt;提供了静态方法创建不同类型的&lt;code&gt;ExecutorService&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;必须调用&lt;code&gt;shutdown()&lt;/code&gt;关闭&lt;code&gt;ExecutorService&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ScheduledThreadPool&lt;/code&gt;可以定期调度多个任务。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;</description></item><item><title>在Linux(CentOS)系统上部署Minecraft服务器</title><link>https://ottercoconut.github.io/p/%E5%9C%A8linuxcentos%E7%B3%BB%E7%BB%9F%E4%B8%8A%E9%83%A8%E7%BD%B2minecraft%E6%9C%8D%E5%8A%A1%E5%99%A8/</link><pubDate>Wed, 19 Mar 2025 18:48:59 +0800</pubDate><guid>https://ottercoconut.github.io/p/%E5%9C%A8linuxcentos%E7%B3%BB%E7%BB%9F%E4%B8%8A%E9%83%A8%E7%BD%B2minecraft%E6%9C%8D%E5%8A%A1%E5%99%A8/</guid><description>&lt;p&gt;笔者近日配置好了物理服务器，便想利用起来建一个我的世界服务器，经熬夜研究后成功，将本攻略分享出来，希望能帮到大家，尤其是没有公网环境的Linux用户(像我一样)&lt;/p&gt;
&lt;h3 id="参考网站"&gt;参考网站
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://docs.redhat.com/zh-cn/documentation/red_hat_build_of_openjdk/21/html-single/installing_and_using_red_hat_build_of_openjdk_21_on_rhel/index#installing-jre-on-rhel-using-yum_openjdk" target="_blank" rel="noopener"
 &gt;在 RHEL 上安装并使用红帽构建的 OpenJDK 21 | Red Hat Product Documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://doc.natfrp.com/launcher/usage.html" target="_blank" rel="noopener"
 &gt;SakuraFrp 启动器安装 / 使用指南 | SakuraFrp 帮助文档&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://docs.docker.com/engine/install/centos/" target="_blank" rel="noopener"
 &gt;CentOS | Docker Docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://www.bilibili.com/video/BV1iv4y1P7wJ/?spm_id_from=333.1007.top_right_bar_window_history.content.click&amp;amp;vd_source=c8beb52bf015e61e5378008c684545a4" target="_blank" rel="noopener"
 &gt;Linux终端开服教程★无面板★Minecraft_哔哩哔哩_bilibili&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;来自B站的UP主&lt;code&gt;翱翔大使&lt;/code&gt;，是全篇的主要思路来源&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="java配置"&gt;Java配置
&lt;/h2&gt;&lt;p&gt;运行我的世界需要，须对应版本的Java环境，笔者这里安装的是OpenJDK21&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo yum install java-21-openjdk
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;java -version //验证是否成功安装
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果服务器有多个Java版本，可以用&lt;code&gt;alternatives&lt;/code&gt;进行版本切换&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;alternatives --config java
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如图，我们输入&lt;code&gt;2&lt;/code&gt;并回车，就切换到了需要的版本&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/Minecraft-server/Screenshot_2025-03-19_191616.png" alt="Screenshot_2025-03-19_191616.png" loading="lazy" /&gt;&lt;/p&gt;
&lt;h2 id="游戏部署"&gt;游戏部署
&lt;/h2&gt;&lt;p&gt;首先在下面这个网址下载Minecraft的服务器端，这里我下的是支持Fabric的Banner(1.20.1)&lt;/p&gt;
&lt;p&gt;[MohistMC](&lt;a class="link" href="https://www.mohistmc.com/" target="_blank" rel="noopener"
 &gt;MohistMC - 主页&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/Minecraft-server/Screenshot_2025-03-19_185204.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/Minecraft-server/Screenshot_2025-03-19_185231.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;下载完成后是个类似&lt;code&gt;banner-1.20.1-800-server.jar&lt;/code&gt;的文件，接下来打开SSH软件，在服务器上操作：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /home/username //切换到个人文件夹或者想安装的位置
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir Minecraft //创建存放游戏的文件夹
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; Minecraft
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;我们用SSH软件中的SFTP功能(或其他文件传输功能)，将刚才的游戏文件&lt;code&gt;banner-1.20.1-800-server.jar&lt;/code&gt;拷贝到新建的文件夹&lt;code&gt;/home/username/Mineraft&lt;/code&gt;中&lt;/p&gt;
&lt;p&gt;接着我们来写一个服务器的启动脚本&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nano start.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;其中内容如下填写，但注意各参数的作用&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-Xmx&lt;/code&gt;是最大分配内存，&lt;code&gt;-Xms&lt;/code&gt;是最小分配内存，笔者有32GB内存，为游戏分配了6G(其实可以多分点)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;banner-1.20.1-800-server.jar&lt;/code&gt;是刚才下载的游戏文件名&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;java -Xmx6144M -Xms6144m -jar banner-1.20.1-800-server.jar
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;stty &lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;按&lt;code&gt;Ctrl + O&lt;/code&gt;写入，&lt;code&gt;Enter&lt;/code&gt;确认写入，&lt;code&gt;Ctrl + X&lt;/code&gt;退出&lt;/p&gt;
&lt;p&gt;接着为&lt;code&gt;start.sh&lt;/code&gt;赋权，避免无权限访问的情况&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod &lt;span class="m"&gt;777&lt;/span&gt; start.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;然后安装&lt;code&gt;screen&lt;/code&gt;，简单来说，&lt;code&gt;screen&lt;/code&gt;是帮用户创建独立会话，并可以随时恢复的工具&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;yum install screen
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;screen&lt;/code&gt;有如下几个常用命令&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;screen -S &lt;span class="o"&gt;[&lt;/span&gt;name&lt;span class="o"&gt;]&lt;/span&gt; //新建名为&lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;的screen
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;screen -ls //列出所有运行中的screen的名称和端口
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;screen -r &lt;span class="o"&gt;[&lt;/span&gt;port&lt;span class="o"&gt;]&lt;/span&gt; //返回端口号为port的screen
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;接着，新建一个&lt;code&gt;screen&lt;/code&gt;运行脚本&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;screen -S Minecraft
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;在新出现的会话中，运行&lt;code&gt;start.sh&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./start.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;然后一路顺畅，笔者在这里没有遇到报错，最后来到&lt;code&gt;...EULA...&lt;/code&gt;让我们同意EULA协议，输入&lt;code&gt;true&lt;/code&gt;后回车，等待一下，游戏服务器就在&lt;code&gt;25565&lt;/code&gt;端口上成功运行了&lt;/p&gt;
&lt;p&gt;若想离开Minecraft的这个&lt;code&gt;screen&lt;/code&gt;按下&lt;code&gt;Ctrl+A+D&lt;/code&gt;即可&lt;/p&gt;
&lt;p&gt;关于游戏规则的更改(比如”是否允许非正版玩家加入“)，需要修改&lt;code&gt;server.properties&lt;/code&gt;的内容&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;关于连接，如果是云服务器，在管理界面映射一下端口，然后在客户端的Minecraft中连接&lt;code&gt;域名:端口&lt;/code&gt;即可&lt;/p&gt;
&lt;p&gt;但是像笔者这样的物理服务器，或者说安装了Linux的设备，个人PC，在没有公网IP的情况下，就要继续内网穿透了&lt;/p&gt;
&lt;h2 id="内网穿透"&gt;内网穿透
&lt;/h2&gt;&lt;p&gt;笔者在这里使用我的世界领域中比较有名且良心的&lt;code&gt;SakuraFrp&lt;/code&gt;进行内网穿透，其它工具也大同小异&lt;/p&gt;
&lt;h3 id="docker"&gt;Docker
&lt;/h3&gt;&lt;p&gt;Linux上的&lt;code&gt;SakuraFrp&lt;/code&gt;是基于Docker运行的，所以下面我们先部署Docker，操作完全根据官方文档进行&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dnf -y install dnf-plugins-core
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;笔者在下面这遇到了安装速度十分缓慢，和下载失败的问题，重新执行命令再执行一次便解决了&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;安装完毕后&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; --now docker
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo docker run hello-world
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;上面的这个&lt;code&gt;run hello-world&lt;/code&gt;测试极有可能失败，下面来解决这个问题，参考了下面两篇文章：&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://blog.csdn.net/Fengdf666/article/details/140236208" target="_blank" rel="noopener"
 &gt;【完全解决】Docker安装完成运行hello-world镜像失败：Unable to find image ‘hello-world:latest‘ locallylatest:_unable to find image &amp;lsquo;hello-world:latest&amp;rsquo; locally-CSDN博客&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://www.cnblogs.com/paul-liang/p/18384633" target="_blank" rel="noopener"
 &gt;Docker运行hello-world镜像失败或超时 - Paul7777 - 博客园&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;综合上面二者，最终是能解决问题的，先来配置&lt;code&gt;daemon&lt;/code&gt;文件&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nano /etc/docker/daemon.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;复制下面的内容进去&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在笔者测试的时间(2025/3/19)下面的镜像源还是可用的&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;registry-mirrors&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://h59pkpv6.mirror.aliyuncs.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://registry.docker-cn.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://docker.mirrors.ustc.edu.cn&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://hub-mirror.c.163.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://mirror.baidubce.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://do.nark.eu.org&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://dc.j8.work&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://docker.m.daocloud.io&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://dockerproxy.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://docker.nju.edu.cn&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;保存 + 退出，接下来重启docker，再执行一次测试&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl daemon-reload
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl restart docker
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run hello-world
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;笔者到这就已经成功安装好docker了，若是测试仍不通过，请检查&lt;code&gt;daemon.json&lt;/code&gt;的内容，是否少了或者多了逗号和括号&lt;/p&gt;
&lt;h3 id="sakurafrp"&gt;SakuraFrp
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;SakuraFrp&lt;/code&gt;在Linux上的部署，官方文档给出了详细的方案&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/Minecraft-server/Screenshot_2025-03-19_203047.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;首先在终端以管理员身份运行&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo bash -c &lt;span class="s2"&gt;&amp;#34;. &amp;lt;(curl -sSL https://doc.natfrp.com/launcher.sh)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;安装好后，应该是会自动输出日志，并需要填写访问密钥，这个(或者说接下来的操作)可以在&lt;code&gt;SakuraFrp&lt;/code&gt;官网的管理面板找到&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/Minecraft-server/Screenshot_2025-03-19_203530.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;登录好之后就能看到其日志文件，下面是常规的启动并查看日志的操作&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker start natfrp-service
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker logs natfrp-service
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如图，接下来需要用物理方式操作下服务器&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/Minecraft-server/Image_146159838978722.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;打开浏览器(一般Linux自带Firefox)访问“使用”后面的网址打开&lt;code&gt;WebUI&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;然后看到“隧道”那什么都没有，只有一个加号，这时我们在打开&lt;code&gt;SakuraFrp&lt;/code&gt;的管理面板，找到服务下的&lt;code&gt;隧道列表&lt;/code&gt;，新建两个隧道，如图所示：&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/Minecraft-server/Screenshot_2025-03-19_204855.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/Minecraft-server/Screenshot_2025-03-19_205010.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;第一个端口号为7102的是服务器上&lt;code&gt;SakuraFrp&lt;/code&gt;的&lt;code&gt;WebUI&lt;/code&gt;，以便远程管理&lt;/p&gt;
&lt;p&gt;第二个端口号为25565的是Minecraft的服务器端&lt;/p&gt;
&lt;p&gt;回到&lt;code&gt;WebUI&lt;/code&gt;界面刷新一下就能看到刚刚创建好的两个隧道了，我们分别双击，然后回到终端的日志界面&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/Minecraft-server/Image_146585201484185.png" alt="" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;如图的红色字符的链接，就是&lt;code&gt;WebUI&lt;/code&gt;和Minecraft的远程访问链接，将Minecraft对应的复制到游戏中即可连接上&lt;/p&gt;
&lt;h2 id="结语"&gt;结语
&lt;/h2&gt;&lt;p&gt;大功告成！(笔者服务器出生地的截图 &amp;gt;w&amp;lt;)&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/Minecraft-server/792C7ECDA8518FCCDC8FA8E5E4E726CF.png" alt="" loading="lazy" /&gt;&lt;/p&gt;</description></item><item><title>Redis</title><link>https://ottercoconut.github.io/p/redis/</link><pubDate>Tue, 18 Mar 2025 15:41:00 +0800</pubDate><guid>https://ottercoconut.github.io/p/redis/</guid><description>&lt;p&gt;Redis（Remote Dictionary Server）是一个高性能的开源内存数据结构存储系统，常被用作数据库、缓存和消息代理。&lt;/p&gt;
&lt;h3 id="参考网站"&gt;参考网站
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://zhuanlan.zhihu.com/p/411888708" target="_blank" rel="noopener"
 &gt;知乎 超强、超详细Redis入门教程&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://blog.csdn.net/wenwenaier/article/details/121878831" target="_blank" rel="noopener"
 &gt;CSDN【Redis二三事】一套超详细的Redis学习教程（步骤图片+实操）&amp;mdash;第一集&lt;/a&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;详细，附有业务场景的实例&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="数据结构"&gt;数据结构
&lt;/h2&gt;&lt;p&gt;Redis包含五大数据类型：字符串(&lt;code&gt;string&lt;/code&gt;), 列表(&lt;code&gt;list&lt;/code&gt;), 哈希(&lt;code&gt;hash&lt;/code&gt;), 集合(&lt;code&gt;set&lt;/code&gt;), 集合(&lt;code&gt;zset&lt;/code&gt;)&lt;/p&gt;
&lt;h3 id="string"&gt;string
&lt;/h3&gt;&lt;p&gt;Redis 最基本的数据类型，每个键对应一个值，值可以是文本、数字或二进制数据，最大存储 512MB。支持字符串拼接、截取、递增递减等操作，适用于缓存数据、计数器（如访问量统计）、分布式锁等场景。&lt;/p&gt;
&lt;h4 id="基础操作"&gt;基础操作
&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;set key value
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;get key
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;del key 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="添加修改多个数据"&gt;添加修改多个数据
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mset key1 value1 key2 value2...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="获取多个数据"&gt;获取多个数据
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mget key1 key2...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="获取数据的字符个数"&gt;获取数据的字符个数
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;strlen key
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//例如
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;set name1 nosql
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;strlen name1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//输出为: 5
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="追加信息"&gt;追加信息
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;append key value
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//例如
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;append name1 name
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;get name1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/*输出为: nosqlname*/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="多数据操作与单数据操作"&gt;多数据操作与单数据操作
&lt;/h5&gt;&lt;ul&gt;
&lt;li&gt;单指令执行 n 条指令需要 n次发送 + n次处理 + n次返回&lt;/li&gt;
&lt;li&gt;多指令执行 n 条指令需要 1次发送 + n次处理 + 1次返回&lt;/li&gt;
&lt;li&gt;数据量较大时，多指令消耗的时间远远少于单指令&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="扩展操作"&gt;扩展操作
&lt;/h4&gt;&lt;h5 id="设置数值数据增加减少指定范围的值"&gt;设置数值数据增加/减少指定范围的值
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;incrby key increment
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;decrby key increment
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="对字符串类型进行数值操作"&gt;对字符串类型进行数值操作
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; set mynum &amp;#34;2&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;OK
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; get mynum
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;#34;2&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; incr mynum
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(integer) 3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; get mynum
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;#34;3&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;遇到数值操作，redis会自动将字符串类型转换成数值&lt;/p&gt;
&lt;h4 id="string类型数值操作的注意事项"&gt;string类型数值操作的注意事项
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;数据操作不成功的反馈与数据正常操作之间的差异
&lt;ul&gt;
&lt;li&gt;表示运行结果是否成功
&lt;ul&gt;
&lt;li&gt;（integer）0-&amp;gt;false 失败&lt;/li&gt;
&lt;li&gt;（integer）1-&amp;gt;true 成功&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;表示运行结果值
&lt;ul&gt;
&lt;li&gt;（integer）3-&amp;gt;3 3个&lt;/li&gt;
&lt;li&gt;（integer）1-&amp;gt;1 1个&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;数据未获取到
&lt;ul&gt;
&lt;li&gt;（&amp;lsquo;&amp;rsquo;nil&amp;rsquo;&amp;rsquo;）等同于&amp;rsquo;&amp;rsquo;null&amp;rsquo;'&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;数据最大存储量
&lt;ul&gt;
&lt;li&gt;512MB&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;数值计算最大范围（&amp;lsquo;&amp;lsquo;java&amp;rsquo;&amp;lsquo;中的&amp;rsquo;&amp;rsquo;long&amp;rsquo;&amp;lsquo;的最大值）
&lt;ul&gt;
&lt;li&gt;9223372036854775807&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="hash"&gt;hash
&lt;/h3&gt;&lt;p&gt;类似于小型的键值存储，适用于存储结构化数据，如用户信息（ID、姓名、邮箱等），相比 &lt;code&gt;String&lt;/code&gt; 类型更节省内存，因为多个字段共享同一个键。可以对字段进行单独操作，避免整体读取修改，适用于存储对象、会话信息等。&lt;/p&gt;
&lt;h4 id="基础操作-1"&gt;基础操作
&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hset key field value //添加/修改数据
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hget key field //获取数据
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hgetall key
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hdel key field1 [field2]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="添加修改多个数据-1"&gt;添加/修改多个数据
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hmset key field1 value1 field2 value2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="获取多个数据-1"&gt;获取多个数据
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hmget key field1 field2...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="获取哈希表中字段的数量"&gt;获取哈希表中字段的数量
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hlen key
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="获取哈希表中是否存在指定的字段"&gt;获取哈希表中是否存在指定的字段
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hexists key field
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="扩展操作-1"&gt;扩展操作
&lt;/h4&gt;&lt;h5 id="获取哈希表中所有字段名或字段值"&gt;获取哈希表中所有字段名或字段值
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hkeys key
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hvals key
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="设置指定字段的数值数据增加指定范围的值"&gt;设置指定字段的数值数据增加指定范围的值
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hincrby key field increment
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="综合示例"&gt;综合示例
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//建立哈希，并赋值
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; HMSET user:001 username antirez password P1pp0 age 34 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;OK
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//列出哈希的内容
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; HGETALL user:001 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1) &amp;#34;username&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2) &amp;#34;antirez&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3) &amp;#34;password&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4) &amp;#34;P1pp0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;5) &amp;#34;age&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;6) &amp;#34;34&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//更改哈希中的某一个值
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; HSET user:001 password 12345 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(integer) 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//再次列出哈希的内容
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; HGETALL user:001 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1) &amp;#34;username&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2) &amp;#34;antirez&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3) &amp;#34;password&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4) &amp;#34;12345&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;5) &amp;#34;age&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;6) &amp;#34;34&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="hash类型数据操作的注意事项"&gt;hash类型数据操作的注意事项
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;1.&lt;code&gt;hash&lt;/code&gt;类型下的&lt;code&gt;value&lt;/code&gt;&lt;strong&gt;只能存储字符串&lt;/strong&gt;，不允许存储其他数据类型，不存在嵌套现象。如果数据未获取到，对应的值为（&lt;code&gt;nil&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;2.每个&lt;code&gt;hash&lt;/code&gt;可以存储2^23-1个键值对&lt;/li&gt;
&lt;li&gt;3.&lt;code&gt;hash&lt;/code&gt;类型十分贴近对象的数据存储形式，并且可以灵活添加对象属性。但hash设计初衷不是为了存储大量对象而设计的，切记不可滥用，&lt;strong&gt;更不可以将hash作为对象列表使用&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;4.&lt;code&gt;hgetall&lt;/code&gt;操作可以获取全部属性，如果内部&lt;code&gt;field&lt;/code&gt;过多，遍历整体数据效率就会很低，有可能成为数据访问瓶颈&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="list"&gt;list
&lt;/h3&gt;&lt;p&gt;基于双向链表实现，可以从头部（左侧）或尾部（右侧）快速插入和删除元素，同时支持指定范围的索引读取。适合实现消息队列、时间轴（如微博动态）、任务调度等应用，尤其适用于需要按照插入顺序处理数据的场景。&lt;/p&gt;
&lt;h4 id="基础操作-2"&gt;基础操作
&lt;/h4&gt;&lt;h5 id="添加修改数据"&gt;添加/修改数据
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lpush key value1 [value2]... //从左边进
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rpush key value1 [value2]... /*从右边进*/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="获取数据"&gt;获取数据
&lt;/h5&gt;&lt;p&gt;关于&lt;code&gt;lrange&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;lrange用来获取指定范围的元素&lt;/li&gt;
&lt;li&gt;-1 代表倒数第一个元素&lt;/li&gt;
&lt;li&gt;列表元素索引从位置0开始&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lrange key start stop
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lindex key index
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lien key
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="获取并移除数据"&gt;获取并移除数据
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lpop key
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rpop key
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="移除指定数据"&gt;移除指定数据
&lt;/h5&gt;&lt;p&gt;关于&lt;code&gt;lrem&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;参数&lt;code&gt;count&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;count &amp;gt; 0&lt;/code&gt; → 从头（左侧）开始删除&lt;code&gt;count&lt;/code&gt;个匹配的&lt;code&gt;value&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;count &amp;lt; 0&lt;/code&gt; → 从尾（右侧）开始删除&lt;code&gt;count&lt;/code&gt;个匹配的&lt;code&gt;value&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;count = 0&lt;/code&gt; → 删除&lt;strong&gt;所有匹配的&lt;code&gt;value&lt;/code&gt;&lt;/strong&gt;（等价于删除列表中所有该值的元素）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;如果&lt;code&gt;key&lt;/code&gt;不存在
&lt;ul&gt;
&lt;li&gt;返回 0&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;常用于&lt;strong&gt;去除列表中的重复元素或清理数据&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;lrem key count value
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="扩展操作-2"&gt;扩展操作
&lt;/h4&gt;&lt;h5 id="在规定时间内获取并移除数据"&gt;在规定时间内获取并移除数据
&lt;/h5&gt;&lt;p&gt;关于&lt;code&gt;blpop&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;参数&lt;code&gt;key1 [key2...]&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;可以提供多个列表的键名，&lt;code&gt;Redis&lt;/code&gt; 会按照顺序依次检查这些列表&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;参数&lt;code&gt;timeout&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;timeout &amp;gt; 0 → 如果列表为空，则最多等待 &lt;code&gt;timeout&lt;/code&gt; 秒&lt;/li&gt;
&lt;li&gt;timeout &amp;lt; 0 → 永远&lt;strong&gt;阻塞&lt;/strong&gt;，直到有数据可用&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;适用于&lt;strong&gt;任务队列、生产者-消费者模型&lt;/strong&gt;等场景&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;blpop key1 [key2] timeout
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brpop key1 [key2] timeout
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;示例&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;RPUSH list1 &amp;#34;a&amp;#34; &amp;#34;b&amp;#34; &amp;#34;c&amp;#34; // 列表内容：[&amp;#34;a&amp;#34;, &amp;#34;b&amp;#34;, &amp;#34;c&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;BLPOP list1 10 // 取出 &amp;#34;a&amp;#34;，返回 [&amp;#34;list1&amp;#34;, &amp;#34;a&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;BLPOP list1 10 // 取出 &amp;#34;b&amp;#34;，返回 [&amp;#34;list1&amp;#34;, &amp;#34;b&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;BLPOP list1 10 // 取出 &amp;#34;c&amp;#34;，返回 [&amp;#34;list1&amp;#34;, &amp;#34;c&amp;#34;]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;BLPOP list1 10 /* 列表为空，阻塞最多 10 秒，若无新元素，则返回 nil */
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="综合示例-1"&gt;综合示例
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//新建一个list叫做mylist，并在列表头部插入元素&amp;#34;1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; lpush mylist &amp;#34;1&amp;#34; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//返回当前mylist中的元素个数
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(integer) 1 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//在mylist右侧插入元素&amp;#34;2&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; rpush mylist &amp;#34;2&amp;#34; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(integer) 2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//在mylist左侧插入元素&amp;#34;0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; lpush mylist &amp;#34;0&amp;#34; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(integer) 3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//列出mylist中从编号0到编号1的元素
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; lrange mylist 0 1 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1) &amp;#34;0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2) &amp;#34;1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//列出mylist中从编号0到倒数第一个元素
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; lrange mylist 0 -1 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1) &amp;#34;0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2) &amp;#34;1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3) &amp;#34;2&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="list类型数据操作注意事项"&gt;list类型数据操作注意事项
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;1.&lt;code&gt;list&lt;/code&gt;中保存的数据都是&lt;code&gt;string&lt;/code&gt;类型的，数据总容量是有限的，最多2^32-1个元素&lt;/li&gt;
&lt;li&gt;2.&lt;code&gt;list&lt;/code&gt;具有&amp;rsquo;&amp;lsquo;索引&amp;rsquo;&amp;lsquo;的概念，但是操作数据时通常以&amp;rsquo;&amp;lsquo;队列&amp;rsquo;&amp;lsquo;的形式进行入队出队操作，或以&amp;rsquo;&amp;lsquo;栈&amp;rsquo;&amp;lsquo;的形式进行入栈出栈操作&lt;/li&gt;
&lt;li&gt;3.获取全部数据操作结束索引设置为-1&lt;/li&gt;
&lt;li&gt;4.&lt;code&gt;list&lt;/code&gt;可以对数据进行&lt;code&gt;分页&lt;/code&gt;操作，通常第1页的信息来自于&lt;code&gt;list&lt;/code&gt;，第2页及更多的信息通过&amp;rsquo;&amp;lsquo;数据库&amp;rsquo;&amp;lsquo;的形式加载&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="set"&gt;set
&lt;/h3&gt;&lt;p&gt;由唯一无序的元素组成，支持 O(1) 时间复杂度的添加、删除和查找操作，并提供交集、并集、差集等集合运算，适用于去重、推荐系统中的共同关注、标签管理等应用。由于不允许重复元素，可以高效存储不重复的数据集合。&lt;/p&gt;
&lt;h4 id="基础操作-3"&gt;基础操作
&lt;/h4&gt;&lt;h5 id="添加数据"&gt;添加数据
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sadd key member1 [member2]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="获取全部数据"&gt;获取全部数据
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;smembers key
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="删除数据"&gt;删除数据
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;srem key member1 [member2]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="获取集合数据总量"&gt;获取集合数据总量
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;scard key
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="判断集合中是否包含指定数据"&gt;判断集合中是否包含指定数据
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sismember key member
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="进阶操作"&gt;进阶操作
&lt;/h4&gt;&lt;h5 id="随机获取集合中指定数量的数据"&gt;随机获取集合中指定数量的数据
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;srandmember key [count]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="随机获取集合中的某个数据并将其移出集合"&gt;随机获取集合中的某个数据并将其移出集合
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;spop key
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="求两个集合的交并差集"&gt;求两个集合的交、并、差集
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sinter key1 [key2]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sunion key1 [key2]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sdiff key1 [key2]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="求两个集合的交并差集-并存储到指定集合中"&gt;求两个集合的交、并、差集 并存储到指定集合中
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sinterstore destination key1 [key2]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sunionstore destination key1 [key2]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sdiffstore destination key1 [key2]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="将指定数据从原始集合中移动到目标集合中"&gt;将指定数据从原始集合中移动到目标集合中
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;smove source destination member
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="综合示例-2"&gt;综合示例
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//向集合myset中加入一个新元素&amp;#34;one&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; sadd myset &amp;#34;one&amp;#34; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(integer) 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; sadd myset &amp;#34;two&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(integer) 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//列出集合myset中的所有元素
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; smembers myset 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1) &amp;#34;one&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2) &amp;#34;two&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//判断元素1是否在集合myset中，返回1表示存在
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; sismember myset &amp;#34;one&amp;#34; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(integer) 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//判断元素3是否在集合myset中，返回0表示不存在
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; sismember myset &amp;#34;three&amp;#34; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(integer) 0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//新建一个新的集合yourset
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; sadd yourset &amp;#34;1&amp;#34; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(integer) 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; sadd yourset &amp;#34;2&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(integer) 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; smembers yourset
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1) &amp;#34;1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2) &amp;#34;2&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//对两个集合求并集
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; sunion myset yourset 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1) &amp;#34;1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2) &amp;#34;one&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3) &amp;#34;2&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4) &amp;#34;two&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="set类型数据操作的注意事项"&gt;set类型数据操作的注意事项
&lt;/h4&gt;&lt;ul&gt;
&lt;li&gt;set类型&lt;code&gt;不允许数据重复&lt;/code&gt;，如果添加的数据在set中已经存在，将只&lt;code&gt;保留一份&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;set虽然和hash的&lt;code&gt;存储结构相同&lt;/code&gt;，但是&lt;code&gt;无法启用hash中存储值的空间&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="zset"&gt;zset
&lt;/h3&gt;&lt;p&gt;在 Set 的基础上增加了一个分数（score），并按分数排序，支持范围查询、按分数排名等操作。适用于排行榜（如游戏积分榜）、优先级队列（如定时任务）、时间排序数据存储（如文章阅读量排名）等需要按权重排序的场景。&lt;/p&gt;
&lt;h4 id="基础操作-4"&gt;基础操作
&lt;/h4&gt;&lt;h5 id="添加数据-1"&gt;添加数据
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zadd key score1 member1 [score2 member2]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="获取全部数据-1"&gt;获取全部数据
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zrange key start stop [WITHSCORES] //按从小到大的顺序展示
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zrevrange key start stop [WITHSCORES] //按从大到小的顺序展示
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="删除数据-1"&gt;删除数据
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zrem key member [member...]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="按条件获取数据"&gt;按条件获取数据
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zrangebyscore key min max [Withscores][limit]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zrevrangebyscore key max min [withscores]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="按条件删除数据"&gt;按条件删除数据
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zremrangebyrank key start stop //按索引删除
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zremrangebyscore key min max 	//按范围删除
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="综合示例-3"&gt;综合示例
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//新增一个有序集合myzset，并加入一个元素baidu.com，给它赋予的序号是1：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; zadd myzset 1 baidu.com 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(integer) 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//向myzset中新增一个元素360.com，赋予它的序号是3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; zadd myzset 3 360.com 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(integer) 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//向myzset中新增一个元素google.com，赋予它的序号是2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; zadd myzset 2 google.com 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(integer) 1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//列出myzset的所有元素，同时列出其序号，可以看出myzset已经是有序的了。
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; zrange myzset 0 -1 with scores 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1) &amp;#34;baidu.com&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2) &amp;#34;1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3) &amp;#34;google.com&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4) &amp;#34;2&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;5) &amp;#34;360.com&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;6) &amp;#34;3&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;//只列出myzset的元素
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;127.0.0.1:6379&amp;gt; zrange myzset 0 -1 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1) &amp;#34;baidu.com&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2) &amp;#34;google.com&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3) &amp;#34;360.com&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="进阶操作-1"&gt;进阶操作
&lt;/h4&gt;&lt;h5 id="获取集合数据总量-1"&gt;获取集合数据总量
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zcard key
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zcount key min max
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h5 id="集合交并集操作"&gt;集合交、并集操作
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zinterstore destination numkeys key [key …]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;zunionstore destination numkeys key [key …]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="sorted_set类型数据操作的注意事项"&gt;sorted_set类型数据操作的注意事项
&lt;/h4&gt;&lt;p&gt;score保存的数据存储空间是64位，如果是整数范围是-9007199254740992~9007199254740992
score保存的数据也可以是一个双精度的double值，基于双精度浮点数的特征，可能会丢失精度，使用时候要慎重
sorted_set底层存储还是基于set结构的，因此数据不能重复，如果重复添加相同的数据，score值将被反复覆盖，保留最后一次修改的结果&lt;/p&gt;</description></item><item><title>MySQL</title><link>https://ottercoconut.github.io/p/mysql/</link><pubDate>Mon, 17 Mar 2025 20:06:34 +0800</pubDate><guid>https://ottercoconut.github.io/p/mysql/</guid><description>&lt;h3 id="参考网站"&gt;参考网站
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="http://xuesql.cn/" target="_blank" rel="noopener"
 &gt;自学SQL网(教程 视频 练习全套)&lt;/a&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;学完知识就有题做&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;&lt;a class="link" href="https://www.zhihu.com/question/30357711" target="_blank" rel="noopener"
 &gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://www.runoob.com/mysql/mysql-tutorial.html" target="_blank" rel="noopener"
 &gt;MySQL 教程 | 菜鸟教程&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://blog.csdn.net/weixin_43896929/article/details/120750965" target="_blank" rel="noopener"
 &gt;MySQL总结_sq连表-CSDN博客&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://liaoxuefeng.com/books/sql/relational/primary-key/index.html" target="_blank" rel="noopener"
 &gt;主键 - SQL教程 - 廖雪峰的官方网站&lt;/a&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;观感最好的教程&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="关系模型"&gt;关系模型
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;引用自 &lt;a class="link" href="https://liaoxuefeng.com/books/sql/relational/index.html" target="_blank" rel="noopener"
 &gt;关系模型 - SQL教程 - 廖雪峰的官方网站&lt;/a&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="主键"&gt;主键
&lt;/h3&gt;&lt;p&gt;在关系数据库中，一张表中的每一行数据被称为一条记录。一条记录就是由多个字段组成的。例如，&lt;code&gt;students&lt;/code&gt;表的两行记录：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;id&lt;/th&gt;
					&lt;th&gt;class id&lt;/th&gt;
					&lt;th&gt;name&lt;/th&gt;
					&lt;th&gt;gender&lt;/th&gt;
					&lt;th&gt;score&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;小明&lt;/td&gt;
					&lt;td&gt;M&lt;/td&gt;
					&lt;td&gt;90&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;小红&lt;/td&gt;
					&lt;td&gt;F&lt;/td&gt;
					&lt;td&gt;95&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;对于关系表，有个很重要的约束，就是&lt;strong&gt;任意两条记录不能重复&lt;/strong&gt;。不能重复不是指两条记录不完全相同，而是指&lt;strong&gt;能够通过某个字段唯一区分出不同的记录&lt;/strong&gt;，这个字段被称为&lt;em&gt;&lt;strong&gt;主键&lt;/strong&gt;&lt;/em&gt;。&lt;/p&gt;
&lt;p&gt;例如，假设我们把&lt;code&gt;name&lt;/code&gt;字段作为主键，那么通过名字&lt;code&gt;小明&lt;/code&gt;或&lt;code&gt;小红&lt;/code&gt;就能唯一确定一条记录。但是，这么设定，就没法存储同名的同学了，因为&lt;strong&gt;插入相同主键的两条记录是不被允许的&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;对主键的要求，最关键的一点是：记录一旦插入到表中，&lt;strong&gt;主键最好不要再修改，因为主键是用来唯一定位记录的&lt;/strong&gt;，修改了主键，会造成一系列的影响。&lt;/p&gt;
&lt;p&gt;由于主键的作用十分重要，如何选取主键会对业务开发产生重要影响。如果我们以学生的身份证号作为主键，似乎能唯一定位记录。然而，身份证号也是一种业务场景，如果身份证号升位了，或者需要变更，作为主键，不得不修改的时候，就会对业务产生严重影响。&lt;/p&gt;
&lt;p&gt;所以，选取主键的一个基本原则是：&lt;strong&gt;不使用任何业务相关的字段作为主键&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;因此，身份证号、手机号、邮箱地址这些看上去可以唯一的字段，均&lt;em&gt;不可&lt;/em&gt;用作主键。&lt;/p&gt;
&lt;p&gt;作为主键最好是完全业务无关的字段，我们一般把这个字段命名为&lt;code&gt;id&lt;/code&gt;。常见的可作为&lt;code&gt;id&lt;/code&gt;字段的类型有：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;自增整数类型：数据库会在插入数据时自动为每一条记录分配一个自增整数，这样我们就完全不用担心主键重复，也不用自己预先生成主键；&lt;/li&gt;
&lt;li&gt;全局唯一GUID类型：也称UUID，使用一种全局唯一的字符串作为主键，类似&lt;code&gt;8f55d96b-8acc-4636-8cb8-76bf8abc2f57&lt;/code&gt;。GUID算法通过网卡MAC地址、时间戳和随机数保证任意计算机在任意时间生成的字符串都是不同的，大部分编程语言都内置了GUID算法，可以自己预算出主键。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;对于大部分应用来说，通常自增类型的主键就能满足需求。我们在&lt;code&gt;students&lt;/code&gt;表中定义的主键也是&lt;code&gt;BIGINT NOT NULL AUTO_INCREMENT&lt;/code&gt;类型。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;如果使用INT自增类型，那么当一张表的记录数超过2147483647（约21亿）时，会达到上限而出错。使用BIGINT自增类型则可以最多约922亿亿条记录。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h4 id="小结"&gt;小结
&lt;/h4&gt;&lt;p&gt;主键是关系表中记录的唯一标识。主键的选取非常重要：主键不要带有业务含义，而应该使用BIGINT自增或者GUID类型。主键也不应该允许&lt;code&gt;NULL&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;可以使用多个列作为联合主键，但联合主键并不常用。&lt;/p&gt;
&lt;h3 id="外键"&gt;外键
&lt;/h3&gt;&lt;p&gt;当我们用主键唯一标识记录时，我们就可以在&lt;code&gt;students&lt;/code&gt;表中确定任意一个学生的记录：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;id&lt;/th&gt;
					&lt;th&gt;name&lt;/th&gt;
					&lt;th&gt;other columns&amp;hellip;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;小明&lt;/td&gt;
					&lt;td&gt;&amp;hellip;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;小红&lt;/td&gt;
					&lt;td&gt;&amp;hellip;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;我们还可以在&lt;code&gt;classes&lt;/code&gt;表中确定任意一个班级记录：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;id&lt;/th&gt;
					&lt;th&gt;name&lt;/th&gt;
					&lt;th&gt;other columns&amp;hellip;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;一班&lt;/td&gt;
					&lt;td&gt;&amp;hellip;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;二班&lt;/td&gt;
					&lt;td&gt;&amp;hellip;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;但是我们如何确定&lt;code&gt;students&lt;/code&gt;表的一条记录，例如，&lt;code&gt;id=1&lt;/code&gt;的小明，属于哪个班级呢？&lt;/p&gt;
&lt;p&gt;由于一个班级可以有多个学生，在关系模型中，这两个表的关系可以称为“一对多”，即一个&lt;code&gt;classes&lt;/code&gt;的记录可以对应多个&lt;code&gt;students&lt;/code&gt;表的记录。&lt;/p&gt;
&lt;p&gt;为了表达这种一对多的关系，我们需要在&lt;code&gt;students&lt;/code&gt;表中加入一列&lt;code&gt;class_id&lt;/code&gt;，让它的值与&lt;code&gt;classes&lt;/code&gt;表的某条记录相对应：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;id&lt;/th&gt;
					&lt;th&gt;class_id&lt;/th&gt;
					&lt;th&gt;name&lt;/th&gt;
					&lt;th&gt;other columns&amp;hellip;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;小明&lt;/td&gt;
					&lt;td&gt;&amp;hellip;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;小红&lt;/td&gt;
					&lt;td&gt;&amp;hellip;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;5&lt;/td&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;小白&lt;/td&gt;
					&lt;td&gt;&amp;hellip;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这样，我们就可以根据&lt;code&gt;class_id&lt;/code&gt;这个列直接定位出一个&lt;code&gt;students&lt;/code&gt;表的记录应该对应到&lt;code&gt;classes&lt;/code&gt;的哪条记录。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;小明的&lt;code&gt;class_id&lt;/code&gt;是&lt;code&gt;1&lt;/code&gt;，因此，对应的&lt;code&gt;classes&lt;/code&gt;表的记录是&lt;code&gt;id=1&lt;/code&gt;的一班；&lt;/li&gt;
&lt;li&gt;小红的&lt;code&gt;class_id&lt;/code&gt;是&lt;code&gt;1&lt;/code&gt;，因此，对应的&lt;code&gt;classes&lt;/code&gt;表的记录是&lt;code&gt;id=1&lt;/code&gt;的一班；&lt;/li&gt;
&lt;li&gt;小白的&lt;code&gt;class_id&lt;/code&gt;是&lt;code&gt;2&lt;/code&gt;，因此，对应的&lt;code&gt;classes&lt;/code&gt;表的记录是&lt;code&gt;id=2&lt;/code&gt;的二班。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在&lt;code&gt;students&lt;/code&gt;表中，通过&lt;code&gt;class_id&lt;/code&gt;的字段，&lt;strong&gt;可以把数据与另一张表关联起来&lt;/strong&gt;，这种列称为&lt;code&gt;外键&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;外键并不是通过列名实现的，而是通过定义外键约束实现的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-mysql" data-lang="mysql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONSTRAINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fk_class_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FOREIGN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;class_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;REFERENCES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;classes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;其中，外键约束的名称&lt;code&gt;fk_class_id&lt;/code&gt;可以任意，&lt;code&gt;FOREIGN KEY (class_id)&lt;/code&gt;指定了&lt;code&gt;class_id&lt;/code&gt;作为外键，&lt;code&gt;REFERENCES classes (id)&lt;/code&gt;指定了这个外键将关联到&lt;code&gt;classes&lt;/code&gt;表的&lt;code&gt;id&lt;/code&gt;列（即&lt;code&gt;classes&lt;/code&gt;表的主键）。&lt;/p&gt;
&lt;p&gt;通过定义外键约束，关系数据库可以保证无法插入无效的数据。即如果&lt;code&gt;classes&lt;/code&gt;表不存在&lt;code&gt;id=99&lt;/code&gt;的记录，&lt;code&gt;students&lt;/code&gt;表就无法插入&lt;code&gt;class_id=99&lt;/code&gt;的记录。&lt;/p&gt;
&lt;p&gt;由于外键约束会降低数据库的性能，大部分互联网应用程序为了追求速度，并不设置外键约束，而是仅靠应用程序自身来保证逻辑的正确性。这种情况下，&lt;code&gt;class_id&lt;/code&gt;仅仅是一个普通的列，只是它起到了外键的作用而已。&lt;/p&gt;
&lt;p&gt;要删除一个外键约束，也是通过&lt;code&gt;ALTER TABLE&lt;/code&gt;实现的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-mysql" data-lang="mysql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DROP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FOREIGN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fk_class_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;注意：删除外键约束并没有删除外键这一列。删除列是通过&lt;code&gt;DROP COLUMN ...&lt;/code&gt;实现的。&lt;/p&gt;
&lt;h4 id="多对多"&gt;多对多
&lt;/h4&gt;&lt;p&gt;通过一个表的外键关联到另一个表，我们可以定义出一对多关系。有些时候，还需要定义“多对多”关系。例如，一个老师可以对应多个班级，一个班级也可以对应多个老师，因此，班级表和老师表存在多对多关系。&lt;/p&gt;
&lt;p&gt;多对多关系实际上是通过两个一对多关系实现的，即通过一个中间表，关联两个一对多关系，就形成了多对多关系：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;teachers&lt;/code&gt;表：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;id&lt;/th&gt;
					&lt;th&gt;name&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;张老师&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;王老师&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;李老师&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;4&lt;/td&gt;
					&lt;td&gt;赵老师&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;classes&lt;/code&gt;表：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;id&lt;/th&gt;
					&lt;th&gt;name&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;一班&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;二班&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;中间表&lt;code&gt;teacher_class&lt;/code&gt;关联两个一对多关系：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;id&lt;/th&gt;
					&lt;th&gt;teacher_id&lt;/th&gt;
					&lt;th&gt;class_id&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;2&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;4&lt;/td&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;2&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;5&lt;/td&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;6&lt;/td&gt;
					&lt;td&gt;4&lt;/td&gt;
					&lt;td&gt;2&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;通过中间表&lt;code&gt;teacher_class&lt;/code&gt;可知&lt;code&gt;teachers&lt;/code&gt;到&lt;code&gt;classes&lt;/code&gt;的关系：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;id=1&lt;/code&gt;的张老师对应&lt;code&gt;id=1,2&lt;/code&gt;的一班和二班；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;id=2&lt;/code&gt;的王老师对应&lt;code&gt;id=1,2&lt;/code&gt;的一班和二班；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;id=3&lt;/code&gt;的李老师对应&lt;code&gt;id=1&lt;/code&gt;的一班；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;id=4&lt;/code&gt;的赵老师对应&lt;code&gt;id=2&lt;/code&gt;的二班。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;同理可知&lt;code&gt;classes&lt;/code&gt;到&lt;code&gt;teachers&lt;/code&gt;的关系：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;id=1&lt;/code&gt;的一班对应&lt;code&gt;id=1,2,3&lt;/code&gt;的张老师、王老师和李老师；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;id=2&lt;/code&gt;的二班对应&lt;code&gt;id=1,2,4&lt;/code&gt;的张老师、王老师和赵老师；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，通过中间表，我们就定义了一个“多对多”关系。&lt;/p&gt;
&lt;h4 id="一对一"&gt;一对一
&lt;/h4&gt;&lt;p&gt;一对一关系是指，一个表的记录对应到另一个表的唯一一个记录。&lt;/p&gt;
&lt;p&gt;例如，&lt;code&gt;students&lt;/code&gt;表的每个学生可以有自己的联系方式，如果把联系方式存入另一个表&lt;code&gt;contacts&lt;/code&gt;，我们就可以得到一个“一对一”关系：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;id&lt;/th&gt;
					&lt;th&gt;student_id&lt;/th&gt;
					&lt;th&gt;mobile&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;135xxxx6300&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;138xxxx2209&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;5&lt;/td&gt;
					&lt;td&gt;139xxxx8086&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;有细心的童鞋会问，既然是一对一关系，那为啥不给&lt;code&gt;students&lt;/code&gt;表增加一个&lt;code&gt;mobile&lt;/code&gt;列，这样就能合二为一了？&lt;/p&gt;
&lt;p&gt;如果业务允许，完全可以把两个表合为一个表。但是，有些时候，如果某个学生没有手机号，那么，&lt;code&gt;contacts&lt;/code&gt;表就不存在对应的记录。实际上，一对一关系准确地说，是&lt;code&gt;contacts&lt;/code&gt;表一对一对应&lt;code&gt;students&lt;/code&gt;表。&lt;/p&gt;
&lt;p&gt;还有一些应用会把一个大表拆成两个一对一的表，目的是把经常读取和不经常读取的字段分开，以获得更高的性能。例如，把一个大的用户表分拆为用户基本信息表&lt;code&gt;user_info&lt;/code&gt;和用户详细信息表&lt;code&gt;user_profiles&lt;/code&gt;，大部分时候，只需要查询&lt;code&gt;user_info&lt;/code&gt;表，并不需要查询&lt;code&gt;user_profiles&lt;/code&gt;表，这样就提高了查询速度。&lt;/p&gt;
&lt;h4 id="小结-1"&gt;小结
&lt;/h4&gt;&lt;p&gt;关系数据库通过外键可以实现一对多、多对多和一对一的关系。外键既可以通过数据库来约束，也可以不设置约束，仅依靠应用程序的逻辑来保证。&lt;/p&gt;
&lt;h3 id="索引"&gt;索引
&lt;/h3&gt;&lt;p&gt;在关系数据库中，如果有上万甚至上亿条记录，在查找记录的时候，想要获得非常快的速度，就需要使用索引。&lt;/p&gt;
&lt;p&gt;索引是关系数据库中对某一列或多个列的值进行预排序的数据结构。通过使用索引，可以让数据库系统不必扫描整个表，而是直接定位到符合条件的记录，这样就大大加快了查询速度。&lt;/p&gt;
&lt;p&gt;例如，对于&lt;code&gt;students&lt;/code&gt;表：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;id&lt;/th&gt;
					&lt;th&gt;class_id&lt;/th&gt;
					&lt;th&gt;name&lt;/th&gt;
					&lt;th&gt;gender&lt;/th&gt;
					&lt;th&gt;score&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;小明&lt;/td&gt;
					&lt;td&gt;M&lt;/td&gt;
					&lt;td&gt;90&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;2&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;小红&lt;/td&gt;
					&lt;td&gt;F&lt;/td&gt;
					&lt;td&gt;95&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;3&lt;/td&gt;
					&lt;td&gt;1&lt;/td&gt;
					&lt;td&gt;小军&lt;/td&gt;
					&lt;td&gt;M&lt;/td&gt;
					&lt;td&gt;88&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;如果要经常根据&lt;code&gt;score&lt;/code&gt;列进行查询，就可以对&lt;code&gt;score&lt;/code&gt;列创建索引：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;idx_score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;使用&lt;code&gt;ADD INDEX idx_score (score)&lt;/code&gt;就创建了一个名称为&lt;code&gt;idx_score&lt;/code&gt;，使用列&lt;code&gt;score&lt;/code&gt;的索引。索引名称是任意的，索引如果有多列，可以在括号里依次写上，例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;idx_name_score&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;索引的效率取决于索引列的值是否散列，即该列的值如果越互不相同，那么索引效率越高。反过来，如果记录的列存在大量相同的值，例如&lt;code&gt;gender&lt;/code&gt;列，大约一半的记录值是&lt;code&gt;M&lt;/code&gt;，另一半是&lt;code&gt;F&lt;/code&gt;，因此，对该列创建索引就没有意义。&lt;/p&gt;
&lt;p&gt;可以对一张表创建多个索引。索引的优点是提高了查询效率，缺点是在插入、更新和删除记录时，需要同时修改索引，因此，索引越多，插入、更新和删除记录的速度就越慢。&lt;/p&gt;
&lt;p&gt;对于主键，关系数据库会自动对其创建主键索引。使用主键索引的效率是最高的，因为主键会保证绝对唯一。&lt;/p&gt;
&lt;h4 id="唯一索引"&gt;唯一索引
&lt;/h4&gt;&lt;p&gt;在设计关系数据表的时候，看上去唯一的列，例如身份证号、邮箱地址等，因为他们具有业务含义，因此不宜作为主键。&lt;/p&gt;
&lt;p&gt;但是，这些列根据业务要求，又具有唯一性约束：即不能出现两条记录存储了同一个身份证号。这个时候，就可以给该列添加一个唯一索引。例如，我们假设&lt;code&gt;students&lt;/code&gt;表的&lt;code&gt;name&lt;/code&gt;不能重复：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INDEX&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uni_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;通过&lt;code&gt;UNIQUE&lt;/code&gt;关键字我们就添加了一个唯一索引。&lt;/p&gt;
&lt;p&gt;也可以只对某一列添加一个唯一约束而不创建唯一索引：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;CONSTRAINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uni_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;UNIQUE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这种情况下，&lt;code&gt;name&lt;/code&gt;列没有索引，但仍然具有唯一性保证。&lt;/p&gt;
&lt;p&gt;无论是否创建索引，对于用户和应用程序来说，使用关系数据库不会有任何区别。这里的意思是说，当我们在数据库中查询时，如果有相应的索引可用，数据库系统就会自动使用索引来提高查询效率，如果没有索引，查询也能正常执行，只是速度会变慢。因此，索引可以在使用数据库的过程中逐步优化。&lt;/p&gt;
&lt;h4 id="小结-2"&gt;小结
&lt;/h4&gt;&lt;p&gt;通过对数据库表创建索引，可以提高查询速度；&lt;/p&gt;
&lt;p&gt;通过创建唯一索引，可以保证某一列的值具有唯一性；&lt;/p&gt;
&lt;p&gt;数据库索引对于用户和应用程序来说都是透明的。&lt;/p&gt;
&lt;h2 id="select-查询"&gt;SELECT 查询
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;another_column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mytable&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;another_condition&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;movies&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;year&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="mi"&gt;2010&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;length_minutes&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="筛选数字属性列"&gt;&lt;strong&gt;筛选数字属性列&lt;/strong&gt;
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;关键字&lt;/th&gt;
					&lt;th&gt;&lt;/th&gt;
					&lt;th&gt;例&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;=, !=, &amp;lt; &amp;lt;=, &amp;gt;, ≥&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;col_name != 4&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;BETWEEN … AND …&lt;/td&gt;
					&lt;td&gt;在两个数之间&lt;/td&gt;
					&lt;td&gt;col_name BETWEEN 1.5 AND 10.5&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;NOT BETWEEN … AND …&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;col_name NOT BETWEEN 1 AND 10&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;IN (…)&lt;/td&gt;
					&lt;td&gt;在一个列表&lt;/td&gt;
					&lt;td&gt;col_name IN (2, 4, 6)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;NOT IN (…)&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;col_name NOT IN (1, 3, 5)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="筛选字符串属性列"&gt;&lt;strong&gt;筛选字符串属性列&lt;/strong&gt;
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;/th&gt;
					&lt;th&gt;&lt;/th&gt;
					&lt;th&gt;&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;=&lt;/td&gt;
					&lt;td&gt;完全等于&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;!= or &amp;lt;&amp;gt;&lt;/td&gt;
					&lt;td&gt;不等于&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;LIKE&lt;/td&gt;
					&lt;td&gt;没有用通配符等价于 =&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;NOT LIKE&lt;/td&gt;
					&lt;td&gt;没有用通配符等价于 !=&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;%&lt;/td&gt;
					&lt;td&gt;通配符&lt;/td&gt;
					&lt;td&gt;col_name LIKE &amp;ldquo;%AT%”&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;_(下划线)&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
					&lt;td&gt;col_name LIKE &amp;ldquo;AN_”&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*通配符*/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;col_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;%AT%&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*&amp;#34;AT&amp;#34;&amp;#34;AT*...&amp;#34;&amp;#34;...*AT&amp;#34;&amp;#34;...*AT*...&amp;#34;均满足条件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; &amp;#34;AT&amp;#34;前后可以有任意字符*/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;col_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIKE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;AN_&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*&amp;#34;AND&amp;#34;可以 &amp;#34;AN&amp;#34;&amp;#34;ANDD&amp;#34;均不行
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; 与&amp;#39;%&amp;#39;相似 但只代表一个字符*/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="过滤排序"&gt;过滤/排序
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*用DISTINCT关键字来指定某个或某些属性列唯一返回*/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DISTINCT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;another_column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mytable&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*让结果按一个或多个属性列做排序*/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;another_column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mytable&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* ASC 升序或 DESC 降序*/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ASC&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*LIMIT来指定只返回多少行结果 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; 用OFFSET来指定从哪一行开始返回*/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LIMIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;num_limit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFFSET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;num_offset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/*关于OFFSET 若要输出第N行(及之后)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; 则OFFSET的参数须为N-1 */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="例题"&gt;例题
&lt;/h4&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/MySQL/Screenshot_2025-03-11_132438.png" alt="例题1" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="select复习题"&gt;SELECT复习题
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/MySQL/Screenshot_2025-03-11_134213.png" alt="例题2" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="在查询中使用表达式"&gt;&lt;strong&gt;在查询中使用表达式&lt;/strong&gt;
&lt;/h3&gt;&lt;p&gt;实际上AS不仅用在表达式别名上，普通的属性列甚至是表（table）都可以取一个别名，这让SQL更容易理解&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;--属性列和表取别名的例子
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;better_column_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a_long_widgets_table_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mywidgets&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INNER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;widget_sales&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mywidgets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;widget_sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;widget_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;--包含表达式的例子
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;particle_speed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;half_particle_speed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--对结果做了一个除2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;physics_data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ABS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;particle_position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--（条件要求这个属性绝对值乘以10大于500）;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/MySQL/Screenshot_2025-03-13_164705.png" alt="例题3" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="在查询中进行统计"&gt;&lt;strong&gt;在查询中进行统计&lt;/strong&gt;
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/MySQL/v2-89b10c80ff69acdb02494042f55c59d2_1440w.webp" alt="样图1" loading="lazy" /&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AGG_FUNC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;column_or_expression&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aggregate_description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mytable&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;constraint_expression&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;常用统计函数:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Function&lt;/th&gt;
					&lt;th&gt;Description&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;COUNT(*) COUNT(column)&lt;/td&gt;
					&lt;td&gt;计数！COUNT(*) 统计数据行数，COUNT(column) 统计column非NULL的行数&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;MIN(column)&lt;/td&gt;
					&lt;td&gt;找column最小的一行&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;MAX(column)&lt;/td&gt;
					&lt;td&gt;找column最大的一行&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;AVG(column)&lt;/td&gt;
					&lt;td&gt;对column所有行取平均值&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;SUM(column)&lt;/td&gt;
					&lt;td&gt;对column所有行求和&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="分组统计"&gt;分组统计
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;GROUP BY&lt;/code&gt; 数据分组语法可以按某个&lt;code&gt;col_name&lt;/code&gt;对数据进行分组，如：&lt;code&gt;GROUP BY Year&lt;/code&gt;指对数据按年份分组， 相同年份的分到一个组里。如果把统计函数和&lt;code&gt;GROUP BY&lt;/code&gt;结合，那统计结果就是对分组内的数据统计了
&lt;code&gt;GROUP BY&lt;/code&gt; 分组结果的数据条数，就是分组数量，比如：&lt;code&gt;GROUP BY Year&lt;/code&gt;，全部数据里有几年，就返回几条数据， 不管是否应用了统计函数&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;--用分组的方式统计
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AGG_FUNC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;column_or_expression&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aggregate_description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mytable&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;constraint_expression&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/MySQL/Screenshot_2025-03-13_170736.png" alt="例题4" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;在 &lt;strong&gt;&lt;code&gt;GROUP BY&lt;/code&gt;&lt;/strong&gt; 分组语法中，我们知道数据库是先对数据做 &lt;strong&gt;&lt;code&gt;WHERE&lt;/code&gt;&lt;/strong&gt; ，然后对结果做分组，如果我们要对分组完的数据再筛选出几条如何办？
一个不常用的语法 &lt;strong&gt;&lt;code&gt;HAVING&lt;/code&gt;&lt;/strong&gt; 语法将用来解决这个问题，他可以对分组之后的数据再做&lt;code&gt;SELECT&lt;/code&gt;筛选&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;HAVING&lt;/code&gt;&lt;/strong&gt; 和 &lt;strong&gt;&lt;code&gt;WHERE&lt;/code&gt;&lt;/strong&gt; 语法一样，只不过作用的结果集不一样. 在我们例子数据表数据量小的情况下可能感觉 &lt;strong&gt;&lt;code&gt;HAVING&lt;/code&gt;&lt;/strong&gt; 没有什么用，但当你的数据量成千上万属性又很多时也许能帮上大忙&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="join-连接"&gt;JOIN 连接
&lt;/h3&gt;&lt;h4 id="数据库范式"&gt;数据库范式
&lt;/h4&gt;&lt;p&gt;数据库范式是数据表设计的规范，在范式规范下，数据库里每个表存储的重复数据降到最少(这有助于数据的一致性维护)同时在数据库范式下，表和表之间不再有很强的数据耦合，可以独立的增长(ie. 比如汽车引擎的增长和汽车的增长是完全独立的)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;another_table_column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mytable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--主表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INNER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;another_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--要连接的表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mytable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;another_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--想象一下刚才讲的主键连接，两个相同的连成1条
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ASC&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LIMIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;num_limit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFFSET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;num_offset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;本例中&lt;code&gt;ON&lt;/code&gt;条件描述的关联关系:&lt;/p&gt;
&lt;h4 id="inner-join-内连接"&gt;&lt;strong&gt;&lt;code&gt;INNER JOIN&lt;/code&gt;&lt;/strong&gt; (内)连接
&lt;/h4&gt;&lt;p&gt; 先将两个表数据连接到一起，两个表中如果通过ID互相找不到的数据将会舍弃。此时，你可以将连表后的数据看作两个表的合并，SQL中的其他语句会在这个合并基础上 继续执行(想一下和之前的单表操作就一样了)
还有一个理解 &lt;strong&gt;&lt;code&gt;INNER JOIN&lt;/code&gt;&lt;/strong&gt; 的方式，就是把 &lt;strong&gt;&lt;code&gt;INNER JOIN&lt;/code&gt;&lt;/strong&gt; 想成两个集合的交集。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/MySQL/Screenshot_2025-03-11_142245.png" alt="例题5" loading="lazy" /&gt;&lt;/p&gt;
&lt;h4 id="outer-join外连接"&gt;&lt;code&gt;OUTER JOIN&lt;/code&gt;外连接
&lt;/h4&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;--用LEFT/RIGHT/FULL JOINs 做多表查询
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;another_column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mytable&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INNER&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;RIGHT&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;FULL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;another_table&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mytable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;another_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;matching_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ASC&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;LIMIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;num_limit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFFSET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;num_offset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;在表A 连接 B， &lt;strong&gt;&lt;code&gt;LEFT JOIN&lt;/code&gt;&lt;/strong&gt; 保留A的所有行，不管有没有能匹配上B，反过来 &lt;strong&gt;&lt;code&gt;RIGHT JOIN&lt;/code&gt;&lt;strong&gt;则保留所有B里的行。最后&lt;/strong&gt;&lt;code&gt;FULL JOIN&lt;/code&gt;&lt;/strong&gt; 不管有没有匹配上，同时保留A和B里的所有行&lt;/p&gt;
&lt;p&gt;将两个表数据1-1连接，保留A或B的原有行，如果某一行在另一个表不存在，会用 &lt;code&gt;NULL&lt;/code&gt;来填充结果数据。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/MySQL/Screenshot_2025-03-11_151348.png" alt="例题6" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="查询执行顺序"&gt;查询执行顺序
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/MySQL/v2-d414289449f1dcaaa8c81e13de989b57_1440w.webp" alt="样图2" loading="lazy" /&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;--这才是完整的SELECT查询
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DISTINCT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AGG_FUNC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;column_or_expression&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mytable&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;another_table&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mytable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;another_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;constraint_expression&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;HAVING&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;constraint_expression&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ASC&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LIMIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OFFSET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h4 id="1from和join"&gt;1. &lt;code&gt;FROM&lt;/code&gt; 和 &lt;code&gt;JOIN&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;FROM&lt;/code&gt;&lt;/strong&gt; 或  &lt;strong&gt;&lt;code&gt;JOIN&lt;/code&gt;&lt;/strong&gt; 会第一个执行，确定一个整体的数据范围. 如果要JOIN不同表，可能会生成一个临时Table来用于 下面的过程。总之第一步可以简单理解为确定一个数据源表（含临时表）&lt;/p&gt;
&lt;h4 id="2"&gt;&lt;strong&gt;2. &lt;code&gt;WHERE&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&gt;&lt;p&gt;我们确定了数据来源 &lt;strong&gt;&lt;code&gt;WHERE&lt;/code&gt;&lt;/strong&gt; 语句就将在这个数据源中按要求进行数据筛选，并丢弃不符合要求的数据行，所有的筛选col属性 只能来自 &lt;strong&gt;&lt;code&gt;FROM&lt;/code&gt;&lt;/strong&gt; 圈定的表. &lt;code&gt;AS&lt;/code&gt;别名还不能在这个阶段使用，因为可能别名是一个还没执行的表达式&lt;/p&gt;
&lt;h4 id="3"&gt;&lt;strong&gt;3. &lt;code&gt;GROUP BY&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&gt;&lt;p&gt;如果你用了 &lt;strong&gt;&lt;code&gt;GROUP BY&lt;/code&gt;&lt;/strong&gt; 分组，那 &lt;strong&gt;&lt;code&gt;GROUP BY&lt;/code&gt;&lt;/strong&gt; 将对之前的数据进行分组，统计等，并将是结果集缩小为分组数.这意味着 其他的数据在分组后丢弃.&lt;/p&gt;
&lt;h4 id="4"&gt;&lt;strong&gt;4. &lt;code&gt;HAVING&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&gt;&lt;p&gt;如果你用了 &lt;strong&gt;&lt;code&gt;GROUP BY&lt;/code&gt;&lt;/strong&gt; 分组, &lt;strong&gt;&lt;code&gt;HAVING&lt;/code&gt;&lt;/strong&gt; 会在分组完成后对结果集再次筛选。&lt;code&gt;AS&lt;/code&gt;别名也不能在这个阶段使用.&lt;/p&gt;
&lt;h4 id="5"&gt;&lt;strong&gt;5. &lt;code&gt;SELECT&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&gt;&lt;p&gt;确定结果之后， &lt;strong&gt;&lt;code&gt;SELECT&lt;/code&gt;&lt;/strong&gt; 用来对结果col简单筛选或计算，决定输出什么数据.&lt;/p&gt;
&lt;h4 id="6"&gt;&lt;strong&gt;6. &lt;code&gt;DISTINCT&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&gt;&lt;p&gt;如果数据行有重复 &lt;strong&gt;&lt;code&gt;DISTINCT&lt;/code&gt;&lt;/strong&gt; 将负责排重.&lt;/p&gt;
&lt;h4 id="7"&gt;&lt;strong&gt;7. &lt;code&gt;ORDER BY&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&gt;&lt;p&gt;在结果集确定的情况下， &lt;strong&gt;&lt;code&gt;ORDER BY&lt;/code&gt;&lt;/strong&gt; 对结果做排序。因为 &lt;strong&gt;&lt;code&gt;SELECT&lt;/code&gt;&lt;/strong&gt; 中的表达式已经执行完了。此时可以用&lt;code&gt;AS&lt;/code&gt;别名.&lt;/p&gt;
&lt;h4 id="8"&gt;&lt;strong&gt;8. &lt;code&gt;LIMIT&lt;/code&gt; / &lt;code&gt;OFFSET&lt;/code&gt;&lt;/strong&gt;
&lt;/h4&gt;&lt;p&gt;最后 &lt;strong&gt;&lt;code&gt;LIMIT&lt;/code&gt;&lt;/strong&gt; 和 &lt;strong&gt;&lt;code&gt;OFFSET&lt;/code&gt;&lt;/strong&gt; 从排序的结果中截取部分数据.&lt;/p&gt;
&lt;h4 id="结论"&gt;&lt;strong&gt;结论&lt;/strong&gt;
&lt;/h4&gt;&lt;p&gt;不是每一个SQL语句都要用到所有的句法，但灵活运用以上的句法组合和深刻理解SQL执行原理将能在SQL层面更好的解决数据问题，而不用把问题 都抛给程序逻辑.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="null"&gt;NULL
&lt;/h2&gt;&lt;p&gt;如果某个字段你没有填写到数据库，很可能就会出现 &lt;strong&gt;&lt;code&gt;NULL&lt;/code&gt;&lt;/strong&gt;  。所有一个常见的方式就是为字段设置 &lt;strong&gt;&lt;code&gt;默认值&lt;/code&gt;&lt;/strong&gt; ,比如 数字的默认值设置为0，字符串设置为 &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt; 字符串. 但是在一些 &lt;strong&gt;&lt;code&gt;NULL&lt;/code&gt;&lt;/strong&gt; 表示它本来含义的场景，需要注意是否设置默认值还是保持 &lt;strong&gt;&lt;code&gt;NULL&lt;/code&gt;&lt;/strong&gt; 。 (比如, 当你计算一些行的平均值的时候，如果是0会参与计算导致平均值差错，是 &lt;strong&gt;&lt;code&gt;NULL&lt;/code&gt;&lt;/strong&gt; 则不会参与计算).&lt;/p&gt;
&lt;p&gt;还有一些情况很难避免 &lt;strong&gt;&lt;code&gt;NULL&lt;/code&gt;&lt;/strong&gt; 的出现, 比如之前说的 outer-joining 多表连接，A和B有数据差异时，必须用 &lt;strong&gt;&lt;code&gt;NULL&lt;/code&gt;&lt;/strong&gt; 来填充。这种情况，可以用 &lt;strong&gt;&lt;code&gt;IS NULL&lt;/code&gt;&lt;/strong&gt; 和 &lt;strong&gt;&lt;code&gt;IS NOT NULL&lt;/code&gt;&lt;/strong&gt; 来选在某个字段是否等于 &lt;strong&gt;&lt;code&gt;NULL&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;another_column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mytable&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;another_condition&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;img src="https://ottercoconut.github.io/uploads/posts/MySQL/Screenshot_2025-03-11_203039.png" alt="例题7" loading="lazy" /&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="修改数据"&gt;修改数据
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;部分引用自 &lt;a class="link" href="https://liaoxuefeng.com/books/sql/manipulation/index.html" target="_blank" rel="noopener"
 &gt;修改数据 - SQL教程 - 廖雪峰的官方网站&lt;/a&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;关系数据库的基本操作就是增删改查，即CRUD：Create、Retrieve、Update、Delete。其中，对于查询，我们已经详细讲述了&lt;code&gt;SELECT&lt;/code&gt;语句的详细用法。&lt;/p&gt;
&lt;p&gt;而对于增、删、改，对应的SQL语句分别是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;INSERT：插入新记录；&lt;/li&gt;
&lt;li&gt;UPDATE：更新已有记录；&lt;/li&gt;
&lt;li&gt;DELETE：删除已有记录。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们将分别讨论这三种修改数据的语句的使用方法。&lt;/p&gt;
&lt;h4 id="insert-插入"&gt;INSERT 插入
&lt;/h4&gt;&lt;p&gt;引用于 &lt;a class="link" href="https://www.runoob.com/mysql/mysql-insert-query.html" target="_blank" rel="noopener"
 &gt;MySQL 插入数据 | 菜鸟教程&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;例如，我们向&lt;code&gt;user&lt;/code&gt;表插入一条新记录，先列举出需要插入的字段名称，然后在&lt;code&gt;VALUES&lt;/code&gt;子句中依次写出对应字段的值：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;table_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;column1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;column2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;column3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;--
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;birthdate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is_active&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test@runoob.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1990-01-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果要插入所有列(即插入行)的数据，可以省略列名：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test@runoob.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1990-01-01&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;还可以一次性添加多条记录，只需要在&lt;code&gt;VALUES&lt;/code&gt;子句中指定多个记录值，每个记录是由&lt;code&gt;(...)&lt;/code&gt;包含的一组值，每组值用逗号&lt;code&gt;,&lt;/code&gt;分隔：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;birthdate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is_active&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test1@runoob.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1985-07-10&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test2@runoob.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1988-11-25&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;test3@runoob.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1993-05-03&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;hr&gt;
&lt;h3 id="update-更新"&gt;UPDATE 更新
&lt;/h3&gt;&lt;p&gt;&lt;a class="link" href="https://www.runoob.com/mysql/mysql-update-query.html" target="_blank" rel="noopener"
 &gt;MySQL UPDATE 更新 | 菜鸟教程&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;table_name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;column1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;column2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;参数说明：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;table_name&lt;/code&gt; 是你要更新数据的表的名称。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;column1&lt;/code&gt;, &lt;code&gt;column2&lt;/code&gt;, &amp;hellip; 是你要更新的列的名称。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;value1&lt;/code&gt;, &lt;code&gt;value2&lt;/code&gt;, &amp;hellip; 是新的值，用于替换旧的值。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WHERE condition&lt;/code&gt; 是一个可选的子句，用于指定更新的行。如果省略 &lt;code&gt;WHERE&lt;/code&gt; 子句，将更新表中的所有行。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;更多说明：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;你可以同时更新一个或多个字段。&lt;/li&gt;
&lt;li&gt;你可以在 &lt;code&gt;WHERE&lt;/code&gt; 子句中指定任何条件。&lt;/li&gt;
&lt;li&gt;你可以在一个单独表中同时更新数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当你需要更新数据表中指定行的数据时 &lt;code&gt;WHERE&lt;/code&gt; 子句是非常有用的。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;--更新单个列的值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;employees&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;salary&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;employee_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;--更新多个列的值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Shipped&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ship_date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2023-03-01&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1001&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;--使用表达式更新值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Electronics&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;--更新使用子查询的值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;customers&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;total_purchases&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;customers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;customer_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Premium&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;在使用MySQL这类真正的关系数据库时，&lt;code&gt;UPDATE&lt;/code&gt;语句会返回更新的行数以及&lt;code&gt;WHERE&lt;/code&gt;条件匹配的行数。&lt;/p&gt;
&lt;p&gt;例如，更新&lt;code&gt;id=1&lt;/code&gt;的记录时：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-plain" data-lang="plain"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&amp;gt; UPDATE students SET name=&amp;#39;大宝&amp;#39; WHERE id=1;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Query OK, 1 row affected (0.00 sec)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Rows matched: 1 Changed: 1 Warnings: 0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;MySQL会返回&lt;code&gt;1&lt;/code&gt;，可以从打印的结果&lt;code&gt;Rows matched: 1 Changed: 1&lt;/code&gt;看到。&lt;/p&gt;
&lt;p&gt;当更新&lt;code&gt;id=999&lt;/code&gt;的记录时：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-plain" data-lang="plain"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&amp;gt; UPDATE students SET name=&amp;#39;大宝&amp;#39; WHERE id=999;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Query OK, 0 rows affected (0.00 sec)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Rows matched: 0 Changed: 0 Warnings: 0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;MySQL会返回&lt;code&gt;0&lt;/code&gt;，可以从打印的结果&lt;code&gt;Rows matched: 0 Changed: 0&lt;/code&gt;看到。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="delete-删除"&gt;DELETE 删除
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;DELETE&lt;/code&gt;语句的基本语法是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DELETE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;表名&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;例如，我们想删除&lt;code&gt;students&lt;/code&gt;表中&lt;code&gt;id=1&lt;/code&gt;的记录，就需要这么写：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-mysql" data-lang="mysql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- 删除id=1的记录:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DELETE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- 查询并观察结果:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;注意到&lt;code&gt;DELETE&lt;/code&gt;语句的&lt;code&gt;WHERE&lt;/code&gt;条件也是用来筛选需要删除的行，因此和&lt;code&gt;UPDATE&lt;/code&gt;类似，&lt;code&gt;DELETE&lt;/code&gt;语句也可以一次删除多条记录：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-mysql" data-lang="mysql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- 删除id=5,6,7的记录:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DELETE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- 查询并观察结果:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果&lt;code&gt;WHERE&lt;/code&gt;条件没有匹配到任何记录，&lt;code&gt;DELETE&lt;/code&gt;语句不会报错，也不会有任何记录被删除。例如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-mysql" data-lang="mysql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- 删除id=999的记录:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DELETE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;999&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- 查询并观察结果:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;最后，要特别小心的是，和&lt;code&gt;UPDATE&lt;/code&gt;类似，不带&lt;code&gt;WHERE&lt;/code&gt;条件的&lt;code&gt;DELETE&lt;/code&gt;语句会删除整个表的数据：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;DELETE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;students&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这时，整个表的所有记录都会被删除。所以，在执行&lt;code&gt;DELETE&lt;/code&gt;语句时也要非常小心，最好先用&lt;code&gt;SELECT&lt;/code&gt;语句来测试&lt;code&gt;WHERE&lt;/code&gt;条件是否筛选出了期望的记录集，然后再用&lt;code&gt;DELETE&lt;/code&gt;删除。&lt;/p&gt;
&lt;p&gt;在使用MySQL这类真正的关系数据库时，&lt;code&gt;DELETE&lt;/code&gt;语句也会返回删除的行数以及&lt;code&gt;WHERE&lt;/code&gt;条件匹配的行数。&lt;/p&gt;
&lt;p&gt;例如，分别执行删除&lt;code&gt;id=1&lt;/code&gt;和&lt;code&gt;id=999&lt;/code&gt;的记录：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-plain" data-lang="plain"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&amp;gt; DELETE FROM students WHERE id=1;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Query OK, 1 row affected (0.01 sec)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql&amp;gt; DELETE FROM students WHERE id=999;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Query OK, 0 rows affected (0.01 sec)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="create-创建"&gt;CREATE 创建
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://www.runoob.com/mysql/mysql-create-tables.html" target="_blank" rel="noopener"
 &gt;MySQL 创建数据表 | 菜鸟教程&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;--用户表实例
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AUTO_INCREMENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;birthdate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is_active&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;BOOLEAN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DEFAULT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TRUE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;实例解析：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;id&lt;/code&gt;: 用户 id，整数类型，自增长，作为主键。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;username&lt;/code&gt;: 用户名，变长字符串，不允许为空。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;email&lt;/code&gt;: 用户邮箱，变长字符串，不允许为空。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;birthdate&lt;/code&gt;: 用户的生日，日期类型。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;is_active&lt;/code&gt;: 用户是否已经激活，布尔类型，默认值为 true。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上只是一个简单的实例，用到了一些常见的数据类型包括&lt;code&gt;INT&lt;/code&gt;, &lt;code&gt;VARCHAR&lt;/code&gt;, &lt;code&gt;DATE&lt;/code&gt;, &lt;code&gt;BOOLEAN&lt;/code&gt;，可以根据实际需要选择不同的数据类型。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;AUTO_INCREMENT&lt;/code&gt; 关键字用于创建一个自增长的列，&lt;code&gt;PRIMARY KEY&lt;/code&gt; 用于定义主键。&lt;/p&gt;
&lt;p&gt;如果希望在创建表时指定数据引擎，字符集和排序规则等，可以使用 &lt;strong&gt;&lt;code&gt;CHARACTER SET&lt;/code&gt;&lt;/strong&gt; 和 &lt;strong&gt;&lt;code&gt;COLLATE&lt;/code&gt;&lt;/strong&gt; 子句：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mytable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;CHARACTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;utf8mb4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;COLLATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;utf8mb4_general_ci&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;</description></item></channel></rss>