多线程面试题 59 道

笔记/Java/面试专栏/多线程面试题 59 道

整理自多线程面试题 59 道。深度学习见 Java 并发系列 · 扩展 并发编程面试 123 道

相关学习笔记#

专题笔记
线程基础线程基础
生命周期与通信生命周期与通信
JMM 与 volatileJMM 与 volatile
synchronized 与 Locksynchronized 与 Lock
Atomic 与 CASAtomic 与 CAS
线程池线程池
并发工具并发工具类
ThreadLocalThreadLocal
并发容器并发容器

目录#


基础概念#

1. 多线程有什么用?#

① 发挥多核 CPU 优势,真正并行;② 防止阻塞(单线程 IO 阻塞会拖死整个程序);③ 便于建模,大任务拆小任务。→ 线程基础

2. 线程和进程的区别?#

进程是资源分配单位,有独立地址空间;线程是调度单位,共享进程堆等资源,有独立栈。进程切换开销大、更健壮;线程轻量但一崩可能拖垮进程。→ 线程基础

3. Java 实现线程有哪几种方式?#

继承 Thread、实现 Runnable、Callable+Future、线程池提交任务。生产优先线程池。

4. start() 和 run() 有什么区别?#

start() 启动新线程由 JVM 调用 run(),多线程交替/并行;直接 run() 只是当前线程普通方法调用。

5. 怎么终止线程?如何优雅终止?#

废弃 stop()。用 interrupt + 正确处理中断,或 volatile 标志 协作退出。

6. 线程生命周期有哪几种状态?如何流转?#

NEW → RUNNABLE ⇄ BLOCKED/WAITING/TIMED_WAITING → TERMINATED。→ 生命周期

7. wait() 和 sleep() 有什么区别?#

sleep 不释放锁,属 Thread;wait 释放对象监视器,属 Object,需 notify 唤醒。

8. 多线程同步有哪几种方法?#

synchronized、Lock(ReentrantLock 等)、分布式锁;读多写少可用 ReadWriteLock。

9. 什么是死锁?如何避免?#

两线程互相等待对方锁。避免:固定加锁顺序、缩小锁范围、tryLock 超时、避免嵌套多锁。

10. 多线程之间如何通信?#

wait/notify/notifyAll、BlockingQueue、Condition、CountDownLatch 等。

11. 线程怎样拿到返回结果?#

实现 Callable,配合 Future/FutureTask 或线程池 submit

12. volatile 关键字的作用?#

保证可见性;禁止特定指令重排序。不保证 i++ 等复合操作原子性;常与 CAS 配合。→ JMM 与 volatile

13. T1、T2、T3 如何保证按顺序执行?#

链式 join():t1.start(); t1.join(); t2.start(); t2.join(); …

14. 怎么控制同一时间只有 3 个线程运行?#

Semaphore(3)acquire() / release()

20. 什么是原子性、可见性、有序性?#

原子性:操作不可分割;可见性:修改对其他线程可见;有序性:程序执行顺序感知。→ JMM

21. 什么是守护线程?有什么用?#

守护线程为其他线程服务,JVM 在所有用户线程结束后退出。setDaemon(true)

22. 线程运行时发生异常会怎样?#

未捕获则线程终止;可通过 UncaughtExceptionHandler 统一处理。

23. yield() 有什么用?#

提示让出 CPU,不保证其他线程立即运行。

43. 多线程上下文切换是什么?#

CPU 从一线程切换到另一线程,保存/恢复上下文,有开销。

44. Java 用什么线程调度算法?#

抢占式;高优先级/饥饿等因素影响时间片分配。

45. Thread.sleep(0) 的作用?#

可能触发重新分配时间片,平衡低优先级线程机会。

46. Java 内存模型?哪些共享、哪些不共享?#

堆、方法区共享;栈、PC、本地方法栈线程私有。→ JMM

47. 乐观锁和悲观锁?#

悲观:先加锁再操作(synchronized)。乐观:CAS 比较交换,失败重试。

51. Runnable 和 Thread 用哪个好?#

优先 Runnable,避免占用唯一继承位,便于线程池。

56. Java 中堆和栈有什么不同?#

堆共享存对象;每线程独立栈存局部变量、栈帧。堆上共享变量需同步或 volatile。

57. 如何获取线程堆栈?#

jstack pid、Linux kill -3、JVisualVM/JConsole 等。

58. 如何创建线程安全的单例?#

饿汉式、静态内部类、枚举;懒汉 DCL 需 volatile 实例引用。→ DCL

59. 什么是阻塞式方法?#

结果返回前当前线程挂起,如 accept()read()Future.get()


