欢迎光临
我们一直在努力

并发编程面试突击 —— 核心知识点精讲

一、并发基础概念

1. 串行、并发、并行的区别(✅ 高频面试题)

  • ​串行​:任务依次执行,无重叠。
  • ​并发​:多个任务交替执行(逻辑上“同时”),适用于单核 CPU。
  • ​并行​:多个任务真正同时执行,需多核支持。

✅ 面试重点:能结合 CPU 核心数、任务类型(CPU 密集 vs IO 密集)解释适用场景。

2. 为什么必须调用 start() 而不是 run()?

  • start():由 JVM 创建新线程并调度执行 run()。
  • 直接调用 run():仅在当前线程执行,无并发效果。

3. 如何优雅终止线程?

  • 使用 volatile boolean flag 控制循环退出。
  • 配合 Thread.interrupt() 中断阻塞操作(如 sleep、wait)。
  • ​**禁止使用 stop()**​(已废弃,会导致状态不一致)。

4. ThreadLocal 内存泄漏原因(✅ 高频考点)

  • ThreadLocal 的值存储在 Thread 对象的 ThreadLocalMap 中。
  • 若 Thread 生命周期长(如线程池),而 ThreadLocal 未 remove(),则 value 无法被 GC。
  • ​解决方案​:使用完务必调用 remove()。

二、Java 内存模型与原子性

1. volatile 能保证原子性吗?

  • ​不能​!volatile 仅保证可见性和​禁止指令重排序​。
  • 对于复合操作(如 i++),仍需 synchronized 或原子类。

2. 高并发累加:AtomicLong vs LongAdder(✅ 高频对比题)

  • ​AtomicLong​:基于 CAS,高竞争下大量重试,性能下降。
  • ​LongAdder​:分段累加(Cell 数组),最终求和,​高并发下性能更优​。
  • ​结论​:统计类场景优先用 LongAdder。

三、锁机制深度剖析

1. Synchronized 锁升级流程

偏向锁 → 轻量级锁(CAS + 自旋) → 重量级锁(OS 级互斥)

2. 轻量级锁失败后会直接挂起吗?

  • ​不会​!会先进行​自旋​(默认 10 次),失败后才升级为重量级锁并挂起线程。

3. CAS(乐观锁) vs Synchronized(悲观锁)谁更快?

  • ​低竞争​:CAS 更快(无锁开销)。
  • ​高竞争​:Synchronized(经 JVM 优化后)可能更稳定,避免 CAS 大量重试。
  • ​结论​:无绝对优劣,需结合场景。

4. 为什么 wait() 必须在 while 循环中?

  • 防止​虚假唤醒​(spurious wakeup):线程可能在未被 notify 的情况下醒来。
  • if 会导致条件不满足时继续执行,引发逻辑错误。

5. ReentrantLock vs Synchronized 性能

  • JDK 1.6 后 Synchronized 经过大幅优化(锁消除、锁粗化、自旋等)。
  • ​一般场景两者性能接近​,但 ReentrantLock 提供更多功能(超时、公平锁、Condition)。

四、并发容器与 COW 思想

1. HashMap 为什么线程不安全?

  • ​扩容时形成环形链表​(JDK7)。
  • ​数据覆盖​:多个线程 put 相同 key 时可能丢失更新。

2. Copy-on-Write(COW)详解(✅ 阿里面试题)

  • ​原理​:写操作时复制整个底层数组,读操作无锁。
  • ​适用场景​:读远多于写(如监听器列表、配置缓存)。
  • ​优点​:读无锁、线程安全。
  • ​缺点​:写开销大、内存占用高、数据弱一致性。
  • ​典型实现​:CopyOnWriteArrayList、CopyOnWriteArraySet。

五、线程池设计与调优

1. 核心线程数计算(✅ 实战高频题)

案例:1 万 QPS,接口耗时 500ms(0.5s)

  • 单机每秒处理能力 = 核心线程数 × (1 / 0.5) = 核心线程数 × 2
  • 设单机部署 N 个核心线程,则单机 QPS = 2N
  • 要支撑 10,000 QPS → 需总核心线程数 ≈ 5000
  • 若单机部署 200 个核心线程 → 需机器数 = 5000 / 200 = 25 台

✅ 公式:

所需总线程数 ≈ QPS × 平均响应时间(秒)

机器数 = 总线程数 / 单机核心线程数

2. 拒绝策略选择

  • 默认:AbortPolicy(抛异常)
  • ​不丢任务​:使用 CallerRunsPolicy(由提交线程自己执行)
  • 自定义策略:可落库、发 MQ、记录日志等。

3. 高性能队列设计

  • 避免有锁队列(如 LinkedBlockingQueue)。
  • 推荐无锁队列:Disruptor(环形缓冲区 + 内存预加载 + 无锁 CAS)。

六、总结与面试建议

模块高频考点回答要点
线程基础 start vs run、ThreadLocal 泄漏 强调 JVM 行为与内存结构
原子操作 volatile 原子性、LongAdder 优势 明确 volatile 局限,LongAdder 分段思想
锁机制 wait 在 while 中、Synchronized 优化 虚假唤醒、锁升级、自旋
并发容器 HashMap 不安全、COW 原理 扩容死链、读写分离、弱一致性
线程池 QPS 与线程数计算、拒绝策略 公式推导、CallerRunsPolicy

💡 终极建议:面试时不仅要答出“是什么”,更要说明“为什么”和“怎么用”。结合业务场景(如秒杀、日志收集)展示架构思维,将大幅提升竞争力。

赞(0)
未经允许不得转载:171主机测评 » 并发编程面试突击 —— 核心知识点精讲
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址