Skip to content

02-并发编程面试题

对应原始资料:12-BAT/08-并发编程篇07-常见集合篇

一、线程基础

Q1:创建线程的方式

继承 Thread、实现 Runnable、实现 Callable(有返回值 + FutureTask)、线程池。

Q2:start 和 run 区别

  • start() 启动新线程并自动调 run。
  • 直接调 run() 是普通方法调用,不开新线程。

Q3:线程状态(6 种)

NEW → RUNNABLE → (BLOCKED / WAITING / TIMED_WAITING) → TERMINATED。

Q4:sleep vs wait

sleepwait
所属ThreadObject
释放锁
使用位置任意synchronized 块内
唤醒时间到notify/notifyAll

二、synchronized

Q5:synchronized 用法和锁对象

  • 修饰实例方法:锁 this。
  • 修饰静态方法:锁 Class 对象。
  • 同步代码块:锁指定对象。

Q6:synchronized 底层原理

  • 代码块:monitorenter / monitorexit 字节码指令。
  • 方法:ACC_SYNCHRONIZED 标志。
  • 锁升级(JDK 6+):无锁 → 偏向锁 → 轻量级锁 → 重量级锁
    • 偏向锁:单线程访问,CAS 设线程 ID。
    • 轻量级锁:多线程交替,自旋。
    • 重量级锁:竞争激烈,OS 互斥量。

三、volatile

Q7:volatile 两个作用

  1. 可见性:写后立即刷主存,读从主存读。
  2. 禁止指令重排:内存屏障。
  • 不保证原子性i++ 仍线程不安全)。

Q8:单例为什么要 volatile

new 不是原子,分三步:① 分配内存 ② 初始化 ③ 赋值。若重排成 ①③②,其他线程可能拿到未初始化对象。volatile 禁止重排。

四、CAS 与 AQS

Q9:CAS 原理

Compare And Swap:比较并交换。

预期值 == 内存值 ? 把内存设为新值 : 失败重试

底层 Unsafe.compareAndSwap,CPU cmpxchg 指令保证原子。

  • ABA 问题:用 AtomicStampedReference(版本号)。

Q10:AQS(AbstractQueuedSynchronizer)

  • ReentrantLock、Semaphore、CountDownLatch 的底层框架。
  • 核心:state(同步状态)+ CLH 双向队列。
  • 独占模式 / 共享模式。

五、ReentrantLock vs synchronized

维度synchronizedReentrantLock
释放自动手动 unlock(finally)
中断不可中断lockInterruptibly()
超时不支持tryLock(timeout)
公平非公平可选公平
条件一个 wait set多个 Condition

六、线程池

Q11:ThreadPoolExecutor 七参数与执行流程

详见 02-Java进阶/05。 核心线程 → 队列 → 非核心线程 → 拒绝策略。

Q12:为什么不推荐 Executors

  • newFixedThreadPool / newSingleThreadExecutor:队列 LinkedBlockingQueue 无界,易 OOM。
  • newCachedThreadPool:max 是 Integer.MAX_VALUE,线程数无限,易 OOM。
  • 用 ThreadPoolExecutor 显式指定参数。

Q13:核心线程数设置

  • CPU 密集:N + 1。
  • IO 密集:2N 或更多。

七、并发工具

Q14:CountDownLatch vs CyclicBarrier

  • CountDownLatch:一次性,等待 N 个完成(主线程等待子任务)。
  • CyclicBarrier:可重置,N 个线程互相等待到齐。

Q15:Semaphore

信号量,控制同时访问的线程数(限流)。

Q16:ThreadLocal

  • 线程私有变量副本。
  • 底层:ThreadLocalMap(key 是 ThreadLocal 弱引用)。
  • 内存泄漏:value 是强引用,线程不结束不释放;用完 remove()

八、JUC 集合

Q17:HashMap 多线程下问题

  • JDK 7:扩容采用头插法,可能死循环
  • JDK 8:尾插法不死循环,但仍可能丢数据。
  • 并发用 ConcurrentHashMap

Q18:ConcurrentHashMap 实现

  • JDK 7:分段锁 Segment(16 段)。
  • JDK 8:数组 + 链表/红黑树 + CAS + synchronized(锁桶头节点)。

Q19:CopyOnWriteArrayList

写时复制:写时加锁复制出新数组,读不加锁。适合读多写少

九、死锁

Q20:死锁四条件

互斥、请求保持、不剥夺、循环等待。

Q21:如何避免

固定锁顺序、tryLock 超时、减小锁粒度。

Q22:怎么排查

  • jstack <pid> 查线程堆栈,找 "Found one Java-level deadlock"。
  • arthas thread -b 查阻塞。

十、原子类

用途
AtomicInteger/Long基本类型原子
AtomicReference引用类型
AtomicStampedReference带版本号(ABA)
LongAdder高并发计数(分段累加)

高频考点速记

  • synchronized 锁升级:偏向 → 轻量 → 重量。
  • volatile:可见性 + 禁止重排,不保证原子。
  • CAS:比较交换,ABA 用版本号。
  • AQS = state + CLH 队列。
  • 线程池流程:核心 → 队列 → 非核心 → 拒绝。
  • ConcurrentHashMap JDK 8 锁桶头节点。