Java面试高频考点解析:ArrayList扩容与ConcurrentHashMap锁机制

📅 2026/8/22 18:49:43
Java面试高频考点解析:ArrayList扩容与ConcurrentHashMap锁机制
1. 项目概述当严肃面试遇上谢飞机式候选人去年帮公司面试Java开发岗时我遇到个典型谢飞机型候选人——简历上写着精通高并发却连ThreadPoolExecutor核心参数都说不全。这种戏剧性场景恰恰反映了当前Java面试的魔幻现实候选人拼命背八股文面试官努力辨别真才实学。本文将还原大厂三轮技术面的真实攻防重点剖析ArrayList扩容、ConcurrentHashMap分段锁等高频考点附带我整理的避坑指南和手写学习笔记。2. 核心考点深度拆解2.1 ArrayList底层实现与扩容机制// 典型面试题示例 ListInteger list new ArrayList(10); for (int i 0; i 20; i) { list.add(i); System.out.println(size: list.size() capacity: getCapacity(list)); }ArrayList的扩容是面试必问点。关键要掌握默认初始容量10JDK8后是空数组首次add时扩容扩容系数1.5倍oldCapacity (oldCapacity 1)扩容触发条件size1 elementData.length精确扩容次数公式⌈log₁.₅(n/10)⌉避坑提示明确区分size和capacity很多候选人混淆两者。size是逻辑长度capacity是物理数组长度。2.2 ConcurrentHashMap的演进之路JDK版本实现方式锁粒度特性对比≤1.7Segment分段锁16个段写竞争高≥1.8CASsynchronized节点级别锁并发度更高面试常考连环问为什么弃用分段锁内存消耗大、并发度固定size()方法如何保证准确性baseCountCounterCell扩容时如何保证线程安全ForwardingNode多线程协助2.3 ThreadPoolExecutor参数精讲ThreadPoolExecutor executor new ThreadPoolExecutor( 5, // corePoolSize 10, // maximumPoolSize 60L, // keepAliveTime TimeUnit.SECONDS, new LinkedBlockingQueue(100), // workQueue new ThreadPoolExecutor.AbortPolicy() // handler );参数配置黄金法则CPU密集型corePoolSize CPU核数 1IO密集型corePoolSize CPU核数 * 2队列选择短任务用SynchronousQueue长任务用LinkedBlockingQueue拒绝策略日志记录建议用CallerRunsPolicy3. 三轮面试实战复盘3.1 一面技术基础拷问面试官ArrayList和LinkedList遍历性能差异谢飞机呃...都是O(n)吧正解随机访问ArrayList O(1) vs LinkedList O(n)顺序访问Iterator模式下差异小于10%内存占用ArrayList节省40%-60%空间3.2 二面并发编程深挖面试官ConcurrentHashMap的get需要加锁吗谢飞机当然要啊不然怎么线程安全原理剖析get操作完全无锁Node的val和next都是volatile弱一致性迭代器反映创建时的哈希表状态写操作只锁单个桶JDK8优化3.3 三面系统设计考察场景题设计10万QPS的秒杀系统谢飞机方案用Redis的incr原子操作...优化方案本地库存Redis集群二级校验队列削峰RabbitMQ死信队列处理超时热点Key分片商品ID取模库存预热定时刷新4. 高频考点避坑指南4.1 ArrayList常见误区误区new ArrayList(100)的size是100事实size仍是0只是capacity100误区Arrays.asList()返回的是ArrayList事实返回的是Arrays内部类不支持add操作误区foreach循环中删除元素安全事实会抛ConcurrentModificationException4.2 ConcurrentHashMap致命坑点computeIfAbsent陷阱JDK8存在递归死锁风险已修复size()的代价可能需要遍历CounterCell数组扩容期间get可能读到旧哈希表的数据弱一致性4.3 线程池使用禁忌禁止使用Executors快捷方法有OOM风险核心线程数设为0会导致任务队列满才创建线程拒绝策略用DiscardPolicy可能造成数据丢失线程工厂不设名称会增加排查难度5. 手写源码学习笔记5.1 ArrayList扩容核心代码private void grow(int minCapacity) { int oldCapacity elementData.length; int newCapacity oldCapacity (oldCapacity 1); // 1.5倍 if (newCapacity - minCapacity 0) newCapacity minCapacity; if (newCapacity - MAX_ARRAY_SIZE 0) newCapacity hugeCapacity(minCapacity); elementData Arrays.copyOf(elementData, newCapacity); }5.2 ConcurrentHashMap.putVal流程计算hashspread(key.hashCode())桶为空时CAS插入桶为ForwardingNode时协助扩容存在hash冲突时synchronized锁链表头树化判断binCount TREEIFY_THRESHOLD-15.3 ThreadPoolExecutor执行流程提交任务后优先创建核心线程核心线程满后进入工作队列队列满后创建非核心线程达到maxPoolSize后触发拒绝策略空闲线程超时回收allowCoreThreadTimeOut控制6. 大厂面试备战策略6.1 知识体系构建方法概念层理解专业术语如CAS、AQS实现层阅读JDK关键源码HashMap 1.7vs1.8应用层线上问题定位线程池满排查设计层解决方案设计分布式锁选型6.2 模拟面试训练建议用录音设备记录自己的回答重点检查表述是否条理清晰总分总结构能否准确使用专业术语是否暴露知识盲区如混淆ReentrantLock和synchronized6.3 简历优化技巧项目经历按STAR法则描述技术栈区分精通/熟悉/了解避免虚假描述如自称精通JVM却说不清GC日志附带GitHub链接要确保代码质量7. 真实案例诊断候选人A声称精通多线程但不知道ThreadLocal内存泄漏问题诊断未理解ThreadLocalMap的弱引用设计不清楚remove()的必要性典型的理论与实践脱节改进方案通过Arthas模拟内存泄漏场景对比使用remove()前后的堆内存差异分析ThreadLocalMap的GC Root引用链