
这套卷子虽然叫“映客2020春招研发B卷”但放在今天看它依然是直播赛道后端、客户端岗位笔试的一份很典型的样例。直播业务的特点是高并发、低延迟、强互动所以笔试题目会明显偏向Java基础、并发编程、网络原理、数据结构与算法再加上一道系统设计题来考察你对直播场景的理解。很多同学刷题只看算法忽略了基础题和设计题结果反而在这类卷子上栽跟头。这篇文章我就结合这套B卷的常见题型把每一类题背后的考察意图、解题思路和复习方法完整拆一遍尤其适合正在准备直播、社交、音视频类公司研发岗笔试的同学。1. 整套卷子想考察什么1.1 从直播业务反推考察重点我在复盘这套B卷之前先做了一个反向推导映客是直播平台直播场景下研发团队每天要面对什么问题答案无非是三个方向海量用户同时在线、消息实时分发、极端流量下的稳定性。这三个方向直接决定了笔试题的选型。海量用户在线意味着集合类、内存模型、缓存设计要熟练消息实时分发意味着网络协议、IO模型、并发编程要扎实极端流量下的稳定性意味着算法复杂度、限流降级、系统设计要有全局观。所以这套B卷里Java集合、线程池、TCP/IP、算法题和一道直播场景设计题几乎是必出组合。这不是映客独有的偏好而是整个直播行业研发笔试的共同倾向。搞清楚这一点你就明白为什么复习不能只闷头刷LeetCode。1.2 题型构成与时间分配2020年春招的研发B卷整体结构分为几个模块。客观题主要覆盖Java基础、操作系统、网络原理题量大概在20到30道之间每道题分值不大但覆盖面广。编程题一般是两到三道难度从LeetCode中等题到偏难的动态规划或设计类问题不等。最后还有一道系统设计题主观性很强考察的是你面对开放性问题时的分析框架。时间分配上我建议客观题控制在40分钟内编程题每道题20分钟左右系统设计题留出至少30分钟。很多同学在编程题上死磕一道题导致最后设计题只写了两行字这是笔试的大忌。设计题只要结构完整、逻辑自洽即使方案不完美也能拿基础分而编程题卡住了可以先跳最后再回来补。2. 客观题复盘Java基础与数据结构高频点2.1 HashMap为什么是必考题B卷的客观题里HashMap是出现频率最高的考点没有之一。考察的角度通常有三个底层数据结构、put流程、扩容机制。底层数据结构在JDK 1.8之后是数组加链表加红黑树。数组是主体链表解决哈希冲突当链表长度超过8且数组长度超过64时转为红黑树。这个阈值为什么是8因为理想情况下随机哈希码导致容器中节点分布频率遵循泊松分布链表长度达到8的概率已经极其低所以从时间和空间权衡来看8是一个合理的阈值。面试官问到这一点时你能说出这个概率推理就会比单纯背“8转红黑树”更有说服力。put流程要能完整描述出来先计算key的hash值通过扰动函数让高位也参与运算然后通过(n - 1) hash定位到数组下标如果该位置为空直接放入不为空则遍历链表或红黑树判断key是否存在存在则覆盖value否则插入新节点。插入后检查size是否超过threshold超过则扩容。扩容机制是另一个高频点默认容量16负载因子0.75扩容时容量翻倍元素需要重新计算位置。JDK 1.8的扩容做了个优化元素重新定位时只需要看原hash值新增的bit位是0还是1是0则位置不变是1则原位置加旧容量。这个设计避免了rehash时重新计算hash是JDK 1.8性能提升的一个细节。你在复盘这道题时一定要自己画一遍put和扩容的流程能把流程图在纸上默写出来才算真正掌握而不是只在脑海里有个模糊印象。2.2 线程安全的集合类要分清适用场景B卷还喜欢考察线程安全的集合类常见的有Hashtable、ConcurrentHashMap、Collections.synchronizedMap。这三者的区别是经典题目。Hashtable是线程安全的但它的实现方式是给整个数组加锁也就是所有方法都用synchronized修饰并发度极低现在基本不使用了。ConcurrentHashMap在JDK 1.8之后放弃了分段锁的设计改用CAS加synchronized锁住数组中的每个节点锁粒度变得更细。读操作无锁写操作只锁当前桶因此并发度远高于Hashtable。这里有个容易忽略的点ConcurrentHashMap的size()方法在并发场景下不是精确值它先无锁统计如果两次统计结果一致才返回否则加锁重统计因此它是弱一致性的。Collections.synchronizedMap则是在普通Map外面包了一层同步锁所有方法都被同一个对象锁保护实现简单但并发性能一般。复习这个知识点时不要只背结论要理解每种方案在并发度、一致性、实现复杂度三个维度上的取舍这样即使题目换个问法你也能应对。2.3 字符串、数组与栈队列的基础题陷阱客观题里还有一些送分题但送分题也有陷阱。比如String、StringBuilder、StringBuffer三者的区别很多同学只记得“String不可变StringBuilder线程不安全StringBuffer线程安全”但忽略了底层实现。String底层是final char数组JDK 9之后是byte数组每次拼接都会创建新对象所以循环内大量拼接会频繁GC。StringBuilder的append方法是直接操作内部数组性能好但如果多线程同时调用可能出现数组越界或数据错乱。StringBuffer则在append方法上加synchronized线程安全但性能略低。这种题目的陷阱在于它喜欢让你判断一段代码创建了几个对象。比如String s new String(abc)问创建了几个对象答案是1个或2个字符串常量池中有abc则只创建1个堆对象没有则先在常量池创建1个再在堆中new出1个。这种细节题就是区分“背过”和“真懂”的分水岭。栈和队列的基础题往往结合括号匹配、表达式求值、用两个栈实现队列这类经典问题来考。这些题难度不大但要注意代码的边界处理比如栈溢出、空队列弹出等异常情况。3. 并发与网络直播场景的隐藏考点3.1 线程池参数会背八股更要会计算线程池是B卷并发题的核心。考察点集中在ThreadPoolExecutor的七个参数以及拒绝策略。七个参数是核心线程数、最大线程数、空闲存活时间、时间单位、工作队列、线程工厂、拒绝策略。关键问题是核心线程数和最大线程数怎么设置这是很多同学的死穴。实际生产环境的经验公式是CPU密集型任务线程数设置为CPU核心数加1目的是减少上下文切换让CPU尽量满负荷工作IO密集型任务线程数设置为CPU核心数乘以2因为IO等待期间线程让出CPU需要有更多线程来填补等待间隙。直播场景里的消息推送、弹幕审核这类任务大部分属于IO密集型所以核心线程数往往会设置得比CPU核心数大。你可以记住一个经验值思路核心线程数 CPU核心数 / (1 - 阻塞系数)阻塞系数在IO密集型任务中通常取0.8到0.9。比如8核机器阻塞系数取0.8核心线程数就是40左右。这块还有一个高频考察点是拒绝策略有AbortPolicy直接抛异常、CallerRunsPolicy让调用者线程执行、DiscardPolicy静默丢弃、DiscardOldestPolicy丢弃队列中最老的任务。你要能结合实际场景说明选择理由比如直播弹幕场景如果系统过载弹幕丢几条其实影响不大可以选择DiscardPolicy而礼物赠送这种需要保证消息不丢的场景必须选CallerRunsPolicy或者自己实现拒绝逻辑。3.2 TCP四次挥手结合弹幕系统来记网络部分的经典考点是TCP三次握手和四次挥手尤其喜欢考TIME_WAIT。为什么会有TIME_WAIT因为主动关闭连接的一方要确保对方收到了自己的ACK。如果这个ACK丢失对方会重发FIN主动关闭方必须能再次回应ACK所以要等待2MSL。MSL是报文段最大生存时间2MSL大约是2到4分钟。B卷里这道题经常变着花样考比如问你“大量TIME_WAIT连接是什么原因怎么解决”。这个问题在直播场景里很真实因为客户端频繁断开重连服务端如果充当主动关闭方就会出现大量TIME_WAIT连接占用端口和内存。解决思路有几个方向。一是打开tcp_tw_reuse和tcp_tw_recycle让处于TIME_WAIT的连接可以被复用但tcp_tw_recycle在NAT环境下有坑已经不建议开启。二是调整keepalive时间减少无效连接。三是在应用层做连接复用比如HTTP长连接减少频繁断开。这类题目如果能结合线上真实场景来答面试官会觉得你是有实战经验的而不是只会背书。3.3 IO模型与NIO判断是否理解高并发最后再说IO模型。B卷经常给一段代码问它是BIO、NIO还是AIO或者直接考察阻塞与非阻塞、同步与异步的区别。简单说BIO是同步阻塞一个连接一个线程连接数一多线程数爆炸性能急剧下降NIO是同步非阻塞一个线程可以处理多个连接通过Selector轮询事件就绪状态AIO是异步非阻塞内核完成IO操作后回调通知应用真正解放应用线程。直播平台的网关层、长连接服务底层基本都是NIO模型因为要支撑数十万甚至百万级的同时在线连接。Netty是NIO的封装B卷如果提到了Netty你要能说出它的核心组件EventLoop、ChannelPipeline、ByteBuf以及为什么用NIO而不是BIO来支撑高并发。4. 编程题拆解从读懂题意到最优解4.1 高频题型与解题框架编程题部分B卷一般会出现链表、二叉树、动态规划、字符串处理这几类。我挑几个最常出现的题型给大家梳理一套解题框架。链表类题目常见的有反转链表、合并两个有序链表、链表是否有环、找链表中点。这类题的核心是掌握虚拟头节点和双指针技巧。虚拟头节点可以避免处理头节点的特殊情况双指针则是解决“环”“中点”“倒数第k个”这类问题的利器。二叉树类题目常见的有层序遍历、最近公共祖先、二叉树的最大深度。层序遍历要记住用队列辅助而最近公共祖先的递归解法要分清楚三种情况两节点分别在左右子树、都在左子树、都在右子树。动态规划类题目是区分度的关键。常见的有最大子序和、最长上升子序列、编辑距离、背包问题。解题框架很固定定义状态、写状态转移方程、确定初始化和遍历顺序。最忌讳的就是一上来直接写代码先把状态定义和转移方程写在草稿纸上确认无误再动手。字符串处理类题目常见的有最长无重复字符子串、字符串全排列、正则表达式匹配。这类题要特别关注边界条件空字符串、只有一个字符、全部相同字符等。举个例子最长无重复字符子串这道题最优解是滑动窗口加哈希表时间复杂度O(n)。我见过很多同学第一次写的是暴力解两层循环枚举所有子串时间复杂度O(n^2)在笔试中大概率会超时。正确思路是维护一个左指针和一个右指针右指针不断向右扩展当遇到重复字符时将左指针跳到该字符上次出现位置的下一个位置过程中记录最大长度。4.2 复杂度分析是隐藏加分项编程题不只是写对代码就完事笔试系统通常还会看你代码的运行时间和内存占用。很多同学在本地IDE跑通了一提交却超时原因就是复杂度没控制好。所以在编程题部分每写完一道题都要自己评估一遍时间复杂度和空间复杂度。比如用递归做二叉树遍历时间复杂度O(n)空间复杂度O(h)h是树的高度但如果用递归做斐波那契不优化的话时间复杂度是O(2^n)空间复杂度O(n)在n稍大时完全跑不动。这里有个我踩过的坑以前笔试时写斐波那契直接用递归加备忘录虽然时间复杂度降到了O(n)但空间复杂度还是O(n)。后来看到一个更优的做法用两个变量滚动迭代空间复杂度直接降到O(1)。这种细节笔试系统是会给你加分的因为同样的功能你用更少的内存完成说明你对代码的掌控力更强。5. 系统设计题直播互动场景怎么答才不丢分5.1 从聊天室到直播间先理清需求B卷的最后一道设计题大概率是直播相关的场景比如设计一个直播弹幕系统、设计一个直播间礼物系统。这类题看起来开放其实有固定的答题框架。我先说一下最常见的错误拿到题就开始画架构图写用什么中间件、什么数据库结果连核心需求都没说清楚。系统设计题的第一步永远是确认需求。以弹幕系统为例你要先搞清楚几个关键问题弹幕的延迟要求是多少实时弹幕要求秒级甚至毫秒级到达写入量有多大一个热门直播间可能每秒上万条弹幕读取量有多大直播间观众可能几十万人在线相当于一个热点数据要被大量并发读取。这些问题的答案直接决定技术选型。延迟要求高就要用长连接或WebSocket而不是HTTP轮询写入量大就要引入消息队列做削峰读取量大就要加缓存层避免所有读请求都打到数据库。5.2 架构设计分层的标准答案需求确认后就可以画出分层架构。标准答案是接入层、业务逻辑层、数据层三层。接入层负责维护客户端的长连接。每个直播间是一个Topic或者Channel客户端通过WebSocket或自定义TCP协议连接接入层接入层负责任务分发。业务逻辑层负责处理弹幕的合法性校验、敏感词过滤、消息存储。这个环节要考虑如何保证消息有序比如同一个用户的弹幕不能乱序同一个直播间内的消息整体有序。实践中通常会给消息加自增ID或者用Redis的INCR生成房间内消息序号。数据层负责消息的最终存储。弹幕消息的特点是写多读少而且很少修改所以适合用消息队列加NoSQL存储。消息先进Kafka或RocketMQ削峰再由消费者写入存储层。读取时用户刚进入直播间时只需要读取最近几十条弹幕历史所以可以用Redis的列表结构保存每个直播间最近的N条弹幕。如果题目问的是礼物系统则要额外考虑赠送礼物的高并发扣减、排行榜的实时计算、消息的可靠投递。高并发扣减可以用Redis的原子操作排行榜可以用Redis的有序集合消息投递则要考虑失败重试机制。核心是你要在答题过程中展示出“我能把一个模糊的需求拆解成清晰的技术方案”的能力而不是堆砌中间件名词。5.3 评估与演进在线人数从1万到100万的扩容路径系统设计题如果只画一个静态架构只能拿及格分。想拿高分必须展示演进思维也就是当系统从1万人同时在线增长到100万人时你的架构如何变化。1万人阶段一台服务器加Redis加MySQL就够了。弹幕写入走WebSocket直连写入MySQL读取时查Redis缓存最近消息。10万人阶段一台服务器扛不住了需要引入负载均衡和网关层。WebSocket服务集群化消息通过内部的发布订阅系统分发。同时引入消息队列削峰填谷避免数据库被打垮。100万人阶段就需要对直播间做分区或分片。比如按直播间ID做哈希不同直播间的消息路由到不同的消息节点。这一阶段还要考虑跨区域部署用户接入最近的接入层节点层与层之间通过消息中间件做数据同步。这套演进思路能直观地告诉阅卷人你是否有过真实的大流量系统设计经验。哪怕你没实际做过把这个逻辑讲通也是一个合格的系统设计答案。6. 容易忽略的细节失误复盘与备考建议6.1 笔试中的低级失误清单自己复盘这套卷子时我总结了笔试中最容易丢分的几个低级失误都在这里列出来。第一客观题看错选项。经常有同学在“下列说法不正确的是”这类题目上掉坑明明题干问的是“不正确”结果选了正确项丢分丢得非常冤。第二编程题没有先想清楚边界条件。比如链表题没考虑空链表数组题没考虑长度小于k的情况二叉树题没考虑根节点为空的情况。这些边界条件在笔试系统里往往是隐藏测试用例一测一个失败。第三设计题忽略了非功能需求。很多同学画完架构图就开始写接口完全没有提到高可用、容灾、监控告警。实际上设计题的评分标准中可靠性、扩展性、运维性是重要的评分维度。第四代码风格问题。变量名用a、b、c代替没有缩进看起来就很不专业。笔试系统是机器评阅为主但代码可读性差会影响后续面试官的人工复核。6.2 春招笔试的复习策略和时间安排最后给出一个我个人认为效率比较高的复习思路适合离笔试还有两到四周的同学。第一周主攻客观题。重点过一遍HashMap、ConcurrentHashMap、线程池、JVM内存结构、TCP/UDP、IO模型这些高频考点。不要只刷题要做笔记把每个知识点背后的原理写下来。第二周主攻编程题。按数据类型分类刷题链表、二叉树、字符串、动态规划各刷一定数量。每道题做完后花五分钟写一遍复杂度分析最好再想想有没有其他解法。第三周集中做整套模拟题。网上能找到不少大厂的历年笔试题挑两三套按真实考试时间来做。做的时候严格计时做完之后认真复盘每一道错题。第四周查漏补缺。把前几周的错题翻出来重做重点看自己反复出错的知识点针对性补强。关于背题和刷题的关系我一直觉得刷题的目的是形成条件反射但仅仅背答案是不够的因为笔试题目稍微变个方式你不会原理就做不出来。所以建议每做一道题都要能讲清楚思路而不是只满足于代码提交通过。这套B卷虽然已经是2020年的题目但它考察的知识点和能力模型到今天依然是直播、社交、音视频类公司笔试的核心。把每一类题背后的原理搞懂比刷多少道题都重要。我在实际复习过程中发现真正有用的不是题海战术而是每做完一道题都问自己一句“为什么”把这个习惯坚持下来笔试的通过率会有很明显的提升。