创建与生命周期#

(见上 3–7、21–23、43–46、51、56–59)


同步与通信#

19. 什么是活锁、饥饿、无锁、死锁?#

死锁:互相等锁;活锁:互相谦让都不前进;饥饿:长期拿不到 CPU/锁;无锁:CAS 循环改共享值,无阻塞。→ synchronized 与 Lock

24. 什么是重入锁?#

同一线程可多次获取同一把锁。synchronized、ReentrantLock 均可重入。

25. synchronized 有哪几种用法?#

锁实例方法、锁静态方法、锁代码块(指定对象)。块范围越小越好。

32. 线程同步需要注意什么?#

缩小同步范围;分布式场景用分布式锁;固定加锁顺序防死锁。

33. wait() 使用前提?#

必须在持有对象监视器的 synchronized 块内。

36. 保证可见性有哪几种方式?#

synchronized、volatile、Lock。

48. Hashtable 的 size() 为什么要同步?#

put 与 size 并发时,非同步 size 可能读到中间态;同步保证一致性。

49. 同步方法和同步块哪种更好?#

同步块更好,锁外代码仍可并发,原则:同步范围越小越好。

50. 什么是自旋锁?#

线程循环 CAS 尝试获锁而不挂起;适合锁持有极短。

52. notify 和 notifyAll 区别?#

notify 唤醒一个等待线程;notifyAll 唤醒全部,由锁竞争决定谁执行。

53. 为什么 wait/notify 在 Object 而不是 Thread?#

锁是对象级;wait 表示等待某个对象的锁条件。

54. 为什么 wait/notify 要在同步块中?#

API 强制,否则 IllegalMonitorStateException;也避免 wait/notify 竞态。

55. 为什么要在循环中检查 wait 条件?#

防止伪唤醒;被唤醒时条件可能已变,需 while 再判断。


JMM 与锁#

29. 什么是 CAS?多线程中哪些应用?#

Compare-And-Swap,原子比较替换。java.util.concurrent.atomic 包、ConcurrentHashMap 部分操作。→ Atomic 与 CAS

30. 怎么检测线程是否拥有锁?#

Thread.holdsLock(obj)

37. 常用的 Lock 实现?#

ReentrantLock、ReentrantReadWriteLock。

38. ThreadLocal 是什么?应用场景?#

线程内局部变量;数据库连接(老)、SimpleDateFormat、用户上下文。线程池场景必须 remove。→ ThreadLocal

39. ReadWriteLock 有什么用?#

读共享、写独占,读多写少提升吞吐。

40. FutureTask 是什么?#

可提交线程池的 Runnable,同时是 Future,获取 Callable 异步结果。

41. 怎么唤醒阻塞线程?#

wait/sleep/join 阻塞可 interrupt;IO 阻塞无法被 Java 直接唤醒。

42. 不可变对象对多线程有什么帮助?#

安全发布后可无锁读,无需额外同步。


线程池与工具#

15. 为什么要使用线程池?#

复用线程、控制数量,避免频繁创建销毁和线程过多耗尽资源。→ 线程池

16. 常用线程池及原理?#

Fixed/Cached/Single/Scheduled;底层 ThreadPoolExecutor:core/max/队列/拒绝策略。

17. submit() 和 execute() 区别?#

execute 无返回值;submit 返回 Future,可 get 结果和异常。

18. CyclicBarrier 和 CountDownLatch 区别?#

Latch 一个等多个、一次性;Barrier 多个互相等到齐、可重用。→ 并发工具

26. Fork/Join 框架干什么?#

大任务拆分并行,再合并结果。

27. 线程数过多会造成什么异常?#

栈溢出、OOM、GC 压力等。

28. 线程安全和不安全的集合?#

HashMap、ArrayList 非线程安全;Vector、Hashtable 同步但性能差;推荐 ConcurrentHashMap 等。→ 并发容器

34. Fork/Join 使用注意?#

拆分过深线程堆积;递归过深栈溢出。

35. 线程之间如何传递数据?#

共享对象 + 同步;BlockingQueue 生产者-消费者。

60. 提交任务时线程池队列已满会怎样?#

未达 max 则新建线程;达 max 且队列满则执行拒绝策略(Abort/CallerRuns 等)。


排查与其他#

31. JDK 排查多线程用什么命令?#

jstack 打印线程栈;配合 jps 查 pid。


速记#

主题关键词
创建Runnable、Callable、线程池
协作wait/notify + while、synchronized
可见性volatile、synchronized
原子Atomic、CAS、锁
限流Semaphore、线程池 max
排查jstack、jconsole
文章目录

文章目录