<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Java on Liangweidong's blog</title><link>https://liangweidonggood.github.io/tags/java/</link><description>Recent content in Java on Liangweidong's blog</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Tue, 06 Mar 2018 00:00:00 +0000</lastBuildDate><atom:link href="https://liangweidonggood.github.io/tags/java/index.xml" rel="self" type="application/rss+xml"/><item><title>AQS原理简述</title><link>https://liangweidonggood.github.io/p/13-aqs-yuan-li-jian-shu/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/13-aqs-yuan-li-jian-shu/</guid><description>&lt;h2 id="225-aqs原理简述"&gt;§2.2.5 AQS原理简述
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：理解AQS作为JUC基石的原理深度，而非泛泛而谈&amp;quot;抽象队列同步器&amp;quot;。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;回答样板&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;AQS（AbstractQueuedSynchronizer）是JUC锁和同步器（ReentrantLock、CountDownLatch、Semaphore等）的基石。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心三要素&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;volatile int state&lt;/code&gt;——同步状态（独占模式0表示未锁，大于0表示已锁；共享模式表示剩余资源数）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CLH变体双向队列&lt;/strong&gt;——等待获取锁的线程队列，每个节点通过CAS和前驱节点的waitStatus状态协作&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模板方法模式&lt;/strong&gt;——子类实现tryAcquire/tryRelease等抽象方法决定同步语义，AQS内部维护队列和状态流转&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;独占模式获取锁流程&lt;/strong&gt;：tryAcquire尝试获取 → 成功则返回 → 失败则将当前线程包装成Node加入等待队列 → 在队列中自旋或阻塞等待前驱节点唤醒。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;项目层面&lt;/strong&gt;：日常使用多是读API层面（直接用ReentrantLock、CountDownLatch），没有深入到定制AQS同步器那个层面。但对AQS的CLH队列原理、state状态机有清晰理解。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：说&amp;quot;精通AQS&amp;quot;结果说不出CLH队列原理；泛泛而谈&amp;quot;抽象队列同步器&amp;quot;没深度。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;备选话术&lt;/strong&gt;：我日常使用线程池处理异步任务（如设备数据批量写入），对JUC核心类有实操经验。但AQS源码实现细节或无锁编程（CAS/Unsafe）不是日常写代码的层面，坦诚需要查资料。&lt;/p&gt;</description></item><item><title>synchronized vs Lock</title><link>https://liangweidonggood.github.io/p/09-synchronized-yu-lock/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/09-synchronized-yu-lock/</guid><description>&lt;h2 id="221-synchronized-vs-lock"&gt;§2.2.1 synchronized vs Lock
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：能否理解synchronized和Lock的原理差异和选型依据。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;回答样板&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;synchronized是JVM内置锁，由monitorenter/monitorexit字节码指令实现，自动释放锁，非公平锁，适合简单同步场景。&lt;/p&gt;
&lt;p&gt;Lock（ReentrantLock）是JDK API级别的锁，通过AQS（AbstractQueuedSynchronizer）实现，必须手动释放（finally中unlock），支持公平锁、可中断获取锁、尝试获取锁超时、多条件变量（Condition），适合复杂同步场景。&lt;/p&gt;
&lt;p&gt;JDK 6以后synchronized做了锁升级优化——偏向锁 → 轻量级锁 → 重量级锁，单线程竞争场景下性能差距不大。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;追问预判&lt;/strong&gt;：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;追问：&amp;ldquo;synchronized的锁升级过程具体是怎样的？&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;无锁状态 → 偏向锁：Mark Word存储线程ID，同一线程重入不走CAS，直接判断线程ID一致 → 轻量级锁：多个线程交替竞争时，自旋CAS尝试获取锁，Mark Word存锁记录指针 → 重量级锁：自旋超过阈值（默认10次或自适应），升级为OS互斥量，线程阻塞挂起。本质是空间换时间——偏向锁和轻量级锁尽力减少内核态切换，重量级锁是兜底方案。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：说不清锁升级过程；以为synchronized一直是重量级锁。&lt;/p&gt;</description></item><item><title>ThreadLocal原理与内存泄漏</title><link>https://liangweidonggood.github.io/p/11-threadlocal-yu-nei-cun-xie-lou/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/11-threadlocal-yu-nei-cun-xie-lou/</guid><description>&lt;h2 id="223-threadlocal原理与内存泄漏"&gt;§2.2.3 ThreadLocal原理与内存泄漏
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：是否理解ThreadLocal的实现原理、内存泄漏成因及规避方式。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;回答样板&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;每个Thread内部维护一个ThreadLocalMap，key是ThreadLocal实例的弱引用（WeakReference），value是线程持有的值。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;内存泄漏原因&lt;/strong&gt;：在线程池场景下线程复用，ThreadLocal使用完没有调用remove()时——key（ThreadLocal实例）会被GC回收（弱引用特点），但value的强引用链依然存在（Thread → ThreadLocalMap → Entry → value），导致value无法被回收，造成内存泄漏。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;规范&lt;/strong&gt;：ThreadLocal使用完必须在finally块中调用remove()。&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-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ThreadLocal&amp;lt;Object&amp;gt; tl = new ThreadLocal&amp;lt;&amp;gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;try {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; tl.set(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;} finally {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; tl.remove();
&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;blockquote&gt;
 &lt;p&gt;追问：&amp;ldquo;为什么ThreadLocalMap的key要设计成弱引用？&amp;rdquo;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;设计为弱引用的目的是：当ThreadLocal对象不再被外部强引用时（即使用方不再需要它了），GC可以回收ThreadLocal实例，使得对应的Entry（key=null）成为无效条目。下次ThreadLocalMap调用set/get/remove时会主动清理这些key为null的Entry。如果没有这一层弱引用设计，即使外部不再使用ThreadLocal，Entry和value也会一直存活，导致更严重的内存泄漏。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：答不出弱引用设计意图；只知道&amp;quot;用ThreadLocal存用户信息&amp;quot;但说不清泄漏原理。&lt;/p&gt;</description></item><item><title>volatile深入</title><link>https://liangweidonggood.github.io/p/10-volatile-shen-ru/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/10-volatile-shen-ru/</guid><description>&lt;h2 id="222-volatile深入"&gt;§2.2.2 volatile深入
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：volatile是面试高频基础题。初级答&amp;quot;保证可见性+禁止重排序&amp;quot;，中极答内存屏障语义，高级能讲出实际项目中用它解决过什么并发bug。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;一、volatile的两个核心作用&lt;/strong&gt;（基础层，必须熟练）&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;保证可见性&lt;/strong&gt;：一个线程修改volatile变量后，其他线程立即可见。底层通过lock前缀指令触发缓存一致性协议（MESI），写变量时强制将缓存行写回主存并使其他CPU核的缓存行失效，其他核读时必须从主存重新加载。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;禁止指令重排序&lt;/strong&gt;：通过内存屏障限制编译器和CPU的指令重排。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;不保证原子性&lt;/strong&gt;：&lt;code&gt;volatile int i; i++&lt;/code&gt;不是原子操作（读→改→写三步），多线程并发自增仍然会丢失更新。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;二、内存屏障详解&lt;/strong&gt;（深度层，拉开分差）&lt;/p&gt;
&lt;p&gt;内存屏障是一条CPU指令，强制在其前后的内存操作满足特定的执行顺序。Java的volatile通过JMM定义的四类屏障保证了Happens-Before语义：&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;&lt;strong&gt;LoadLoad&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;Load1; LoadLoad; Load2&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;保证Load1在Load2之前完成（防止读操作重排到前面的读之前）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;StoreStore&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;Store1; StoreStore; Store2&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;保证Store1在Store2之前完成（防止写操作重排到前面的写之前）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;LoadStore&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;Load1; LoadStore; Store2&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;保证Load1在Store2之前完成（防止写操作重排到前面的读之前）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;StoreLoad&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;Store1; StoreLoad; Load2&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;保证Store1在Load2之前完成（防止读操作重排到前面的写之前）&lt;strong&gt;最重的一类屏障，同时具备其他三种效果，通常由 &lt;code&gt;mfence&lt;/code&gt;或 &lt;code&gt;lock addl&lt;/code&gt;指令实现&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;volatile的内存屏障插入策略&lt;/strong&gt;（JMM规范）：&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;// volatile 写之前
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;StoreStore屏障 ← 保证volatile写之前的普通写操作对volatile写可见
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// volatile 写
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;StoreLoad屏障 ← 保证volatile写之后的读操作不会被重排到volatile写之前
&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;// volatile 读
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LoadLoad屏障 ← 保证volatile读之后的普通读不会被重排到volatile读之前
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// volatile 读
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;LoadStore屏障 ← 保证volatile读之后的普通写不会被重排到volatile读之前
&lt;/span&gt;&lt;/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;为什么StoreLoad屏障最重？&lt;/strong&gt; 它要求在执行StoreLoad之后的任何Load指令前，Store缓冲区中的所有数据必须全部刷新到主存（或者至少对其他处理器可见）。在x86平台上，&lt;code&gt;StoreLoad&lt;/code&gt;通常由 &lt;code&gt;mfence&lt;/code&gt;（全屏障）或带lock前缀的指令实现，开销是普通指令的几十到上百倍。而LoadLoad、StoreStore、LoadStore在x86上通常无需额外指令——x86本身就是强内存模型（TSO），只允许Store-Load重排，其他重排在硬件层面已被禁止。所以在x86上，volatile的实际开销主要来自StoreLoad屏障。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;三、volatile实用场景&lt;/strong&gt;（实战层，证明你真正用过）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;场景1：DCL（双重检查锁定）单例中的volatile&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;/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;DeviceConfigManager&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;static&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="n"&gt;DeviceConfigManager&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&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;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DeviceConfigManager&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;getInstance&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;instance&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;null&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="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;DeviceConfigManager&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="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;instance&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;null&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="n"&gt;instance&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;DeviceConfigManager&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="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;strong&gt;为什么 &lt;code&gt;instance&lt;/code&gt;必须用volatile？&lt;/strong&gt; 关键在第③行 &lt;code&gt;new DeviceConfigManager()&lt;/code&gt;，这行代码在JVM层面分三步：&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;1. memory = allocate() // 分配内存空间
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2. ctorInstance(memory) // 初始化对象（执行构造方法）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3. instance = memory // 将引用指向分配的内存地址
&lt;/span&gt;&lt;/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;如果不用volatile，步骤2和3可能被重排成1→3→2。线程A执行 &lt;code&gt;new&lt;/code&gt;指令时刚好走到&amp;quot;分配内存→赋值引用&amp;quot;但构造方法还没执行完（对象是半成品），线程B走到第①行 &lt;code&gt;if (instance == null)&lt;/code&gt;发现instance非空，直接返回了一个&lt;strong&gt;没有初始化完成的对象&lt;/strong&gt;——后续使用时NullPointerException或数据错乱。volatile的StoreStore屏障保证了步骤2一定在步骤3之前完成（写前插入StoreStore：&lt;code&gt;ctorInstance; StoreStore; instance=memory&lt;/code&gt;），线程B读instance时LoadLoad屏障保证读到的对象一定是初始化完毕的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;场景2：线程安全的状态标志位&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;/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;PositionEngine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;// 不用volatile——reload线程改了flag，worker线程可能永远看不到&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;// private boolean configChanged = 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="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;// 用volatile——reload线程一改，所有worker线程下次循环立即感知&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;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;configChanged&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;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PositionConfig&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 注意：config本身不是volatile&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&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;// 定时任务线程每5分钟刷新一次&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;reloadConfig&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;PositionConfig&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;newConfig&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;loadFromRemote&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;config&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;newConfig&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ②再赋值给config&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;configChanged&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;// ③最后改标记&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;// volatile写前的StoreStore屏障保证①②③不会重排——&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;// 所以configChanged变为false时，config一定是新值&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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="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;Position&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;calcPosition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Device&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;device&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;configChanged&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;// volatile读后的LoadLoad屏障保证——&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;// 读到configChanged=true时，config一定已经是最新赋值&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;updateLocalConfig&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;config&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;configChanged&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&gt;&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;// ... 定位计算，用本地缓存的config，不走volatile，零开销&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;strong&gt;这个场景volatile的妙处&lt;/strong&gt;：配置变量 &lt;code&gt;config&lt;/code&gt;本身&lt;strong&gt;不需要&lt;/strong&gt;volatile修饰。volatile只用于 &lt;code&gt;configChanged&lt;/code&gt;这个&amp;quot;开关变量&amp;quot;，利用volatile写前StoreStore屏障保证&amp;quot;先赋值config、再改标记&amp;quot;的写入顺序，利用volatile读后LoadLoad屏障保证&amp;quot;先读标记确认、再读config内容&amp;quot;的读取顺序。这种&amp;quot;volatile变量守卫普通变量&amp;quot;的模式比把所有变量都标volatile高效得多。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;场景3：安全发布（Safe Publication）&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;在物联平台设备接入时，每个设备连接对应的Handler需要持有设备基础信息。这个信息在主线程初始化，被NIO的Worker线程读取：&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-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;DeviceHandler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;volatile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DeviceInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deviceInfo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 必须volatile&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&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;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;init&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;deviceId&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;DeviceInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;info&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;DeviceInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deviceId&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="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setProtocol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;modbus&amp;#34;&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="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setLocation&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deviceInfo&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;info&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ③发布——volatile写&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;// StoreStore屏障：保证①②所有初始化在③赋值之前被所有线程可见&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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="c1"&gt;// Netty Worker线程读取&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;onData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&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;DeviceInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;info&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deviceInfo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;info&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;null&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;// LoadLoad屏障：读到的info对象一定是完整初始化的&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;protocol&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;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProtocol&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// 必然返回&amp;#34;modbus&amp;#34;，不会是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="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&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;如果没有volatile，Worker线程可能看到 &lt;code&gt;deviceInfo&lt;/code&gt;非空（引用已赋值），但 &lt;code&gt;info&lt;/code&gt;对象的内部属性还是初始值（构造函数未完整执行被重排），导致 &lt;code&gt;getProtocol()&lt;/code&gt;返回null而NPE。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：说&amp;quot;volatile能保证原子性&amp;quot;——致命错误（i++反例）；说&amp;quot;所有共享变量都需要volatile&amp;quot;——过于暴力，性能代价大；知道四种屏障名字但说不出各自阻止什么重排；不知道DCL单例为什么必须volatile（JDK 5之前volatile语义不够强，DCL有bug）；不知道x86只需要StoreLoad屏障（LoadLoad/StoreStore/StoreLoad在x86上硬件已保证，伪共享除外）。&lt;/p&gt;</description></item><item><title>线程池核心参数与执行流程</title><link>https://liangweidonggood.github.io/p/12-xian-cheng-chi-he-xin-can-shu/</link><pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/12-xian-cheng-chi-he-xin-can-shu/</guid><description>&lt;h2 id="224-线程池核心参数与执行流程"&gt;§2.2.4 线程池核心参数与执行流程
&lt;/h2&gt;
 &lt;blockquote&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;ol&gt;
&lt;li&gt;&lt;code&gt;corePoolSize&lt;/code&gt;——常驻线程数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;maximumPoolSize&lt;/code&gt;——最大线程数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;keepAliveTime&lt;/code&gt;——空闲线程存活时间（超过corePoolSize的线程）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TimeUnit&lt;/code&gt;——时间单位&lt;/li&gt;
&lt;li&gt;&lt;code&gt;workQueue&lt;/code&gt;——阻塞队列（有界/无界）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;threadFactory&lt;/code&gt;——线程工厂（自定义线程名、是否守护线程等）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;handler&lt;/code&gt;——拒绝策略&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;执行流程&lt;/strong&gt;：
提交任务 → 当前线程数 &amp;lt; corePoolSize → 创建核心线程执行
→ 当前线程数 &amp;gt;= corePoolSize → 入队列等待
→ 队列满 → 创建非核心线程执行
→ 当前线程数 &amp;gt;= maximumPoolSize → 触发拒绝策略&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;AbortPolicy（默认）&lt;/td&gt;
					&lt;td&gt;抛RejectedExecutionException&lt;/td&gt;
					&lt;td&gt;必须感知任务丢失的场景&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;CallerRunsPolicy&lt;/td&gt;
					&lt;td&gt;调用者线程执行&lt;/td&gt;
					&lt;td&gt;反向压制动，降低任务提交速度&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;DiscardPolicy&lt;/td&gt;
					&lt;td&gt;直接丢弃，静默失败&lt;/td&gt;
					&lt;td&gt;不重要的日志/统计任务&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;DiscardOldestPolicy&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;项目实战&lt;/strong&gt;：在物联平台用线程池处理设备数据批量写入。I/O密集型任务核心线程数设为CPU核数×2，队列用有界ArrayBlockingQueue防止内存溢出。自定义ThreadFactory设置线程名前缀方便排查。拒绝策略用CallerRunsPolicy做背压。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：背参数但说不清业务场景下怎么选型和调参。&lt;/p&gt;</description></item><item><title>ArrayList vs LinkedList</title><link>https://liangweidonggood.github.io/p/16-arraylist-yu-linkedlist/</link><pubDate>Thu, 06 Mar 2008 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/16-arraylist-yu-linkedlist/</guid><description>&lt;h2 id="233-arraylist-vs-linkedlist"&gt;§2.3.3 ArrayList vs LinkedList
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：是否理解List不同实现的性能差异及工程选型判断。&lt;/p&gt;

 &lt;/blockquote&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;ArrayList&lt;/th&gt;
					&lt;th&gt;LinkedList&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;底层结构&lt;/td&gt;
					&lt;td&gt;动态数组（Object[]）&lt;/td&gt;
					&lt;td&gt;双向链表（Node）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;随机访问&lt;/td&gt;
					&lt;td&gt;O(1)&lt;/td&gt;
					&lt;td&gt;O(n)——需要遍历&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;尾部插入&lt;/td&gt;
					&lt;td&gt;O(1)均摊（扩容时O(n)）&lt;/td&gt;
					&lt;td&gt;O(1)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;头/中间插入&lt;/td&gt;
					&lt;td&gt;O(n)（需要移动元素）&lt;/td&gt;
					&lt;td&gt;头O(1)，中间O(n)——定位+O(1)插入&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;内存开销&lt;/td&gt;
					&lt;td&gt;连续内存，数据紧凑&lt;/td&gt;
					&lt;td&gt;每个节点额外存储prev+next指针&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;工程实践&lt;/strong&gt;：实际开发中ArrayList用得更多。原因是内存连续、CPU缓存友好（缓存行预读），大多数场景下遍历性能远超LinkedList。LinkedList的优势场景是频繁头尾插入删除（如队列、栈）。日常开发90%场景ArrayList够用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ArrayList扩容&lt;/strong&gt;：默认初始容量10，扩容时增长为原来的1.5倍（&lt;code&gt;oldCapacity + (oldCapacity &amp;gt;&amp;gt; 1)&lt;/code&gt;），通过&lt;code&gt;Arrays.copyOf&lt;/code&gt;拷贝数组。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：不知道ArrayList扩容机制细节；说&amp;quot;LinkedList插入快&amp;quot;不考虑定位开销。&lt;/p&gt;</description></item><item><title>HashMap原理</title><link>https://liangweidonggood.github.io/p/14-hashmap-yuan-li/</link><pubDate>Tue, 06 Jun 2006 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/14-hashmap-yuan-li/</guid><description>&lt;h2 id="231-hashmap原理"&gt;§2.3.1 HashMap原理
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：是否理解HashMap的数据结构演进、put流程、扩容与树化等关键机制。&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;：JDK 7：数组+链表。JDK 8：数组+链表/红黑树。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;put流程&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;计算key的hash值（高16位异或低16位，降低hash冲突）&lt;/li&gt;
&lt;li&gt;定位桶：&lt;code&gt;(n - 1) &amp;amp; hash&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;无冲突 → 直接放入&lt;/li&gt;
&lt;li&gt;有冲突 → 判断equals → 相同则覆盖，不同则尾插（JDK 7是头插，JDK 8改尾插避免死链）&lt;/li&gt;
&lt;li&gt;链表长度 &amp;gt; 8 且数组长度 ≥ 64 → 树化为红黑树&lt;/li&gt;
&lt;li&gt;容量超过 threshold（capacity × loadFactor）→ 扩容&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;扩容机制&lt;/strong&gt;：2倍扩容，JDK 8做了rehash优化——原hash值与oldCap按位与，结果为0留在原位，为1移到&amp;quot;原位置+oldCap&amp;quot;，省去了每次rebuild hash表的开销。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;负载因子0.75&lt;/strong&gt;：时间和空间的折中。太低（如0.5）浪费内存；太高（如1）hash冲突增加，影响查询性能。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;红黑树退化&lt;/strong&gt;：resize时如果树的节点数 ≤ 6，退化为链表。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：说&amp;quot;HashMap线程安全&amp;quot;；不知道树化阈值是链表长度&amp;gt;8且数组长度≥64两个条件缺一不可。&lt;/p&gt;</description></item><item><title>ConcurrentHashMap原理</title><link>https://liangweidonggood.github.io/p/15-concurrenthashmap-yuan-li/</link><pubDate>Thu, 06 Apr 2006 00:00:00 +0000</pubDate><guid>https://liangweidonggood.github.io/p/15-concurrenthashmap-yuan-li/</guid><description>&lt;h2 id="232-concurrenthashmap原理"&gt;§2.3.2 ConcurrentHashMap原理
&lt;/h2&gt;
 &lt;blockquote&gt;
 &lt;p&gt;考察意图：是否理解ConcurrentHashMap在JDK 7/8的演进及JDK 8的改进要点。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;回答样板&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;JDK 7（分段锁）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据结构：Segment数组 + HashEntry数组 + 链表&lt;/li&gt;
&lt;li&gt;Segment继承ReentrantLock，默认16个Segment&lt;/li&gt;
&lt;li&gt;理论上支持16个线程并发写（每个Segment一把锁）&lt;/li&gt;
&lt;li&gt;并发度固定不可动态调整&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;JDK 8（CAS + synchronized）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据结构：Node数组 + 链表/红黑树&lt;/li&gt;
&lt;li&gt;put时CAS尝试插入空桶，CAS失败则synchronized锁桶头节点再插入&lt;/li&gt;
&lt;li&gt;锁粒度从Segment级别（一锁锁一段）细化到桶级别（一锁锁一个桶），并发度更高&lt;/li&gt;
&lt;li&gt;扩容支持多线程并发——transferIndex分段迁移，每个线程负责一段区域的rehash&lt;/li&gt;
&lt;li&gt;JDK 8改synchronized而非ReentrantLock的原因：JDK 6后synchronized性能足够；省去Segment对象的内存开销；锁粒度更细带来的收益远超锁机制本身的微小差异&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;陷阱提示&lt;/strong&gt;：仍停留在JDK 7分段锁的理解；不知道JDK 8为什么改CAS+synchronized。&lt;/p&gt;</description></item></channel></rss>