Java 中的多线程与并发编程是后端面试中的重头戏。不管你是实习生还是准备秋招/春招,掌握线程相关知识不仅能帮你答出高频面试题,更能提升你对系统性能优化的理解。
本文将从最基础的线程创建方式,到线程池、JMM 内存模型、并发工具类、经典面试题等方面系统讲解,并附带通俗例子与答题技巧,适合收藏学习。
问题 | 核心内容 |
---|---|
Java 中如何实现多线程? | 继承 Thread 、实现 Runnable 、实现 Callable 、线程池 |
线程和进程的区别? | 线程是进程的执行单位,共享内存;进程是系统资源分配单位 |
什么是线程生命周期? | 新建 → 就绪 → 运行 → 阻塞 → 死亡 |
守护线程与用户线程区别? | 守护线程随主线程结束,如垃圾回收器 |
知识点 | 简要说明 |
---|---|
synchronized 原理 | 基于对象头的 Monitor 锁,使用重量级锁 |
volatile 关键字 | 保证可见性,不保证原子性,禁止指令重排 |
wait/notify | Object 类方法,配合 synchronized 使用,实现线程通信 |
Lock 接口 | 显式加解锁(如 ReentrantLock),可中断/公平锁/尝试锁等 |
Thread.join() | 主线程等待子线程执行完再继续 |
Thread.sleep() | 当前线程暂停一定时间,不释放锁 |
知识点 | 简要说明 |
---|---|
Executor 框架 | Java 线程池的标准框架 |
常用线程池类型 | newFixedThreadPool 、newCachedThreadPool 、newSingleThreadExecutor 、newScheduledThreadPool |
核心参数 | corePoolSize、maximumPoolSize、queueCapacity、keepAliveTime、RejectedExecutionHandler |
线程池优点 | 复用线程、控制并发数、避免频繁创建销毁线程带来的开销 |
工具类 | 用途 |
---|---|
ReentrantLock | 可重入锁,手动控制加解锁,更灵活 |
CountDownLatch | 等待多个线程完成(倒计时) |
CyclicBarrier | 所有线程到达屏障后统一执行 |
Semaphore | 信号量控制并发线程数 |
Future / Callable | 支持带返回值的任务执行 |
BlockingQueue | 支持线程安全的队列操作,适合生产者消费者模型 |
ThreadLocal | 每个线程独享变量副本,避免共享冲突 |
问题 | 要点 |
---|---|
什么是 JMM? | Java 内存模型,定义了线程如何与主内存交互(读写变量) |
可见性问题 | 一个线程修改变量,其他线程不可见,使用 volatile 解决 |
原子性问题 | 多线程同时修改共享变量,使用 synchronized 或 Atomic 类解决 |
有序性问题 | 编译器或 CPU 重排序,volatile 可防止重排 |
问题 | 涉及知识 |
---|---|
启动 10 个线程打印 1~100 | 多线程协调,任务划分 |
如何实现线程安全的单例模式? | 双重检查锁 + volatile |
为什么用 volatile 修饰单例变量? | 保证对象创建完成后其他线程可见 |
如何优雅停止一个线程? | 使用 volatile 变量配合中断标志 |
Thread 和 Runnable 区别? | Runnable 更灵活,避免单继承限制 |
sleep() 和 wait() 区别? | sleep 不释放锁,wait 释放锁,需要 notify 唤醒 |
一般来说,创建线程有很多种方式,例如继承Thread
类、实现Runnable
接口、实现Callable
接口、使用线程池、使用CompletableFuture
类等等。
Java 提供了 4 种主流的多线程实现方式:
实现方式 | 是否推荐 | 特点 |
---|---|---|
1. 继承 Thread 类 |
❌ | 只能单继承,耦合高 |
2. 实现 Runnable 接口 |
✅ | 解耦逻辑与线程控制 |
3. 实现 Callable + FutureTask |
✅ | 支持返回值和异常处理 |
4. 使用线程池(Executor) | ✅✅ | 实际开发最推荐的方式 |
不过,这些方式其实并没有真正创建出线程。准确点来说,这些都属于是在 Java 代码中使用多线程的方法。
严格来说,Java 就只有一种方式可以创建线程,那就是通过new Thread().start()
创建。不管是哪种方式,最终还是依赖于new Thread().start()
。
深入了解这个问题的可以查看这篇文章:大家都说 Java 有三种创建线程的方式!并发编程中的惊天骗局!。
新建(new)
就绪(runnable)
运行中(running)
阻塞(blocked / waiting)
终止(dead)
守护线程:如 GC 线程,随着主线程终止而自动退出
用户线程:正常业务线程,必须显式结束
关键字/类 | 功能 |
---|---|
synchronized |
加锁代码块或方法,保证原子性 |
volatile |
保证可见性,禁止指令重排 |
ReentrantLock |
可重入显式锁,支持公平/中断 |
ThreadLocal |
每个线程独立变量副本 |
✅ wait / notify 简例
synchronized(obj) {
while (condition) obj.wait(); // 等待
// 条件满足
obj.notify(); // 唤醒其他线程
}
ThreadPoolExecutor
构造函数来创建(推荐) /**
* 用给定的初始参数创建一个新的ThreadPoolExecutor。
*/
public ThreadPoolExecutor(int corePoolSize,//线程池的核心线程数量
int maximumPoolSize,//线程池的最大线程数
long keepAliveTime,//当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit,//时间单位
BlockingQueue workQueue,//任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory,//线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler//拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
ThreadPoolExecutor
3 个最重要的参数:
corePoolSize
: 任务队列未达到队列容量时,最大可以同时运行的线程数量。maximumPoolSize
: 任务队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最大线程数。workQueue
: 新任务来的时候会先判断当前运行的线程数量是否达到核心线程数,如果达到的话,新任务就会被存放在队列中。
ThreadPoolExecutor
其他常见参数 :
keepAliveTime
:当线程池中的线程数量大于 corePoolSize
,即有非核心线程(线程池中核心线程以外的线程)时,这些非核心线程空闲后不会立即销毁,而是会等待,直到等待的时间超过了 keepAliveTime
才会被回收销毁。unit
: keepAliveTime
参数的时间单位。threadFactory
:executor 创建新线程的时候会用到。handler
:拒绝策略(后面会单独详细介绍一下)。工具类 | 应用场景 |
---|---|
CountDownLatch |
等待多个线程执行完成(如初始化) |
CyclicBarrier |
多线程分阶段同步执行 |
Semaphore |
控制同时并发数 |
BlockingQueue |
线程安全队列,适合生产者-消费者 |
FutureTask |
获取异步执行结果 |
问题 | 描述 | 解决方案 |
---|---|---|
可见性 | 一个线程对变量的修改,另一个看不到 | volatile |
原子性 | 多个操作不是一个整体 | synchronized / Lock |
有序性 | 指令执行顺序与预期不一致 | volatile / happens-before 原则 |
你还想看哪些面试专题?欢迎留言!