Java 多线程进阶知识(2025-2026 主流视角)
多线程是 Java 后端工程师“内功”的重要体现。基础阶段掌握创建方式、synchronized、wait/notify 后,进阶阶段真正拉开差距的是下面这些内容。
按实际掌握难度和面试/生产价值排序,从中到高难度整理(Java 8 → 21+ 都覆盖):
一、核心理论与内存模型(必考 & 最容易被深挖)
- JMM(Java Memory Model) 三大特性
- 原子性(Atomicity)
- 可见性(Visibility)
- 有序性(Ordering)
- happens-before 规则(至少背熟前6条,面试最常问)
- 程序次序规则
- 监视器锁规则(synchronized)
- volatile 变量规则
- 传递性
- start() 规则
- join() 规则
- 线程中断规则
- 线程终结规则
- 对象终结规则
- 重排序的3种类型 + as-if-serial / happens-before 保护机制
- 指令重排序、内存屏障、Store/Load Buffer、as-if-serial、JMM 对它们的折衷
二、锁与并发原语进阶(生产最常出问题的地方)
| 知识点 | 核心考察点 | 难度 | 生产价值 |
|---|---|---|---|
| synchronized 优化全过程(JDK6→21) | 偏向锁 → 轻量级锁 → 重量级锁 升级路径、锁粗化、锁消除、适应性自旋 | ★★★★★ | 高 |
| ReentrantLock 公平/非公平实现差异 | AQS + CAS + 队列 + 条件变量 | ★★★★☆ | 高 |
| ReadWriteLock 读写分离真实收益场景与写饥饿问题 | 读多写少 vs 写密集 | ★★★★ | 中高 |
| StampedLock(乐观读+悲观读写) | 比 ReadWriteLock 更细粒度,写时不阻塞读 | ★★★★ | 中 |
| LockSupport.park/unpark 原理与使用陷阱 | 先 unpark 后 park 依然有效 | ★★★★ | 高 |
| AQS(AbstractQueuedSynchronizer)核心模板 | state、CLH队列、独占/共享模式、Condition | ★★★★★ | 极高(面试压轴) |
三、JUC 工具类高频实战用法(面试+生产最常考)
| 工具类 | 典型使用场景 | 核心考察点 | 推荐掌握程度 |
|---|---|---|---|
| CountDownLatch | 主线程等 N 个子任务完成 | 倒计数、不可重用 | ★★★★★ |
| CyclicBarrier | 多线程互相等待到齐后一起继续(可重用) | 栅栏、parties、barrierAction | ★★★★☆ |
| Semaphore | 限流、数据库连接池、停车场 | 许可数、公平/非公平 | ★★★★ |
| Exchanger | 两个线程数据交换(基因算法、校对工作) | exchange 方法阻塞特性 | ★★★ |
| Phaser | 分阶段多线程协作(比 CyclicBarrier 更灵活) | arrive、register、arriveAndAwaitAdvance | ★★★★ |
| CompletableFuture | 异步编排、依赖关系、异常处理 | supplyAsync、thenCombine、exceptionally、allOf/anyOf | ★★★★★ |
四、线程池深度(ThreadPoolExecutor 几乎必考)
7个核心参数 + 4种拒绝策略 + 线程池状态流转(RUNNING → SHUTDOWN → STOP → TIDYING → TERMINATED)
常见写法对比(生产最推荐):
// 推荐写法(2025~2026 主流)
ExecutorService executor = new ThreadPoolExecutor(
corePoolSize, // 建议:2~4 × CPU核数(IO密集更高)
maximumPoolSize, // 建议:core × 2 ~ 100,根据任务阻塞程度
60L, TimeUnit.SECONDS, // 空闲线程存活时间
new LinkedBlockingQueue<>(1000~10000), // 有界队列!!!
new ThreadFactoryBuilder().setNameFormat("my-pool-%d").build(),
new ThreadPoolExecutor.CallerRunsPolicy() // 推荐 CallerRuns 而非 Discard
);
常见错误做法(红线):
- Executors.newFixedThreadPool(…) → 无界队列 OOM
- Executors.newCachedThreadPool() → 极端情况下创建海量线程 OOM/CPU爆炸
- 核心线程数 = 最大线程数 = Integer.MAX_VALUE
- 拒绝策略用 AbortPolicy(抛异常太暴力)
五、Java 19~21 虚拟线程(Virtual Threads)时代(2025年后最热门)
一句话总结:虚拟线程主要解决IO密集型高并发场景,让你写同步风格代码却获得接近异步的吞吐。
最重要对比(面试必问):
| 维度 | 平台线程(Platform Thread) | 虚拟线程(Virtual Thread) |
|---|---|---|
| 实现层 | OS 线程 | JVM 调度(Project Loom) |
| 内存开销 | 1~2MB / 线程 | ~几百字节 ~ 几KB |
| 最大数量 | 几千 ~ 上万 | 几十万 ~ 几百万甚至更多 |
| 上下文切换成本 | 高(内核态) | 极低(用户态) |
| 适合场景 | CPU密集型 | IO密集型(网络、数据库、文件等) |
| 阻塞时行为 | 占用 OS 线程 | 释放 carrier thread(挂起) |
| ThreadLocal | 正常使用 | 慎用!(可能导致内存泄漏) |
| synchronized | 正常 | 支持,但重量级锁仍较贵 |
| ReentrantLock | 正常 | 推荐(比 synchronized 更好) |
创建方式对比(Java 21+)
// 传统
new Thread(task).start();
// 虚拟线程(推荐方式1 - 直接启动)
Thread.startVirtualThread(task);
// 方式2 - Thread.ofVirtual() 构建器(最灵活)
Thread vt = Thread.ofVirtual()
.name("vt-worker-", 1)
.inheritInheritableThreadLocals(false) // 重要优化
.unstarted(task);
vt.start();
// 方式3 - 配合 Executor(最推荐生产使用)
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 100_000; i++) {
executor.submit(task);
}
}
虚拟线程最常见的生产陷阱(2025~2026 真实踩坑总结)
- ThreadLocal 大量使用 → 内存膨胀(建议用 InheritableThreadLocal 谨慎,或改用其他上下文传递方式)
- synchronized 块内长时间阻塞 → carrier thread 被长时间占用
- Pinned 线程(虚拟线程被“钉住”在 carrier 上):synchronized + native 方法、JNI、Foreign Function & Memory API
- 误用于 CPU 密集型任务 → 性能反而下降
- 监控指标缺失 → 用 JMX 或 Micrometer 监控 carrier thread 数量、虚拟线程数、 pinning 情况
六、进阶总结口诀(背下来能应付80%面试)
- 可见性问题 → volatile / happens-before / 锁
- 原子性问题 → Atomic* / LongAdder / synchronized / Lock
- 有序性问题 → volatile / synchronized / Lock
- 高并发计数 → LongAdder > AtomicLong
- 高并发限流 → RateLimiter / Semaphore
- 异步编排首选 → CompletableFuture(而非 FutureTask)
- IO密集高并发(2025年后) → 优先考虑虚拟线程 + 结构化并发(Structured Concurrency Java 21+预览)
- 线程池拒绝策略 → CallerRunsPolicy > DiscardPolicy > AbortPolicy
你目前最想深入哪个方向?
- AQS 源码级拆解
- 虚拟线程 + Spring Boot 实战改造
- CompletableFuture 高级编排技巧
- 线程池参数压测调优
- 生产中常见的死锁/活锁/饥饿/上下文切换爆炸案例
告诉我,我可以继续往对应方向展开更细的代码 + 原理 + 踩坑总结。