《Java 100 天进阶之路》并发编程与JUC通关总结:从线程基础到并发容器,一套吃透Java高并发全链路(2026版)
🎯 并发编程与JUC通关总结:从线程基础到并发容器,一套吃透Java高并发全链路(2026精版)
📌 系列导航:《Java 100 天进阶之路》完整目录
恭喜你! 你已经完成了《Java 100 天进阶之路》并发编程与JUC详解阶段(第51~60篇) 的全部学习。
这是进阶篇中面试权重最高、区分度最大的阶段之一——从线程生命周期到锁升级机制,从 JMM 内存模型到 AQS 底层原理,从线程池调优到死锁排查,从 CompletableFuture 异步编排到 ThreadLocal 内存泄漏治理,10 篇文章,覆盖了 Java 并发编程 90% 以上的面试考点。从“线程是什么”到“高并发系统设计”,你完成了并发编程的完整进阶。
本文是这一阶段的通关总结,用 一张学习路线图 + 十张速查表 + 面试题汇总 + 避坑清单,帮你把 10 篇精华全部串联起来。建议收藏,随时复习。
📌 本阶段完整学习路线图

学习路径建议:
- 零基础/系统学习:按 51→52→53→54→55→56→57→58→59→60 顺序学习,层层递进
- 有基础/面试突击:优先看 52(锁升级)+ 54(AQS)+ 55(线程池)+ 60(压轴题)
- 架构师/调优方向:重点关注 53(JMM/volatile)+ 56(死锁排查)+ 58(LongAdder/伪共享)+ 59(TTL)
📚 分篇核心知识点速查表
第51篇:线程生命周期与创建方式
📖 查看完整文章
| 核心概念 | 一句话总结 | 高频面试提问 |
|---|---|---|
| 6种线程状态 | NEW → RUNNABLE → BLOCKED/WAITING/TIMED_WAITING → TERMINATED | Java线程有几种状态? |
| 状态转换 | start()、sleep()、wait()、notify()、join() 触发转换 | 状态之间如何转换? |
| 4种创建方式 | Thread、Runnable、Callable、线程池 | 创建线程有几种方式? |
| sleep vs wait | sleep 不释放锁,wait 释放锁 | sleep() 和 wait() 的区别? |
| start vs run | start 启动新线程,run 是普通方法调用 | start() 和 run() 的区别? |
| 虚拟线程 | JDK 21+ 轻量级线程,M:N 调度 | 虚拟线程和平台线程的区别? |
| 虚拟线程适用场景 | 高并发 I/O 密集型,不适合 CPU 密集型 | 虚拟线程什么时候用? |
👉 阅读完整文章
第52篇:synchronized 深度解析
📖 查看完整文章
| 核心概念 | 一句话总结 | 高频面试提问 |
|---|---|---|
| 三种使用方式 | 实例方法(锁this)、静态方法(锁Class)、代码块(自定义锁对象) | synchronized 的三种用法? |
| Mark Word | 锁状态存储在对象头中,64位JVM占8字节 | synchronized 的锁存在哪里? |
| 锁升级全流程 | 无锁 → 偏向锁 → 轻量级锁 → 重量级锁(单向升级) | synchronized 锁升级过程? |
| 偏向锁 | 单线程场景,Mark Word存线程ID,无CAS开销 | 偏向锁解决什么问题? |
| 轻量级锁 | 轻度竞争,自旋等待,Lock Record | 轻量级锁怎么工作? |
| 重量级锁 | 重度竞争,OS互斥量,ObjectMonitor | 重量级锁什么时候触发? |
| JVM优化 | 自适应自旋、锁消除、锁粗化 | JVM 对 synchronized 做了哪些优化? |
| 虚拟线程 Pinning | synchronized 导致虚拟线程固定在载体线程 | 虚拟线程中为什么慎用 synchronized? |
👉 阅读完整文章
第53篇:volatile 与 JMM
📖 查看完整文章
| 核心概念 | 一句话总结 | 高频面试提问 |
|---|---|---|
| JMM vs JVM内存结构 | JMM管“怎么看见”,JVM内存结构管“存哪里” | JMM 和 JVM 内存结构的区别? |
| 三大特性 | 原子性(synchronized/锁)、可见性(volatile)、有序性(内存屏障) | JMM 解决什么问题? |
| volatile 保证 | ✅ 可见性 ✅ 禁止重排 ❌ 不保证原子性 | volatile 能保证原子性吗? |
| 内存屏障 | StoreStore、StoreLoad、LoadLoad、LoadStore | volatile 如何禁止指令重排? |
| Happens-Before | volatile写 → volatile读 | volatile 的 Happens-Before 规则? |
| DCL单例 | 必须加 volatile 防止半初始化对象暴露 | DCL 单例为什么必须加 volatile? |
👉 阅读完整文章
第54篇:AQS 抽象队列同步器
📖 查看完整文章
| 核心概念 | 一句话总结 | 高频面试提问 |
|---|---|---|
| AQS 定义 | JUC 并发体系的底层基石 | AQS 是什么? |
| 核心三要素 | volatile int state + CLH双向队列 + 模板方法模式 | AQS 的核心思想? |
| 独占模式 | 同一时刻只有一个线程能获取(ReentrantLock) | AQS 的独占模式? |
| 共享模式 | 同一时刻多个线程可同时获取(Semaphore/CountDownLatch) | AQS 的共享模式? |
| CLH队列 | FIFO双向链表,存储等待线程,每个线程封装为Node | CLH 队列是什么? |
| 可重入性实现 | state 计数,当前线程是持有者时 state++ | ReentrantLock 如何实现可重入? |
👉 阅读完整文章
第55篇:线程池 ThreadPoolExecutor
📖 查看完整文章
| 核心概念 | 一句话总结 | 高频面试提问 |
|---|---|---|
| 七大参数 | corePoolSize、maxPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler | ThreadPoolExecutor 七大参数? |
| 四步执行流程 | 核心线程 → 任务队列 → 非核心线程 → 拒绝策略 | 任务提交后的执行流程? |
| 四种拒绝策略 | AbortPolicy、CallerRunsPolicy、DiscardPolicy、DiscardOldestPolicy | 线程池的拒绝策略有哪些? |
| Executors陷阱 | 无界队列→OOM,无限线程→资源耗尽 | 为什么禁止使用 Executors? |
| 线程数公式 | CPU密集型:CPU核数+1;IO密集型:CPU核数×2 | corePoolSize 如何设置? |
| 生命周期 | shutdown(优雅关闭)、shutdownNow(立即关闭) | shutdown 和 shutdownNow 的区别? |
👉 阅读完整文章
第56篇:死锁与排查工具
📖 查看完整文章
| 核心概念 | 一句话总结 | 高频面试提问 |
|---|---|---|
| 四大必要条件 | 互斥 + 持有并等待 + 不可剥夺 + 循环等待 | 死锁的四个必要条件? |
| jstack 排查 | jps -l 找 PID → jstack -l <PID> → 搜索 “deadlock” | 如何排查 Java 死锁? |
| 预防策略 | 统一锁顺序、tryLock 超时、减少锁粒度 | 如何预防死锁? |
| 死锁 vs 活锁 | 死锁永久阻塞,活锁不断重试失败 | 死锁和活锁的区别? |
👉 阅读完整文章
第57篇:CompletableFuture 异步编程
📖 查看完整文章
| 核心概念 | 一句话总结 | 高频面试提问 |
|---|---|---|
| Future 四大痛点 | 阻塞等待、无法链式、无法组合、异常难处理 | CompletableFuture 比 Future 好在哪? |
| 任务创建 | supplyAsync(有返回值)、runAsync(无返回值) | 如何创建异步任务? |
| thenApply vs thenCompose | thenApply 同步转换,thenCompose 串联异步任务 | thenApply 和 thenCompose 的区别? |
| 任务组合 | thenCombine(并行合并)、allOf(等全部)、anyOf(等任意) | 如何组合多个异步任务? |
| 异常处理 | exceptionally(兜底)、handle(都处理)、whenComplete(收尾) | 异常处理三件套的区别? |
| 线程池 | 业务异步不用 commonPool,自建线程池区分 CPU/IO | CompletableFuture 默认用什么线程池? |
👉 阅读完整文章
第58篇:原子类与 CAS
📖 查看完整文章
| 核心概念 | 一句话总结 | 高频面试提问 |
|---|---|---|
| CAS 三要素 | 内存位置 V、预期值 A、新值 B | CAS 的三要素是什么? |
| CAS 底层 | CPU 原子指令(x86: lock cmpxchg) | CAS 如何保证原子性? |
| 原子类五大分类 | 基本类型、数组、引用、属性更新器、高性能累加器 | 原子类有哪些? |
| ABA 问题 | 值 A→B→A,CAS 误判 | ABA 问题是什么?如何解决? |
| AtomicStampedReference | 版本号解决 ABA | 如何解决 ABA 问题? |
| LongAdder | 分段累加,高并发计数性能提升4倍+ | LongAdder 为什么比 AtomicLong 快? |
| VarHandle | JDK 23 正式替代 Unsafe | Unsafe 用什么替代? |
👉 阅读完整文章
第59篇:ThreadLocal 原理与内存泄漏
📖 查看完整文章
| 核心概念 | 一句话总结 | 高频面试提问 |
|---|---|---|
| 核心设计 | 空间换时间,每个线程独立变量副本 | ThreadLocal 是什么? |
| JDK 1.8架构 | Thread 对象持有 ThreadLocalMap | ThreadLocal 的数据存在哪里? |
| Entry 结构 | key(弱引用)+ value(强引用) | Entry 的 key 为什么用弱引用? |
| 内存泄漏根因 | key 被 GC 回收 → value 强引用残留 → 线程存活 → 永不释放 | ThreadLocal 的内存泄漏是怎么产生的? |
| 根治方案 | try-finally 保证 remove() 执行 | 如何正确使用 ThreadLocal? |
| remove vs set(null) | remove 删除整个 Entry,set(null) 只设值为 null | remove() 和 set(null) 的区别? |
| InheritableThreadLocal | 父子线程传递 | 子线程如何获取父线程的 ThreadLocal? |
| TransmittableThreadLocal | 线程池场景上下文传递(阿里开源) | 线程池中如何传递 ThreadLocal? |
👉 阅读完整文章
第60篇:并发编程面试压轴题
📖 查看完整文章
| 核心概念 | 一句话总结 | 高频面试提问 |
|---|---|---|
| 30+ 高频题 | 覆盖8大模块 | 多线程面试考点有哪些? |
| 锁升级 | 无锁→偏向→轻量→重量 | synchronized 锁升级过程? |
| AQS 核心 | state + CLH队列 + 模板方法 | AQS 的核心思想? |
| 线程池参数 | 七大参数 + 四步流程 + 拒绝策略 | ThreadPoolExecutor 核心参数? |
| CAS 三要素 | 内存位置 V、预期值 A、新值 B | CAS 的三要素? |
| ThreadLocal 泄漏 | 弱引用 key + 强引用 value + 忘记 remove | ThreadLocal 内存泄漏? |
👉 阅读完整文章
第60.1篇:多线程易混淆概念对比集
📖 查看完整文章
| 核心概念 | 一句话总结 | 高频面试提问 |
|---|---|---|
| sleep vs wait | sleep 不释放锁,wait 释放锁 | sleep() 和 wait() 的区别? |
| start vs run | start 启动新线程,run 是普通方法调用 | start() 和 run() 的区别? |
| synchronized vs ReentrantLock | JVM内置自动释放 vs API手动精细控制 | synchronized 和 ReentrantLock 的区别? |
| volatile vs synchronized | 轻量级可见性 vs 重量级原子性 | volatile 和 synchronized 的区别? |
| JMM vs JVM内存结构 | 管“怎么看见” vs 管“存哪里” | JMM 和 JVM 内存结构的区别? |
| 死锁 vs 活锁 vs 饥饿 | 永久阻塞 vs 空转 vs 缓慢 | 死锁、活锁、饥饿有什么区别? |
| thenApply vs thenCompose | 同步转换 vs 串联异步任务 | thenApply 和 thenCompose 的区别? |
| allOf vs anyOf | 等全部 vs 等任意 | allOf 和 anyOf 的区别? |
| exceptionally vs handle vs whenComplete | 异常兜底 vs 全部处理 vs 收尾 | 异常处理三件套的区别? |
| get vs join | 受检异常 vs 非受检异常 | get() 和 join() 的区别? |
| AtomicInteger vs LongAdder | 强一致性 vs 高吞吐弱一致 | AtomicInteger 和 LongAdder 的区别? |
| AtomicStampedReference vs AtomicMarkableReference | 版本号 vs 布尔标记 | 两种 ABA 解决方案的区别? |
| InheritableThreadLocal vs TransmittableThreadLocal | 父子线程 vs 线程池 | 跨线程传递 ThreadLocal 的两种方案? |
| remove vs set(null) | 删 Entry vs 改值为 null | remove() 和 set(null) 的区别? |
| shutdown vs shutdownNow | 优雅关闭 vs 立即中断 | shutdown() 和 shutdownNow() 的区别? |
👉 阅读完整文章
第60.2篇:面试官追问陷阱合集
📖 查看完整文章
| 核心概念 | 一句话总结 | 高频面试追问 |
|---|---|---|
| 虚拟线程 + synchronized | 虚拟线程在 synchronized 中会被固定在载体线程上 | 虚拟线程中为什么慎用 synchronized? |
| 偏向锁禁用 | 维护成本超过收益,JDK 15 默认禁用 | JDK 15 为什么默认禁用偏向锁? |
| 轻量级锁 vs 重量级锁 | 自旋 vs 阻塞,适用场景不同 | 轻量级锁一定比重量级锁快吗? |
| volatile 性能 | 约比普通变量慢 20% | volatile 比普通变量慢多少? |
| volatile vs AtomicInteger | 状态标记 vs 数字运算 | volatile 和 AtomicInteger 的区别? |
| tryLock 局限性 | 部分获取成功需要手动释放已获取锁 | tryLock 一定能避免死锁吗? |
| jstack 准确性 | 只能检测已发生的死锁 | jstack 的输出一定准确吗? |
| 数据库死锁 vs Java 死锁 | 自动回滚 vs 人工干预 | 数据库死锁和 Java 死锁有什么区别? |
| join vs get | 非受检异常 vs 受检异常 | join() 和 get() 有什么区别? |
| thenApply vs thenApplyAsync | 相同线程 vs 新线程 | thenApply 和 thenApplyAsync 的区别? |
| remove vs set(null) | 删 Entry vs 改值为 null | remove() 和 set(null) 的区别? |
👉 阅读完整文章
🔥 本阶段高频面试题精选(30道必背)
线程基础篇(5题)
- Java 线程有哪几种状态? → 6种:NEW → RUNNABLE → BLOCKED/WAITING/TIMED_WAITING → TERMINATED
sleep()和wait()的区别? → sleep 不释放锁,wait 释放锁;sleep 时间到自醒,wait 需 notifystart()和run()的区别? → start 启动新线程,run 是普通方法调用- 创建线程有几种方式? → Thread、Runnable、Callable、线程池
- 虚拟线程和平台线程的区别? → 虚拟线程轻量(几百字节),M:N 调度,适合高并发 I/O
锁与 JMM 篇(6题)
- synchronized 锁升级过程? → 无锁→偏向锁→轻量级锁→重量级锁,单向不可逆
- synchronized 的锁存在哪里? → 对象头的 Mark Word(64位JVM占8字节)
- volatile 能保证原子性吗? → 不能,
i++是读-改-写三步,volatile 不保证 - volatile 如何保证可见性? → 写即刷主存、读即强制重载 + 内存屏障
- JMM 和 JVM 内存结构的区别? → JMM 管“怎么看见”,JVM 内存结构管“存哪里”
- synchronized 和 ReentrantLock 的区别? → synchronized JVM内置有锁升级,ReentrantLock API支持超时/中断
AQS 与并发工具篇(5题)
- AQS 的核心三要素? → volatile int state + CLH 双向队列 + 模板方法模式
- AQS 的独占模式和共享模式? → 独占:ReentrantLock;共享:Semaphore/CountDownLatch
- CountDownLatch 和 Semaphore 的区别? → CountDownLatch 倒计数不可重置,Semaphore 许可可增减
- AQS 的 CLH 队列是什么? → FIFO 双向链表,存储等待线程
- ReentrantLock 的可重入性如何实现? → state 计数,当前线程持有则 state++
线程池篇(4题)
- ThreadPoolExecutor 七大参数? → corePoolSize、maxPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler
- 任务提交后的执行流程? → 核心线程 → 任务队列 → 非核心线程 → 拒绝策略
- 为什么禁止使用 Executors? → 无界队列 OOM / 无限线程资源耗尽
- corePoolSize 如何设置? → CPU密集型:CPU核数+1;IO密集型:CPU核数×2
死锁与异步篇(5题)
- 死锁的四大必要条件? → 互斥 + 持有并等待 + 不可剥夺 + 循环等待
- 如何排查死锁? →
jps找 PID →jstack -l <PID>→ 搜索 “deadlock” - CompletableFuture 和 Future 的区别? → Future 阻塞无法链式组合,CompletableFuture 支持链式/组合/回调
thenApply和thenCompose的区别? → thenApply 同步转换,thenCompose 串联异步任务allOf和anyOf的区别? → allOf 等全部,anyOf 等任意一个
CAS 与原子类篇(4题)
- CAS 的三要素是什么? → 内存位置 V、预期值 A、新值 B
- ABA 问题是什么?如何解决? → 值 A→B→A,CAS 误判 → AtomicStampedReference(版本号)
- LongAdder 为什么比 AtomicLong 快? → 分段累加,分散竞争
- Unsafe 用什么替代? → VarHandle(JDK 9 引入,JDK 23 确立为唯一推荐)
ThreadLocal 篇(4题)
- ThreadLocal 内存泄漏是怎么产生的? → Entry key 弱引用被 GC 回收,value 强引用残留 → 线程存活 → 永不释放
- Entry 的 key 为什么用弱引用? → 允许 ThreadLocal 对象被 GC 回收,弱引用只是“兜底”
- 如何正确使用 ThreadLocal? → try-finally 保证 remove() 执行
- 线程池中如何使用 ThreadLocal? → 每次任务结束必须 remove(),防止脏读和内存泄漏
- InheritableThreadLocal 和 TransmittableThreadLocal 的区别? → Inheritable 父子线程,TTL 线程池场景(阿里开源)
🧨 避坑清单(本阶段血泪教训)
| 坑点 | 错误做法 | 正确做法 |
|---|---|---|
| synchronized 锁对象为 null | synchronized(null) | 锁对象必须是非 null 引用 |
| 线程池 Executors | Executors.newFixedThreadPool() 无界队列 | 手动 ThreadPoolExecutor + 有界队列 |
| volatile 做计数器 | volatile int count++ | 用 AtomicInteger 或 LongAdder |
| CompletableFuture 不设超时 | 不设超时,可能永久阻塞 | completeOnTimeout() 或 orTimeout() |
| CompletableFuture 异常未处理 | 链中不处理异常 | exceptionally 或 handle |
| CompletableFuture 用 commonPool | 业务异步用默认线程池 | 自建业务线程池 |
| ThreadLocal 用完不 remove | 线程池场景忘记清理 | try-finally 保证 remove() |
| ThreadLocal 存大对象 | 存放大对象导致内存占用高 | 存轻量级 key,大对象放缓存 |
| ReentrantLock unlock 不写 finally | 异常时不释放锁 | 在 finally 中 unlock() |
| 死锁只用 jstack 不分析 | 只看到死锁不改代码 | 分析锁顺序,统一获取顺序 |
| AtomicStampedReference 版本号不递增 | 用 0/1 交替,仍可能漏判 | 版本号必须严格递增 |
| LongAdder 依赖精确值 | sum() 做精确计算 | 需要精确值用 AtomicLong 或加锁 |
| 虚拟线程用 synchronized | 高并发场景用 synchronized | 用 ReentrantLock 避免 Pinning |
🚀 下阶段预告(第61~70篇:JVM调优与故障排查)
并发编程与 JUC 专题已收官,JVM 调优与故障排查专题(第61~70篇) 即将开启:
- 第61篇:JVM 内存区域(JDK 8+ 堆、元空间、虚拟机栈、程序计数器)
- 第62篇:垃圾回收器详解(Serial、Parallel、CMS、G1、ZGC)
- 第63篇:GC 调优实战(日志分析、JVM 参数、年轻代/老年代调整)
- 第64篇:类加载器与热部署(双亲委派、Tomcat 热部署、自定义类加载器)
- 第65篇:OOM 与内存泄漏排查(MAT、jmap、jstat、Arthas)
- 第66篇:JIT 编译与性能优化(热点代码、逃逸分析、栈上分配)
- 第67篇:JVM 面试压轴题
👉 关注专栏 + 订阅,第一时间收到更新!
🎁 福利:本阶段全套知识点 PDF
为方便你随时复习,我把这 10 篇的核心知识点、面试题、避坑清单整理成了一份 PDF速查手册(并发编程与JUC篇)。
获取方式:
- 关注我的CSDN账号(点击关注)
- 在本文评论区留言 “并发通关” 或 私信我
- 我会将PDF下载链接发送给你
📌 下一步行动
- 收藏本文,随时回看知识点速查表和面试题
- 订阅专栏,确保后续 JVM 篇更新时第一时间收到
- 转发给正在学 Java 的朋友,帮他们也少走弯路
- 领取PDF,评论区留言“并发通关”,免费获取本阶段全套知识点手册
种一棵树最好的时间是10年前,其次是现在。
并发编程 10 篇已通关,JVM 调优专题等着你继续征服!
📌 本总结文章属于《Java 100 天进阶之路 | 从入门到上岗就业》系列。
并发编程与 JUC 阶段(第51~60篇)已收官,JVM 调优与故障排查专题即将启航。感谢一路同行,我们下一阶段见!
更多推荐

所有评论(0)