Java 多线程 是 Java 并发编程的核心部分,它能充分利用多核 CPU,大幅提升程序的性能和响应能力。下面从零基础到核心知识点,系统梳理 Java 多线程最常用、最重要的内容(基于 JDK 8 ~ JDK 21 的主流实践,2025-2026 视角)。
1. 进程 vs 线程(最基础概念)
| 对比项 | 进程 (Process) | 线程 (Thread) |
|---|---|---|
| 资源分配单位 | 是(有独立的内存空间) | 否(共享进程的内存) |
| 调度单位 | 否 | 是(CPU 调度线程) |
| 创建开销 | 大(创建进程很重) | 小 |
| 通信方式 | 进程间通信(IPC:管道、消息队列等) | 共享内存(更快,但需注意同步) |
| 崩溃影响 | 通常只影响当前进程 | 可能导致整个进程崩溃 |
一句话总结:线程是进程内的轻量级执行单元,现代 Java 程序几乎都是多线程的。
2. Java 中创建线程的几种方式(从基础到推荐)
| 方式 | 实现方式 | 是否有返回值 | 是否推荐 | 说明与优缺点 |
|---|---|---|---|---|
| 1. 继承 Thread 类 | class MyThread extends Thread | 否 | 不推荐 | 简单,但 Java 单继承,资源浪费 |
| 2. 实现 Runnable 接口 | class MyTask implements Runnable | 否 | 常用 | 推荐,资源复用好,可继承其他类 |
| 3. 实现 Callable 接口 | class MyTask implements Callable<V> | 是 | 常用 | 配合 Future / FutureTask / ExecutorService |
| 4. 使用线程池 | ExecutorService executor = ... | 看情况 | 最推荐 | 线程复用、管理成本低、性能最佳 |
| 5. Java 21 虚拟线程 | Thread.ofVirtual().start(runnable) | — | 推荐(IO密集) | 轻量级线程,适合高并发 IO 场景 |
最推荐的写法(2025-2026 主流):
// 方式1:线程池 + Runnable(最常用)
ExecutorService executor = Executors.newFixedThreadPool(10);
executor.submit(() -> {
System.out.println("任务执行中... " + Thread.currentThread().getName());
});
// 方式2:线程池 + Callable + Future(带返回值)
Future<String> future = executor.submit(() -> "任务结果");
String result = future.get(); // 阻塞等待结果
// 方式3:Java 21+ 虚拟线程(高并发利器)
Thread virtualThread = Thread.ofVirtual().start(() -> {
// IO密集任务
});
3. 线程的生命周期(面试必考)
线程有 6 种状态(Thread.State 枚举):
- NEW 新创建,还没调用 start()
- RUNNABLE 可运行状态(包含 Running 和 Ready)
- BLOCKED 等待锁(synchronized 阻塞)
- WAITING 无限期等待(wait()、join()、LockSupport.park())
- TIMED_WAITING 限时等待(sleep()、wait(timeout)、join(timeout))
- TERMINATED 已结束
状态流转图(最常考):
NEW → start() → RUNNABLE ↔ BLOCKED / WAITING / TIMED_WAITING → TERMINATED
4. 线程安全问题三大核心特性(JMM 相关)
| 特性 | 含义 | 可能出现的问题 | 常见解决方案 |
|---|---|---|---|
| 原子性 | 一个操作要么全部完成,要么全部不完成 | i++ 不是原子操作 | synchronized / Lock / Atomic类 |
| 可见性 | 一个线程修改的值,其他线程立刻可见 | 缓存导致不一致 | volatile / synchronized / Lock |
| 有序性 | 程序执行顺序与代码顺序一致 | 指令重排序 | volatile / synchronized / Happens-before |
Java 内存模型(JMM) 核心作用:保证可见性 + 有序性(原子性靠锁或 Atomic)。
5. 线程同步 / 锁机制对比(面试高频)
| 机制 | 级别 | 可重入 | 可中断 | 公平锁 | 读写分离 | 适用场景 |
|---|---|---|---|---|---|---|
| synchronized | JVM 内置 | 是 | 否 | 否 | 否 | 简单场景,代码简洁 |
| ReentrantLock | JDK API | 是 | 是 | 可选 | 否 | 需要中断、超时、公平锁 |
| ReentrantReadWriteLock | JDK API | 是 | 是 | 可选 | 是 | 读多写少(如缓存) |
| volatile | 轻量 | — | — | — | — | 仅保证可见性 + 禁止重排序 |
| AtomicXXX | CAS 乐观锁 | — | — | — | — | 简单计数器、引用 |
| StampedLock (JDK8+) | 乐观读 | — | — | — | 是 | 高性能读写分离场景 |
synchronized 锁升级(JDK 1.6 后优化):
无锁 → 偏向锁 → 轻量级锁(自旋) → 重量级锁(操作系统 Mutex)
6. 线程池(最重要、最常使用的部分)
四大常用线程池(Executors 工厂创建):
- newFixedThreadPool:固定线程数
- newCachedThreadPool:线程数动态伸缩(慎用,OOM 风险)
- newSingleThreadExecutor:单线程顺序执行
- newScheduledThreadPool:定时/周期任务
推荐:自己创建 ThreadPoolExecutor(7大参数都搞清楚)
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, // corePoolSize
5, // maximumPoolSize
60L, // keepAliveTime
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100), // 工作队列
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
线程池参数记住口诀:核心数 → 最大数 → 存活时间 → 队列 → 线程工厂 → 拒绝策略
7. 常见并发工具(JUC 包)
| 工具类 | 作用 | 典型使用场景 |
|---|---|---|
| CountDownLatch | 倒计数门闩 | 主线程等多个子任务完成 |
| CyclicBarrier | 循环栅栏 | 多线程相互等待到齐再一起执行 |
| Semaphore | 信号量(限流) | 限流、数据库连接池 |
| Exchanger | 线程间交换数据 | 两个线程交换缓冲区 |
| Phaser | 分阶段栅栏(比 CyclicBarrier 更灵活) | 多阶段任务协调 |
| ForkJoinPool | 分治 + 工作窃取 | 大数据并行计算(如并行排序) |
8. 常见面试高频问题(2025-2026 热门)
- 线程安全怎么实现?
- synchronized 和 ReentrantLock 区别?
- volatile 能保证原子性吗?为什么?
- 死锁怎么产生?怎么排查?怎么避免?
- 线程池参数怎么设置?队列满了怎么办?
- 为什么 wait/notify 必须在 synchronized 里?
- CAS 原理?ABA 问题怎么解决?
- Java 21 虚拟线程了解吗?和传统线程区别?
如果你想深入某一块(比如:线程池参数调优、虚拟线程实战、JMM 详细、锁优化、并发容器、死锁案例等),可以告诉我,我继续展开讲解 + 代码示例。
希望这份总结对你有帮助!有什么具体想深入的方向吗?