
1. 多线程面试核心考点解析在技术面试中多线程问题始终是区分候选人水平的重要标尺。我参与过上百场技术面试发现80%的候选人在基础概念环节就会暴露出知识漏洞。以下是面试官最常考察的12个核心维度线程生命周期与状态转换重点考察WAITING/TIMED_WAITING区别synchronized底层实现对象头Mark Word结构volatile的可见性与禁止指令重排序原理内存屏障实现ThreadLocal内存泄漏场景强引用与弱引用问题AQS抽象队列同步器ReentrantLock底层实现线程池参数动态调整策略核心 vs 最大线程数取舍ConcurrentHashMap分段锁演进JDK7 vs JDK8实现差异死锁诊断与预防jstack日志分析实战CompletableFuture异步编排thenApply vs thenCompose区别无锁编程实现CAS的ABA问题解决方案协程与线程的对比尤其在内核态切换开销方面线程安全单例模式的七种写法从DCL到枚举实现演进特别注意面试官通常会要求在白板或IDE中现场实现生产者-消费者模型建议至少掌握三种实现方式wait/notify、BlockingQueue、Semaphore2. Java内存模型(JMM)深度剖析2.1 重排序问题实战// 典型的重排序案例 public class ReorderingDemo { private int x 0; private boolean flag false; public void writer() { x 42; // 操作1 flag true; // 操作2 } public void reader() { if (flag) { // 操作3 System.out.println(x); // 操作4 } } }这段代码在并发执行时可能出现x0的输出结果这是因为操作1和操作2可能被重排序。解决方案对flag变量添加volatile修饰使用synchronized同步方法通过final关键字保证可见性2.2 happens-before规则精讲Java内存模型定义了8条基本的happens-before规则其中最容易混淆的是线程启动规则Thread.start() happens-before 该线程的任何操作线程终止规则线程中的所有操作 happens-before 其他线程检测到该线程终止传递性规则A happens-before BB happens-before C则A happens-before C3. 线程池调优实战手册3.1 参数动态调整策略参数设置原则典型场景示例corePoolSizeCPU密集型N1IO密集型2N18核服务器CPU密集型设9maximumPoolSize不超过任务队列的3倍队列容量1000时设3000keepAliveTime根据任务波动周期设置电商大促期间设为5分钟workQueue有界队列优于无界队列ArrayBlockingQueue(1000)3.2 监控指标与预警ThreadPoolExecutor executor (ThreadPoolExecutor) Executors.newFixedThreadPool(4); // 关键监控指标 int activeCount executor.getActiveCount(); long completedTaskCount executor.getCompletedTaskCount(); int queueSize executor.getQueue().size();预警阈值建议活跃线程数持续 corePoolSize * 80%任务队列积压 队列容量的70%任务平均耗时 500ms4. 并发容器选型指南4.1 ConcurrentHashMap分段策略演进JDK7实现分段锁Segment继承ReentrantLock默认16个分段get操作无需加锁JDK8改进改用synchronizedCAS链表转红黑树阈值8size()方法优化baseCountCounterCell4.2 阻塞队列对比队列类型特点适用场景ArrayBlockingQueue固定容量公平锁可选固定吞吐量的生产消费场景LinkedBlockingQueue可选容量默认Integer.MAX_VALUE任务缓冲池PriorityBlockingQueue优先级排序任务分级处理SynchronousQueue零容量直接传递任务的场景DelayQueue延迟获取元素定时任务调度5. 死锁诊断四步法jstack获取线程快照jstack -l pid thread_dump.log查找BLOCKED状态线程Thread-1 #12 prio5 os_prio0 tid0x00007f48740f7000 nid0x5e1e waiting for monitor entry [0x00007f486b7fe000] java.lang.Thread.State: BLOCKED (on object monitor at com.example.DeadLock$B.run(DeadLock.java:30))分析锁持有链线程A持有锁X等待锁Y线程B持有锁Y等待锁X解决方案统一加锁顺序使用tryLock()设置超时引入死锁检测机制6. 高频面试题精解6.1 synchronized与ReentrantLock区别维度synchronizedReentrantLock实现机制JVM层面JDK层面锁获取方式隐式获取显式lock()/unlock()中断响应不支持支持lockInterruptibly()公平锁非公平可配置公平/非公平条件变量单个monitor可创建多个Condition性能JDK6后优化性能接近高竞争场景下更优6.2 ThreadLocal内存泄漏场景典型问题代码public class ThreadLocalLeak { private static ThreadLocalbyte[] localVariable new ThreadLocal(); public static void main(String[] args) { for (int i 0; i 100; i) { new Thread(() - { localVariable.set(new byte[1024 * 1024]); // 1MB // 忘记调用remove() }).start(); } } }解决方案使用后必须调用remove()改用static final修饰ThreadLocal实例继承InheritableThreadLocal时注意父子线程传递问题7. 并发编程避坑指南锁粒度控制粗粒度锁简单但并发度低细粒度锁复杂但吞吐量高推荐使用锁分段技术如ConcurrentHashMap上下文切换开销// 错误示例过度创建线程 for (int i 0; i 10000; i) { new Thread(() - {...}).start(); }优化方案使用线程池合理设置线程数建议不超过CPU核数*2伪共享问题sun.misc.Contended // JDK8引入的注解 public class FalseSharing { volatile long value1; volatile long value2; }解决方案填充无用字段padding使用Contended注解需开启JVM参数8. 现代并发工具进阶8.1 CompletableFuture组合操作CompletableFuture.supplyAsync(() - queryFromDB()) .thenApplyAsync(result - processData(result)) .thenCombine( CompletableFuture.supplyAsync(() - queryFromAPI()), (dbResult, apiResult) - mergeResults(dbResult, apiResult) ) .exceptionally(ex - handleError(ex)) .thenAcceptAsync(finalResult - saveToCache(finalResult));8.2 StampedLock乐观读public class Point { private double x, y; private final StampedLock sl new StampedLock(); public double distanceFromOrigin() { long stamp sl.tryOptimisticRead(); // 乐观读 double currentX x, currentY y; if (!sl.validate(stamp)) { // 检查是否被修改 stamp sl.readLock(); // 退化为悲观读 try { currentX x; currentY y; } finally { sl.unlockRead(stamp); } } return Math.sqrt(currentX * currentX currentY * currentY); } }9. 面试实战演练9.1 设计线程安全的LRU缓存public class ThreadSafeLRUCacheK, V { private final int capacity; private final ConcurrentHashMapK, V map; private final ConcurrentLinkedDequeK queue; public ThreadSafeLRUCache(int capacity) { this.capacity capacity; this.map new ConcurrentHashMap(capacity); this.queue new ConcurrentLinkedDeque(); } public V get(K key) { return map.computeIfPresent(key, (k, v) - { queue.remove(k); queue.addFirst(k); return v; }); } public void put(K key, V value) { map.compute(key, (k, v) - { if (v ! null) { queue.remove(k); } else if (map.size() capacity) { K eldest queue.removeLast(); map.remove(eldest); } queue.addFirst(k); return value; }); } }9.2 多阶段任务协调// 使用Phaser实现多阶段屏障 Phaser phaser new Phaser(3); // 3个参与方 for (int i 0; i 3; i) { new Thread(() - { System.out.println(阶段1完成); phaser.arriveAndAwaitAdvance(); System.out.println(阶段2完成); phaser.arriveAndAwaitAdvance(); System.out.println(阶段3完成); phaser.arriveAndDeregister(); }).start(); }10. 性能优化关键指标吞吐量QPS每秒查询数与TPS每秒事务数计算公式吞吐量 完成的任务数 / 总时间优化方向减少锁竞争、提高并行度延迟P99、P95响应时间测量方法System.nanoTime()差值优化方向减少上下文切换、避免长时间持有锁CPU利用率理想范围70%-80%过高可能存在计算密集型任务或锁竞争过低可能IO阻塞或线程数不足内存占用关注点线程栈大小默认1MB、对象头开销12字节优化建议-Xss设置合理的栈大小