ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

有赞校招Java笔试B卷深度解析:HashMap、线程池与JVM实战

2026/8/31 21:57:39 拓冰建站 浏览量
有赞校招Java笔试B卷深度解析:HashMap、线程池与JVM实战 1. 从这套B卷看有赞校招Java笔试的出题逻辑有赞2019校招Java笔试B卷这套题在当年应届生圈子里流传度不算低。原因很简单它不是那种纯刷LeetCode就能应付的卷子而是把Java基础、集合源码、并发编程、JVM、算法、数据库、网络基础全部搅在一起题量不小覆盖范围也广看得出是认真设计过的。先说整体印象。这套卷子给我的感觉是——出题人不是在考你背了多少知识点而是在考你平时写代码的时候有没有想过底层在干什么。举个例子同样是考HashMap普通面试题会问HashMap底层数据结构是什么但这套B卷会更倾向于给你一段代码场景让你判断扩容时机、分析put流程中链表转红黑树的条件甚至会让你推演并发put时可能出现的问题。这种考法对死记硬背的人非常不友好但对真正读过源码、写过并发代码的候选人来说反而是送分题。有赞的笔试侧重能不能干活而不是会不会背书。这一点贯穿整张卷子。对准备校招的同学来说这套题的参考价值在于它代表了电商SaaS类互联网公司对Java开发岗的能力预期。你不需要去背原题答案但你需要把它涉及的知识点逐个吃透并且知道每个知识点在公司实际业务里对应什么场景。我自己复盘这套卷子时把它涉及的考察点分了几个大块Java集合与并发占比最高、JVM与内存管理、算法与数据结构、数据库与SQL优化、计算机网络与操作系统基础。下面逐个展开说每块我都会结合当年的题目场景和后来工作中的实际体会来分析。2. Java集合与并发不只考是什么更考怎么用、哪里会出事2.1 HashMap的底层扩容与链表树化从源码推演到并发隐患Java集合这块B卷几乎必考HashMap而且考得相当细。正常的复习资料会告诉你HashMap底层是数组加链表JDK8之后引入红黑树但这套卷子明显不满足于这个层面。我记得有几道题是围绕put一个key时发生了什么展开的先计算key的hashCode然后扰动函数把高16位和低16位异或降低哈希碰撞概率接着用 (n - 1) hash 定位到数组下标如果该位置是空直接放入如果非空则遍历链表比较key是否存在存在就覆盖value不存在就尾插链表长度超过8且数组长度达到64时转为红黑树。这里面的隐藏考点有几个。第一为什么树化阈值是8而不是其他数字源码注释里给了泊松分布的计算理想情况下负载因子0.75、随机哈希碰撞链表长度到达8的概率已经非常低所以8是个经过概率计算的阈值。第二为什么树化之前还要判断数组长度是否达到64因为当数组还很小的时候更合理的做法是扩容而不是树化扩容后链表会被拆分长度自然降下来。真正容易丢分的是扩容这个过程。JDK7的头插法在并发场景下会形成环形链表导致get死循环JDK8改成尾插法解决了环路问题但并发put仍然会造成数据覆盖和size计数不准确。这套卷子大概率会在某个场景题里埋这个坑让你判断下面这段代码在并发下会有什么问题。我建议准备时直接把JDK7和JDK8的resize过程各画一遍图搞清楚元素在扩容后是怎么rehash的——低位的留在原位高位的移动到原位置加旧容量的位置。这个结论不仅笔试能用面试聊到HashMap并发问题时也是重要加分项。2.2 线程池的七个参数与任务拒绝策略线程池是有赞这类高并发业务场景公司的必考点。B卷里关于线程池的题通常不会只问你核心线程数、最大线程数这些参数定义而是给出一个具体场景比如某个接口平均耗时200ms峰值QPS 500机器4核8G你该怎么设置线程池参数。这种题没有标准答案考的是你的思考过程。核心线程数一般参考CPU密集还是IO密集CPU密集用 N1IO密集用 2N 或者更高。但实际业务多数是IO密集型因为有网络调用和数据库操作所以可以适当调大。队列容量要考虑积压任务的内存消耗拒绝策略要结合业务容忍度——抛异常、丢弃、由调用线程执行、丢弃最老的各有适用场景。这道题还有个容易忽略的点线程池的线程是怎么创建的核心线程默认不会预热是任务到达后才逐个创建直到达到核心线程数之后新任务进队列队列满了才创建非核心线程到最大线程数再满才触发拒绝策略。很多人以为先创建到最大线程数再进队列这个顺序理解错了笔试里专门有题考这个。2.3 synchronized与volatile的底层语义并发编程那块volatile和synchronized基本是捆绑出现的。B卷里常见的考法有两类一类是问你volatile能保证原子性吗另一类是给一段多线程代码让你分析输出结果和原因。volatile的语义是可见性和禁止指令重排它底层是通过内存屏障实现的。写volatile变量时JVM会在写操作后插入StoreStore屏障和StoreLoad屏障确保之前的普通写入对其他线程可见并且禁止把volatile写重排到普通写之前。读volatile变量时会在读操作前插入LoadLoad屏障和LoadLoad屏障禁止后续普通读重排到volatile读之前。但volatile不保证复合操作的原子性经典的 i 问题就是坑。很多准备不充分的人会在这里丢分因为概念背得很熟但一落到代码分析就乱了。synchronized的底层则涉及偏向锁、轻量级锁、重量级锁的升级过程以及Monitor对象、Mark Word里的锁状态位这些在B卷里如果有题通常是让你分析锁升级的条件和性能差异。3. JVM内存与故障排查笔试里最能拉开差距的硬骨头3.1 运行时数据区与对象创建流程JVM这块B卷考察的深度比较稳定运行时数据区划分、对象创建过程、垃圾回收算法与收集器、内存溢出排查。看起来是老生常谈但出题角度会绕。比如运行时数据区大家都会背堆、栈、方法区、程序计数器、本地方法栈但题目可以这么出一个局部变量、一个static变量、一个字符串常量、一个new出来的对象实例分别存在哪里这就要你分清局部变量存在虚拟机栈的局部变量表对象实例存在堆static变量在JDK8以后存在堆里的Class对象中以前是方法区现在方法区被元空间替代静态变量实际在堆里字符串常量在堆里的字符串常量池中。对象创建流程也是常考细节类加载检查、分配内存指针碰撞或空闲列表、内存空间初始化零值、设置对象头、执行构造方法。其中内存分配方式取决于垃圾收集器是否有压缩整理能力而对象头里存储了哈希码、GC分代年龄、锁状态标志——这些信息在后续并发那几道题里还能串起来。3.2 内存溢出与内存泄漏从OutOfMemoryError到排查思路相关热搜词里有一条 java: outofmemoryerror: insufficient memory这个词出现在这里一点都不意外因为笔试题里关于OOM的题目历来是拉开差距的地方。B卷关于OOM通常不会只问OOM有哪几种而是给你一段代码或一个场景问你这段代码会不会OOM是哪一种OOM发生在哪个区域。比如无限创建线程导致无法创建本地线程抛出 OutOfMemoryError: unable to create new native thread这和堆内存无关是操作系统的线程数限制。在循环里用字符串拼接如果JVM没有优化会产生大量中间String对象最终堆内存溢出。大量使用直接内存DirectByteBuffer但MaxDirectMemorySize设置过小抛出OOM。递归没有出口导致栈溢出 StackOverflowError。真正需要理解的是排查思路。我后来在工作中遇到过好几次堆内存OOM最快的定位方式就是用 jmap 导出堆dump然后用MAT分析支配树看哪个对象占用的内存最大、被谁引用。笔试阶段不会让你实际操作但题目可能会问线上OOM了你会怎么排查这里建议按这个顺序答先jps找进程再jstat看GC情况jmap dump堆MAT分析必要时查GC日志。把排查链路说完整比单纯背概念更能拿分。3.3 垃圾收集器与GC日志解读GC相关题目B卷可能涉及CMS和G1的区别、Minor GC和Full GC的触发条件、对象什么时候进入老年代年龄达到15、大对象直接进老年代、动态年龄判断、空间分配担保等。CMS和G1这块核心区别是CMS基于标记-清除算法会产生内存碎片并发阶段和用户线程并行执行G1基于Region化内存布局通过复制算法在Region之间回收可以指定最大停顿时间。B卷如果有选择题大概率会考哪个收集器会产生内存碎片哪个收集器适合大堆内存这类结论。GC日志解读也是可能的出题方向。给你一段GC日志让你判断这次GC是Minor GC还是Full GC、回收前后堆内存变化、耗时多少、有没有晋升失败。这类题说实话很看平时的实战积累如果只刷概念题看到日志很容易懵。我的建议是准备阶段自己启动一个Spring Boot应用用 jstat 观察GC频率手动设置 -Xms 和 -Xmx 制造几次GC把日志保存下来逐行看一遍基本就能掌握。4. 算法与数据结构不追求偏难怪但要求边界条件严谨4.1 排序算法的变种考察与手写代码算法这块B卷的难度定位应该是LeetCode中等偏下但很注重边界条件。排序算法是高频考点尤其快排归并这类基础排序几乎年年出现。快排有个经典的变种考法给一个整数数组让你找第K大的元素。很多人第一反应是先排序再取下标但面试官期待的是手写快排的分区逻辑每次partition后判断基准元素的位置和K的关系平均时间复杂度O(n)。这个题在有赞这套B卷里出现的概率很高因为代码量不大又能考验对分治思想的理解。我在给应届生做模拟面试时发现大部分人能写出基本快排但一到边界条件就出问题left和right的移动顺序搞错、等于基准值的元素处理不当、递归终止条件写错导致栈溢出。我的建议是快排、归并、堆排序各自手写三遍以上每遍都刻意测试空数组、单元素数组、全相同元素数组、已经有序的数组把这些边界跑通笔试手写代码才能稳。4.2 链表的操作反转、相交与环形检测链表题在有赞这类公司的笔试题里也很常见。无他链表能考察指针操作和逻辑严谨性而且代码量适中适合笔试环境。高频题包括链表反转迭代和递归两种写法、判断两个链表是否相交并返回相交节点、检测链表是否有环并找到环入口。链表反转的迭代写法是准备重点需要维护prev、curr、next三个指针很多人一紧张就绕晕。判断链表是否有环是快慢指针的经典应用快指针每次走两步慢指针每次走一步如果相遇则有环。找环入口的数学推导——从相遇点到环入口的距离等于从头节点到环入口的距离——这个结论也要会推导光背结论的话笔试时一旦变体就露馅了。4.3 动态规划与字符串处理字符串类题目在有赞笔试题里也占一定比例常见的是最长公共子串、最长回文子串、字符串匹配。这类题如果出通常不会太难但动态规划的状态定义和转移方程是核心。以最长回文子串为例动态规划解法中 dp[i][j] 表示 s[i..j] 是否为回文串状态转移方程是 dp[i][j] s[i]s[j] (j-i2 || dp[i1][j-1])。这种题要拿满分关键在于遍历顺序——必须按子串长度从小到大遍历否则依赖的子问题还没计算出来。很多人栽在这里。背包类动态规划0-1背包、完全背包也是常客。有赞这类电商业务场景可能会把背包问题包装成凑金额优惠券组合之类的生活化题目但核心模型不变。准备时建议把01背包的滚动数组优化理解透内层循环为什么要倒序遍历因为要保证每个物品只选一次。理解了这一层笔试遇到变种就不慌。4.4 手写代码时的输出规范与复杂度分析算法题还有一个隐形考点复杂度分析。B卷很可能要求你写出算法的时间复杂度和空间复杂度。很多人代码写对了复杂度分析却没写完整白白丢分。我在实际批改校招笔试题时发现能清楚写出时间复杂度O(n)、空间复杂度O(1)、额外空间O(1)这种完整描述的人不到三成。复杂度分析不只是格式要求它能反映你有没有系统学过算法分析。另一个容易忽略的点是输出规范。题目如果要求输出排序后的数组你得注意分隔符要求返回布尔值的地方别返回字符串。这些细节看起来不算什么但在机考环境下输出格式不对可能导致判题直接失败。5. 数据库与SQL优化业务场景里的实操能力考察5.1 索引失效场景与最左前缀原则数据库部分有赞这类电商SaaS公司非常看重因为日常开发几乎天天和数据库打交道。B卷的数据库题通常围绕索引、SQL优化、事务隔离级别展开。索引失效的典型场景包括对索引列使用函数或计算where salary*2 1000、隐式类型转换、like通配符开头的模糊查询、or条件中有非索引列、不满足最左前缀原则的复合索引查询。最左前缀原则是重点中的重点。复合索引 (a, b, c) 可以匹配 (a)、(a,b)、(a,b,c) 查询但不能直接匹配 (b,c) 或只匹配 (c)。因为联合索引在B树中先按a排序a相同再按b排序b相同再按c排序所以跳过a直接查b或者c无法利用索引的有序性。这个结论不仅笔试常考实际业务中建索引更是天天用。5.2 explain执行计划与慢SQL分析一道很有代表性的题目是给出一条慢SQL让你分析原因并优化。这种题考察的就是explain执行计划的解读能力。需要关注的关键字段包括type至少达到range最好达到ref或constall全表扫描是要优化的信号。key实际使用的索引。rows预估扫描行数数值越大风险越高。Extra出现Using filesort或Using temporary通常意味着需要优化。有赞的支付或订单场景里常见慢SQL类型有分页深翻页limit 100000, 10导致扫描大量行优化方案是延迟关联或基于游标的分页order by字段没有索引导致文件排序join时关联字段没建索引导致驱动表全表扫描。5.3 事务隔离级别与MVCC事务隔离级别是必考内容脏读、不可重复读、幻读三种问题要和四种隔离级别对应起来。InnoDB默认的隔离级别是REPEATABLE READ它通过MVCC解决了不可重复读问题并通过间隙锁Gap Lock一定程度上解决了幻读问题。B卷在这个知识点上可能会问MVCC是如何通过隐藏字段DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID和undo log实现快照读的READ COMMITTED和REPEATABLE READ在生成ReadView的时机上有什么不同前者是每次select都生成新的ReadView后者是事务内第一次select生成ReadView后一直复用。这个区别解释了为什么REPEATABLE READ能保证同一事务内多次读取结果一致。6. 计算机网络与操作系统校招笔试的隐性失分区6.1 TCP三次握手四次挥手进阶考点全梳理网络基础部分的题集中在TCP/IP协议上。三次握手和四次挥手几乎是必背题但B卷更可能考进阶细节为什么需要三次握手而不是两次因为要防止旧的重复连接请求突然到达服务器导致错误连接。SYN泛洪攻击的原理是什么服务器收到SYN后进入SYN_RECV状态大量半连接占满半连接队列导致正常请求无法处理。四次挥手中的TIME_WAIT状态也是高频考点。主动关闭方在收到对方的FIN后发送ACK然后进入TIME_WAIT状态等待2MSL最大报文段生存时间后才关闭。为什么需要2MSL一是保证最后一个ACK能到达对端如果丢失了对端会重发FIN二是让本连接的所有旧报文段在网络中消失避免影响新连接。6.2 HTTP与HTTPS、HTTP状态码语义HTTP部分B卷可能涉及GET和POST的区别、状态码语义、HTTPS的握手过程。状态码里容易混淆的是301和302——301是永久重定向302是临时重定向。有赞这种电商公司活动页经常需要跳转301和302用错会导致SEO问题和链接失效所以这个知识点实际价值很高。HTTPS握手过程如果要展开讲涉及TLS握手客户端发送支持的加密套件列表服务器选择加密套件并返回证书客户端验证证书合法性双方通过非对称加密协商出对称密钥之后用对称加密传输数据。这里常被问到的一个细节是为什么HTTPS要用非对称加密来协商对称密钥而不是直接用非对称加密传输数据因为非对称加密虽然安全但性能差对称加密性能好但密钥分发有安全隐患所以取两者之长。6.3 进程与线程、进程间通信方式操作系统部分的题量通常不大但进程和线程的区别、进程间通信方式这两个考点命中率非常高。进程间通信方式有管道、消息队列、共享内存、信号量、套接字其中共享内存是最快的IPC方式但需要同步机制配合。线程和进程的区别B卷可能以选择题形式考察进程是资源分配的最小单位线程是CPU调度的最小单位同一进程中的线程共享内存空间而进程之间的内存空间相互独立线程创建和切换的开销比进程小。为了帮助记忆可以类比为进程是一个公司线程是公司里的员工公司之间资源独立员工共享公司的办公室和设备。7. 这套卷子的备考复盘与实战通关策略7.1 按考点重要性分配复习优先级结合B卷的考察分布我给准备校招的同学一个复习优先级参考优先级考点板块原因第一梯队HashMap、线程池、JVM内存、SQL索引出现频率高和电商业务强相关第二梯队排序算法、链表、动态规划、TCP/IP算法题必考网络题容易丢分第三梯队设计模式、Linux基础、Redis、Spring可能涉及但比重较小不建议均匀用力。时间有限时把第一梯队吃透的性价比远高于把第三梯队每样略知一二。7.2 刷题正确姿势由背到推有赞这套B卷给了我一个很深的感触笔试准备不能停留在背题层面。最典型的就是HashMap——如果你只是背下来数组链表红黑树但没推演过树化条件、扩容流程、并发问题换一个出题角度就废了。我推荐的复习法是源码推导法:每学一个知识点强制自己回答三个为什么。为什么HashMap链表长度超过8才树化为什么ConcurrentHashMap的size()方法和HashMap不同为什么快排的平均复杂度是nlogn但最坏是n平方这些问题都能回答清楚才算真正掌握。7.3 机考现场的时间分配与答题策略笔试机考的时间分配很关键。以B卷的题量来看我建议先快速浏览全卷把选择题和判断题先过一遍这类题耗时短、拿分快算法题留足时间至少40分钟以上遇到不会的题标记好先跳过不要在一道题上耗十分钟。一个容易被忽略的策略是手写代码题即使不能完整通过所有测试用例也要把思路和部分代码写出来。判卷时经常能看到逻辑方向正确但实现有小bug的答案这种通常能拿到一半以上的分但空白卷一定是零分。机考环境下不要追求完美解法。先把暴力解写出来保证得分再考虑优化。很多人死在想不出最优解就不写的心态上这是最亏的。7.4 笔试之后如何把卷子内容转化为面试谈资B卷的题目其实可以转化为面试阶段的展示素材。比如如果你在笔试里的线程池题目答得不错面试时就可以主动聊我们项目里某个接口用了线程池参数是怎么设置的为什么这么设置。笔试考的是知识储备面试考的是知识应用两者打通能形成完整的候选人形象。我见过不少候选人笔试成绩很好但面试时讲不出自己项目的技术细节这很可惜。建议笔试结束后把笔试中涉及的知识点和自己做过的项目做一次对照整理出项目里哪里用到了这个知识点的记录面试时随时能拿出来讲。