Java 并发编程核心
写 Java 代码写过几年的人,都会被并发问题折磨过。
我带过的学员里,有个阿里 P7 候选人技术面全过,结果挂在了一道"ThreadLocal 内存泄漏"的追问上——他用了 ThreadLocal 做线程隔离,但在线程池场景下忘记在 finally 里 remove(),导致大量数据泄漏到其他请求里。
并发编程是 Java 里公认最难掌握的领域之一:JMM 决定了可见性和有序性,synchronized 和 JUC 锁管理了原子性,线程池管理了资源分配——每一块都足够写一本书。
这套内容,就是帮你把并发从"会用"提升到"真懂"。
内容总览
Java 并发编程可以拆成四个层次:
知识全景
模型层:理解 JMM 🔴🔴
Java 内存模型(JMM)是整个并发的基础。不理解 JMM,就永远说不清楚"为什么 volatile 可见"、"为什么需要 happens-before"。
JMM — 为什么 CPU 缓存和编译器优化会导致可见性和有序性问题
happens-before 原则 — 8 条规则,理解这些规则才能写对多线程代码
volatile 可见性与禁止重排序 — 两条核心保证:可见性 + 有序性
JMM 的核心思想:在多线程环境下,编译器/CPU 的优化不能破坏 happens-before 规则的顺序保证。通过 happens-before 规则,JMM 给程序员提供了编写正确并发代码的 contract。
volatile 不是万能的。它能保证可见性和有序性,但不能保证原子性(比如 i++ 这种读-改-写操作)。volatile 不等于"线程安全"。
锁层:从 synchronized 到 AQS 🔴🔴
synchronized 是 Java 最基础的锁。JDK6 之后引入了锁升级机制:偏向锁 → 轻量级锁 → 重量级锁。这个设计是为了减少无竞争场景下的性能开销。
synchronized vs ReentrantLock — 什么时候选 synchronized,什么时候选 ReentrantLock
CAS 原理与 ABA 问题 — 无锁并发的基础,理解它才能理解 ConcurrentHashMap 的无锁设计
AQS 抽象队列同步器原理 — JUC 并发包的基石,ReentrantLock、Semaphore、CountDownLatch 都基于它
ReentrantLock 公平锁 vs 非公平锁 — 公平 vs 非公平的 trade-off
ReentrantReadWriteLock 读写锁 — 读多写少场景的性能优化
Condition 条件队列 — await/signal 的原理
synchronized 的锁升级是不可逆的——偏向锁可以升级为轻量级锁,轻量级锁可以升级为重量级锁,但反过来不行。JDK15 之后偏向锁被废弃了,因为现代 JVM 的偏向锁优化收益越来越小。
工具层:常用并发工具 🟡
CountDownLatch 原理与使用 — 一次性屏障,等 N 个任务完成
CyclicBarrier 原理与使用 — 可重复使用的屏障,等 N 个线程都到达某点
Semaphore 信号量 — 控制同时访问资源的线程数
ThreadLocal 原理与内存泄漏 — 线程封闭的核心工具,但有内存泄漏风险
ThreadLocal 的内存泄漏是生产中的高频问题。ThreadLocalMap 的 key(ThreadLocal)是弱引用,但 value 是强引用。在线程池场景下,线程复用但 ThreadLocalMap 不会清空,value 不会被 GC。如果 ThreadLocal 不再被外部引用(key 变 null),value 就会泄漏。必须在线程使用完 ThreadLocal 后调用 remove()。
资源层:线程池 🔴
线程池是 Java 并发中最需要掌握的工程工具。不会配置线程池,并发程序要么资源耗尽,要么性能极差。
线程池7个核心参数 — corePoolSize/maximumPoolSize/keepAliveTime/workQueue/threadFactory/handler
线程池 execute 流程 — 判断流程:核心线程 → 队列 → 最大线程 → 拒绝
线程池拒绝策略对比 — AbortPolicy/CallerRunsPolicy/DiscardPolicy/DiscardOldestPolicy
线程池大小如何设置 — CPU 密集型 vs IO 密集型怎么算线程数
阻塞队列(Array/Linked/Synchronous/Delay) — 队列类型对线程池行为的影响
高级并发:CompletableFuture 与 ForkJoin 🟡
CompletableFuture 异步编程 — 链式异步编程,代替回调地狱
Fork/Join 框架 — 分治并行框架,用于递归计算任务
基础概念 🟡
进程 vs 线程 vs 协程 — 理解三者的本质区别
面试关联
并发编程和其他 Java 模块紧密相连:
- synchronized → JVM Mark Word、对象头结构
- volatile → JMM happens-before
- AQS → ReentrantLock、Semaphore
- ThreadLocal → Spring 事务管理、链路追踪
- 线程池 → Spring TaskExecutor、异步任务
阅读建议
记住:并发编程没有捷径。每一个工具、每一个概念,都要理解"它解决了什么问题"、"它本身会带来什么问题"。只知道怎么用,不知道原理和陷阱,是并发编程最大的坑。