《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 内存泄漏? |
👉 阅读完整文章
🔥 本阶段高频面试题精选(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 调优与故障排查专题即将启航。感谢一路同行,我们下一阶段见!
