整理自 Java 并发编程面试题 123 道(含多章节子题)。精简版多线程题见 多线程面试 59 道。
相关学习笔记
| 专题 | 笔记 |
|---|---|
| 线程基础 | 01 线程基础 |
| 生命周期 | 02 生命周期与通信 |
| JMM / volatile | 03 JMM 与 volatile |
| synchronized / Lock | 04 synchronized 与 Lock |
| Atomic / CAS | 05 Atomic 与 CAS |
| 线程池 | 06 线程池 |
| 工具类 | 07 并发工具类 |
| ThreadLocal | 08 ThreadLocal |
| 并发容器 | 09 并发容器 |
目录
一、基础知识(1–52)
1. 为什么要使用并发编程?
提高多核 CPU 利用率;业务拆分并行(如订单减库存);避免单线程 IO 阻塞拖死整体。
2. 多线程应用场景
下载多线程、连接池、批量发短信、Web 容器多线程处理请求等。
3. 并发编程有什么缺点?
上下文切换开销、内存占用、竞态与死锁、调试困难;并非总能加速。
4. 并发编程三个必要因素?
原子性、可见性、有序性。→ JMM
5. Java 如何保证多线程运行安全?
synchronized/Lock 保原子性;volatile/synchronized/Lock 保可见性;happens-before 保有序性。
6. 并行和并发有什么区别?
并发:单核交替,逻辑同时;并行:多核真正同时;串行:单线程顺序执行。
7–9. 什么是多线程 / 好处 / 劣势
多执行流;提高 CPU 利用、防阻塞;代价是内存、调度、同步复杂度。
10. 线程和进程区别
资源分配 vs 调度单位;独立地址空间 vs 共享堆;切换开销与健壮性不同。→ 线程基础
11. 什么是上下文切换?
时间片用完,保存当前线程状态、切换另一线程,有 CPU 开销。
12. 守护线程和用户线程区别
用户线程结束则 JVM 退出;守护线程自动结束。setDaemon(true)。
13. 如何查找 CPU 占用最高的线程?
Linux:top → top -H -p pid → 线程 id 转 16 进制 → jstack pid 对照;或用 JVisualVM。
14–16. 死锁 / 四条件 / 如何避免
互相等待资源;互斥、占有等待、不可抢占、循环等待。固定加锁顺序、tryLock 超时、缩小锁范围。
17. 创建线程的四种方式
Thread、Runnable、Callable+Future、线程池。
18. Runnable 和 Callable 区别
Runnable 无返回值无 checked 异常;Callable 有返回值,可抛异常。
19–20. run() 和 start() / 为何 start 会执行 run
start 注册到 JVM 调度;run 只是普通方法。→ 线程基础
21–22. Callable 与 Future / FutureTask
Future 表示异步结果;FutureTask 实现 Runnable+Future,可提交线程池。
23. 线程的状态
NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED。
24–26. 调度算法 / 策略 / Scheduler
抢占式;时间片轮转;Scheduler 分配 CPU 时间片。
27. 线程同步与调度相关方法
wait/notify/notifyAll、sleep、yield、join、interrupt 等。
28. sleep() 和 wait() 区别
sleep 不释放锁;wait 释放监视器并等待 notify。
29. wait 用 if 还是 while?
while,防伪唤醒。→ 生命周期
30–31. wait/notify 为何在 Object / 为何要在同步块
锁是对象级;API 要求,否则 IllegalMonitorStateException。
32–34. yield / sleep 与 yield 区别 / 为何是静态
yield 让出 CPU;sleep 阻塞指定时间;作用于当前线程故静态。
35. 如何停止正在运行的线程?
协作式 interrupt 或 volatile 标志,不用 stop()。
36. interrupted 和 isInterrupted 区别
interrupted() 静态,检测并清除中断标志;isInterrupted() 实例,不清除。
37–38. 阻塞式方法 / 如何唤醒阻塞线程
accept/read/get 等;interrupt 可唤醒 wait/sleep/join,IO 阻塞难以中断。
39. notify 和 notifyAll
notify 唤醒一个;notifyAll 唤醒全部。
40–41. 两线程共享数据 / 通讯与协作
共享变量+同步;wait/notify、BlockingQueue、Lock Condition。
42–43. 同步块 vs 同步方法 / 同步与互斥实现
同步块范围更小更好;synchronized、Lock、volatile(有限)。
44. Monitor 内如何做线程同步
enter monitor → 执行 → exit;竞争 monitor 所有权。
45. 提交任务时队列已满会怎样?
未达 max 扩线程;达 max 且队列满则拒绝策略;无界队列则持续排队。→ 线程池
46–47. 线程安全 / Servlet 线程安全吗
多线程访问共享数据结果正确;Servlet 实例共享,成员变量需防并发,局部变量安全。
48. 线程优先级
1–10,影响调度概率非绝对;避免依赖优先级保证逻辑。
49. 线程构造方法、静态块被谁调用
定义该线程的父线程(创建 Thread 对象的线程)。
50. 如何获取线程 dump
jstack pid、kill -3、JConsole/VisualVM。
51–52. 线程异常 / 线程过多异常
未捕获则线程终止;OOM、栈溢出、GC 压力。
53. 多线程常用方法(节选)
start、run、sleep、join、interrupt、currentThread、setDaemon 等。
二、并发理论与同步(1–35)
1–2. GC 目的 / 线程通信与同步
回收无用对象;Java 共享内存模型,通信隐式通过主内存完成。
3. Java 内存模型
线程本地内存与主内存;写 flush、读 load 才可见。→ JMM
4–5. null 引用立即回收吗 / finalize
不会立即;finalize 在 GC 决定回收时调用一次,不可靠,不推荐依赖。
6–8. 重排序 / 三种重排 / as-if-serial 规则
编译器、CPU、内存系统重排;单线程结果不变,多线程可能可见性问题。
9. as-if-serial 与 happens-before 区别
前者保证单线程语义;后者保证正确同步的多线程结果。
10–11. synchronized 关键字 / 项目用法
修饰方法、静态方法、代码块;勿锁 String 常量池相同对象。
12. 双重检查锁单例
实例引用必须 volatile,防指令重排看到未初始化对象。
13–14. synchronized 底层 / 可重入原理
monitor enter/exit;计数器重入。
15–16. 自旋 / synchronized 锁升级
忙循环尝试获锁;无锁→偏向→轻量→重量。→ synchronized
17–18. 线程 B 如何知道 A 修改变量 / 其他线程能否进其他 synchronized 方法
volatile/synchronized 可见;实例锁锁整个实例非静态方法,静态锁锁类。
19. synchronized、volatile、CAS 比较
synchronized 互斥;volatile 可见+有序;CAS 无锁原子更新。
20–21. synchronized 和 Lock / 和 ReentrantLock 区别
Lock 可 tryLock、公平、多 Condition、需手动 unlock。
22–26. volatile 作用 / 能否 volatile 数组 / vs Atomic / 能否变原子 / vs synchronized
可见+禁重排;数组元素需 AtomicReferenceArray 等;volatile 不保证 i++。
27. final 不可变对象的帮助
安全发布后无锁读,简化并发。
28. Lock 相对 synchronized 优势
尝试锁、超时、中断、读写锁、公平性。
29–31. 乐观悲观锁 / CAS / CAS 问题
CAS 乐观;ABA、自旋开销、单变量限制。→ Atomic
32–34. 原子类 / 常用类 / Atomic 原理
AtomicInteger 等;Unsafe CAS 循环。
35. 死锁、活锁、饥饿区别
见 多线程 59 道 #19。
三、线程池(1–15)
1–3. 线程池是什么 / 作用 / 优点
复用线程、控制并发、降低创建销毁开销。
4–5. ThreadPoolExecutor / Executors
七大参数;Executors 工厂方法,生产建议手动 new ThreadPoolExecutor。
6–8. 四种创建方式 / Executor vs Executors / 区别与特点
Fixed、Cached、Scheduled、Single;Cached 可能线程爆炸,Fixed 无界队列风险。
9. 线程池状态
RUNNING → SHUTDOWN → STOP → TIDYING → TERMINATED。
10. submit 和 execute
submit 返回 Future;execute 无返回值。
11. 线程组为何不推荐
ThreadGroup API 老旧,异常处理弱;用线程池+命名 ThreadFactory。
12. 饱和策略
Abort、CallerRuns、Discard、DiscardOldest。
13–14. 自定义线程池 / 执行原理
显式 core/max/队列/handler;core 未满新建→入队→扩到 max→拒绝。
15. 如何合理分配大小
CPU 密集 ≈ 核数;IO 密集可 2×核数或按阻塞比例估算。→ 线程池
四、并发容器(1–14)
1. 常用并发容器
ConcurrentHashMap、CopyOnWriteArrayList;替代 Vector/Hashtable。
2–4. Vector / vs ArrayList / Hashtable 为何线程安全
方法 synchronized;Hashtable 全表锁。
5–6. ConcurrentHashMap vs Hashtable / synchronizedMap
CHM 桶级锁/CAS;Hashtable 全表锁;JDK8 CHM 无 Segment。
7. ConcurrentHashMap 并发度
JDK7 Segment 数;JDK8 弃用,CAS+synchronized 桶。
8–10. 并发容器实现 / vs 同步集合 / SynchronizedMap vs CHM
锁分离、写时复制;CHM 迭代弱一致不抛 CME(部分容器)。
11–14. CopyOnWriteArrayList 是什么 / 场景 / 缺点 / 设计思想
读多写少;写复制数组;写开销大、最终一致。→ 并发容器
五、并发队列(1–6)
1–2. 并发队列是什么 / vs 并发集合
FIFO 协作;集合强调共享数据结构。
3–4. 阻塞 vs 非阻塞 / 区别
BlockingQueue 满/空时阻塞;ConcurrentLinkedQueue CAS 非阻塞。
5. 常用队列介绍
ArrayBlockingQueue(有界)、LinkedBlockingQueue、SynchronousQueue、DelayQueue、PriorityBlockingQueue 等。
6. SynchronousQueue
不存储元素,直接交接,线程池 Cached 常用。
六、并发工具类(1–3)
1. 常用并发工具类
CountDownLatch(一个等多个)、CyclicBarrier(互相等到齐)、Semaphore(限流)。
2–3. CyclicBarrier 细节 / Semaphore
Barrier 可重用+ barrierAction;Semaphore acquire/release 控制并发数。
→ 详见 并发工具类
速记对照
| 场景 | 选型 |
|---|---|
| 共享 Map | ConcurrentHashMap |
| 读多写少 List | CopyOnWriteArrayList |
| 任务排队 | BlockingQueue + 线程池 |
| 等多任务完成 | CountDownLatch |
| 限 3 并发 | Semaphore(3) |
| 线程内上下文 | ThreadLocal + remove |
| 可见性 | volatile / synchronized |
| 原子计数 | AtomicInteger / LongAdder |