格力后端笔试题复盘:Java集合、并发编程与MySQL核心考点解析

发布时间:2026/8/31 14:07:54
格力后端笔试题复盘:Java集合、并发编程与MySQL核心考点解析 1. 这套后端笔试题到底在考什么题型分布与出题逻辑没想到2020年的秋招题目到现在还有人在翻出来看。我后来复盘了一下格力的后端笔试题在制造业大厂里属于比较有代表性的那一类不搞算法竞赛那一套也不考什么前沿框架重点扎扎实实落在Java基础、数据库、Spring、以及最基础的并发和系统设计上。对于目标明确、想进传统制造企业数字化部门的人来说这套题的参考价值其实比很多互联网大厂的偏题怪题要高得多。1.1 一张试卷背后的岗位画像先看格力后端岗的定位。格力是制造业巨头它的后端系统面向的是经销商体系、供应链、生产制造系统、售后服务平台这些业务。这类系统的特点是并发量没有双十一那么夸张但业务逻辑复杂、系统稳定性要求高、数据准确性要求极高。所以笔试不会考“设计一个支撑千万QPS的秒杀系统”而是更关注你有没有扎实的编码功底、能不能理解事务和锁的底层原理、能不能写清楚一条SQL的索引命中情况。我当时拿到试卷的第一感觉是这份题出得很“正统”。选择题占大头然后是简答题和手写代码题最后还有一道综合设计题。没有脑筋急转弯式的智力题也没有需要背冷门API的偏题。如果你把JavaGuide和常见的Java面试题集刷过两遍大部分题目都能找到熟悉的影子但想拿高分光背不行得真理解。1.2 题型分布与时间分配策略我把考卷结构做了个整理大家可以对号入座看看重点在哪题型题量分值占比考察重点单选题20道左右约30%Java基础语法、集合框架、JVM基础、网络协议多选题10道左右约20%并发编程、Spring原理、MySQL隔离级别简答题4-5道约20%HashMap原理、线程池参数、索引失效场景手写代码题2道约15%单例模式、数据结构算法链表/排序综合设计题1道约15%系统设计、数据库表设计、接口设计这里有个很关键的点多选和简答加起来占了40%的分值比手写代码还重要。很多人的误区是把时间全砸在代码题上结果前面的简答随便写两行就交了这是最亏的。我当时的策略是选择题控制在25分钟内多选和简答用30分钟认真答代码题15分钟最后留20分钟给设计题。时间紧但每道题都拿到了该拿的分。提示不要因为选择题简单就掉以轻心。制造业企业的笔试分数是机器筛选和人工复核双重机制高分不仅取决于你做对了多少还取决于你在简答题里展示出的逻辑完整度。2. 核心技术点逐个击破Java基础与并发编程后端笔试的重头戏永远是Java。格力的题目对Java基础考得相当细细到什么程度它不问你“ArrayList和LinkedList有什么区别”这种烂大街的问题而是会抽一个具体的方法源码问你它的实现逻辑。所以复习的时候如果只停留在“知道区别”这个层面是远远不够的得回到源码层面去理解它为什么这么设计。2.1 Java语法与集合从源码层面理解我印象很深的一道选择题是HashMap在JDK 8中当链表长度超过多少时转为红黑树答案是8还有一个条件是数组长度大于等于64。这个题本身不难但它后面跟了一道多选题——为什么是8而不是16或4这就考到泊松分布了源码注释里写了负载因子0.75的情况下链表长度达到8的概率已经极低约千万分之六转红黑树的目的是为了防止极端哈希冲突下的性能退化。这里我建议大家复习的时候把HashMap的下面几个知识点串成一条线底层结构数组链表红黑树为什么引入红黑树而不是平衡二叉树红黑树插入删除效率更稳定负载因子为什么默认0.75不选0.5或1空间和时间的一个折中这个值是大量实验统计出来的经验值扩容机制为什么扩容是2次幂怎么用位运算替代取模来定位桶位置JDK 7到JDK 8的改进头插法改尾插法解决死循环问题、红黑树引入解决退化问题集合这一块还有一种考法是从线程安全角度切入。比如问你CopyOnWriteArrayList适合什么场景很多人的第一反应是“线程安全的List”但这样回答基本拿不到分。要点是它“读多写少”的适用场景、写时复制导致的内存占用问题、弱一致性的迭代器。笔试不会直接问你“它的缺点是什么”但会给你一个场景让你判断适不适合用这才是真正考理解力。2.2 并发编程从八股到场景判断格力的并发题考得比较实在。有一道简答题是解释一下synchronized和ReentrantLock的区别。这个题目看起来常规但想拿高分我建议按这几个维度展开而不是简单列三条实现层面synchronized是JVM层面的锁ReentrantLock是JDK层面的API基于AQS可中断性synchronized不能响应中断ReentrantLock可以lockInterruptibly方法非阻塞获取锁ReentrantLock可以tryLock尝试获取synchronized不行公平性synchronized非公平ReentrantLock可以设置为公平锁条件变量ReentrantLock可以绑定多个Condition实现精确唤醒synchronized只有wait/notify锁升级synchronized有偏向锁、轻量级锁、重量级锁的升级过程ReentrantLock直接是CAS自旋这里有个容易丢分的细节很多人在回答时把“CAS自旋次数”“Adaptive Spinning”这些机制讲得很深但忽略了最基础的“为什么需要锁”而直接谈锁的实现。我建议大家无论简答题怎么问都要先点出多线程环境下的原子性、可见性、有序性问题再转到锁机制这样阅卷人能立刻看出你是真懂还是在背面试题。再看线程池。有一道多选题说以下哪些参数是ThreadPoolExecutor构造方法的必填参数这个题的迷惑项是keepAliveTime和handler因为它们在构造时有默认值。核心线程数、最大线程数、工作队列这三个是必填的这个必须记牢。后面还会跟着一道追问当任务提交速度超过线程池处理速度时任务会先进入队列还是先创建新线程这题的答案是先创建线程直到核心线程数满再入队队列满后再创建线程直到最大线程数最后触发拒绝策略。很多人把这个顺序搞反了以为核心线程满了就直接入队。实际执行顺序是corePoolSize - BlockingQueue - maximumPoolSize - RejectedExecutionHandler前两步没问题关键在第三步——是先入队再扩线程而不是先扩线程再入队。这个顺序直接影响系统在突发流量下的表现值得多花时间想清楚。2.3 代码题手写单例与快排的得分细节格力那年的手写代码题中有一道是手写线程安全的单例模式。这个题目看起来简单但拿满分不容易。我当时写的是DCL双重检查锁版本写完之后在旁边注明了volatile的两个作用保证可见性和禁止指令重排序。这一步很关键因为如果只是写代码很多面试官会认为你背了模板但你把“为什么加volatile”写清楚就能体现你真正理解了指令重排问题。public class Singleton { // volatile防止指令重排序保证instance初始化完成后再对其他线程可见 private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance null) { // 第一次检查避免不必要的加锁开销 synchronized (Singleton.class) { if (instance null) { // 第二次检查保证只有一个实例 instance new Singleton(); } } } return instance; } }单例模式的两种推荐写法要记住DCL和静态内部类。静态内部类的实现更简洁由JVM类加载机制保证线程安全适合在笔试时快速写出无bug版本。饿汉式虽然最简单但会在类加载时就初始化造成资源浪费而且无法支持延迟加载的需求。枚举方式也能保证线程安全但在实际企业项目里用得少笔试时不推荐写容易被认为对Java企业开发场景不熟悉。另一道代码题是关于链表反转的整体难度不大但有一个常见的坑用递归实现时忽略了链表长度为0或1的边界情况直接导致空指针异常。用迭代法写会更稳一个pre指针、一个cur指针、一个next临时变量循环走完就完成了边界条件只要加上head null || head.next null的判断就能满分。3. 框架与数据库Spring、MySQL、Redis的实战考察范围框架和数据库这块是拿分的大头但也是最容易“背了答案也答不对题”的部分。格力的题目偏重应用理解和原理机制的结合它不会让你默写Spring Bean的生命周期但会给你一个场景让你判断某个Bean会被实例化几次或者给你一条SQL让你分析它有没有走索引。这类题目最能拉开差距。3.1 Spring核心机制IoC和AOP的底层逻辑Spring相关的选择题里有一道关于依赖注入方式的题构造器注入和setter注入分别适用于什么场景。这个问题的核心不在“哪个更好”而在于怎么区分。构造器注入适合强依赖、不可变对象的场景可以保证Bean在初始化完成后就处于一个完整可用的状态避免部分注入的问题setter注入适合可选依赖、需要运行时替换实现的场景但容易产生初始化不完整的问题。追问部分考的是Spring IoC容器创建Bean的默认初始化方法是什么这个要答到PostConstruct注解、InitializingBean接口的afterPropertiesSet()方法、自定义的init-method三者的执行顺序。顺序是构造方法 -PostConstruct-afterPropertiesSet()-init-method。这个顺序在源码里非常清晰但很多人在笔试时会把PostConstruct和init-method搞混。一个简单的记忆方式注解方式是JDK提供的标准能力javax.annotation会在Bean属性设置完成后、Spring完全接管之前执行init-method是Spring容器调用的所以排在最后。再来看AOP。有一道题问的是Spring AOP默认使用JDK动态代理还是CGLIB答案是当目标类实现了接口时默认用JDK动态代理没有实现接口时才用CGLIB。但这道题的坑在于Spring Boot 2.x之后默认配置是spring.aop.proxy-target-classtrue也就是说Spring Boot项目里默认走CGLIB代理。这个变化很多还在看老教程的人完全不知道一写就错。答题时如果能把这个版本差异补充上去阅卷人会觉得你平时关注到了框架演进加分是必然的。3.2 MySQL索引、事务、SQL优化的拿分要点MySQL部分的题量很大而且几乎每个知识点都会延伸出一个场景题。有一道这样的SQL优化题SELECT * FROM order_table WHERE order_status 1 ORDER BY create_time DESC LIMIT 100;如果order_status的区分度很低比如只有0和1两个值那么在order_status上建索引有意义吗这道题的答案是单独建在order_status上的索引作用非常有限。因为区分度太低优化器会认为走索引和全表扫描的代价差不多最后可能还是全表扫描。正确的做法是把(order_status, create_time)建成联合索引既能过滤状态又能利用索引排序避免filesort。这里涉及到一个很重要的细节联合索引的最左前缀原则以及ORDER BY对索引的使用。如果查询条件是WHERE order_status 1 ORDER BY create_time联合索引(order_status, create_time)就是完美匹配既过滤又排序。但如果把顺序反过来建成(create_time, order_status)那排序确实能用到索引但WHERE过滤用不上整体效率反而不如前面那个组合。这提醒我们联合索引的字段顺序是笔试的核心考点千万别只看“有没有索引”而忽略了顺序。事务隔离级别的题目也是必考的。MySQL默认的隔离级别是REPEATABLE READ可重复读但在可重复读级别下INSERT ... ON DUPLICATE KEY UPDATE这种写法会遇到间隙锁Gap Lock的问题。有一道简答题就问在可重复读级别下如何避免幻读答案包括MVCC解决快照读的幻读SELECT ... FOR UPDATE或SELECT ... IN SHARE MODE解决当前读的幻读加Next-Key Lock。如果你能在这里展开说说MVCC的原理undo log版本链 ReadView的生成时机这道简答基本就握手了。3.3 Redis缓存穿透、击穿、雪崩和场景设计题Redis这块格力考了缓存三大问题——穿透、击穿、雪崩但提问形式变成了场景设计而不是名词解释。比如有一道题一个热点新闻的详情接口缓存过期的一瞬间大量请求同时打到数据库如何解决这题考的就是缓存击穿标准答案包含两层互斥锁在缓存失效时只允许一个线程去重建缓存其他线程等待和逻辑过期把过期时间写在value里取到之后判断是否过期过期则异步更新缓存。第二层的逻辑过期方案在实际项目里用得更多因为互斥锁在高并发下会导致大量线程阻塞等待而逻辑过期能做到“更新数据的请求异步执行老数据先返回”体验上更平滑。如果你在笔试中能把这两个方案的利弊对比写出来说清楚什么场景用哪个这题的分数比单写“布隆过滤器”要高。穿透和雪崩也要会区分。穿透是查询一个不存在的key请求直接打到数据库。解决方案除了布隆过滤器还有一个更简单的思路把空值也缓存起来但TTL设置得短一些比如60秒内同一个不存在key的重复请求直接命中Redis返回null。雪崩是大批key同时过期或Redis宕机解决方案包括过期时间加随机数、多级缓存、限流降级。笔试时我建议大家不要只写方案名要写“具体怎么落地”比如“缓存的TTL设置为业务过期时间加上随机值例如3600 random(0,600)秒”这样才有实操感。4. 综合设计题的答题框架从需求分析到方案落地最后一类题是综合设计题这也是一张试卷里分值最大、最考验综合能力的一道题。格力的设计题通常围绕一个具体的业务场景展开比如“设计一个经销商订单查询系统”或“设计一个积分发放与消费系统”。这类题目没有标准答案但阅卷人心里有一把明确的评分尺重点看你的思路是否完整、方案是否能落地。4.1 一道典型系统设计题的完整拆解我把当年的题复述一下设计一个经销商订单管理系统要求支持订单创建、订单查询、订单状态流转考虑到经销商数量大、月末查询量集中需要设计合理的表结构和接口方案。拿到这种题不要上来就画表。我习惯分四步回答第一步明确需求边界。先写清楚系统有哪些角色经销商、内部运营、财务有哪些核心流程下单、审核、发货、对账以及非功能需求日均订单量、峰值查询量、数据保留周期。笔试时不需要真实数据但要给出合理的假设比如“假设有5000个经销商每天产生10万笔订单月末查询峰值可能翻3倍”。第二步设计核心表结构。订单主表、订单明细表是必须的可以考虑分库分表方案按经销商ID取模分表但笔试卷上写清楚分表键就行不要求完整设计方案。订单状态流转可以用单独的order_status_log表记录方便审计追溯。第三步接口设计。核心接口包括创建订单、查询订单详情、批量查询订单列表、订单状态回调。我要特别提醒一个坑查询接口一定要做分页和条件组合(经销商ID 下单时间范围 状态)这个组合要给联合索引。如果答案里没有把分页参数设计进去这个接口在月末查询高峰必挂。第四步方案取舍。最后一个部分非常重要。一定写清楚“我的方案在什么场景下存在问题”比如“如果订单量再涨10倍单表会到亿级就需要按经销商维度分库分表或者引入ES做订单维度搜索”。这部分能体现你的设计不是背书而是真正经历过容量规划。4.2 高并发下数据一致性的答题思路综合设计题还有一个常考变形在积分发放/库存扣减这类写多读少的场景下如何保证数据一致性。有几套方案我按推荐程度排个序数据库乐观锁用version字段做CASUPDATE ... SET version version 1 WHERE id ? AND version ?。适合并发冲突不激烈的场景。Redis分布式锁用SET key value NX EX 3实现最简分布式锁适合需要严格互斥的场景但要考虑锁超时和业务超时长于锁过期的安全问题。消息队列异步化把写操作发到MQ消费者串行处理牺牲部分实时性换取一致性。适合对实时性要求不高的场景。答题时我建议把“为什么不选另外两种”也写出来。比如你选了乐观锁就顺手提一句为什么不用分布式锁——因为积分变更频率并不高分布式锁加锁解锁的网络开销提升不了多少性能反而会增加系统复杂度。这个对比过程比堆方案名更能拿分。还有一种是事务消息方案适合“先写业务表再发消息”的场景可以解决本地事务和消息发送的一致性问题这个如果能在答题中自然带出显得经验更足。5. 笔试实战技巧与常见失分点清单写到这里想必你也发现了这套笔试题的知识点其实没有超出常规后端面试的范围但失分点非常多。我结合自己当年和一些学弟学妹的反馈把最容易踩的坑统一整理出来尽量让大家少走弯路。5.1 时间分配与作答顺序策略时间分配是笔试中最容易翻车的一环。很多人习惯从第一题做到最后一题结果遇到一道多选题卡了五分钟代码题反而没时间写了。我更推荐这样的顺序第一步用3分钟把整张试卷扫一遍。不看选择题的具体选项只看简答题和代码题是什么这样心里有数知道哪道题是大头。第二步先做简答题。简答题分值高且很多内容刚看到题目时记忆最清晰越到后面越容易大脑空白。先把能拿的分数拿住。第三步再做代码题。因为代码题往往需要草稿纸推演在头脑最清醒的时候写不容易出低级bug。第四步做选择题。选择题是最快的拿分项放到最后剩多少时间都来得及。多选题如果拿不准宁少选不多选很多企业采用少选得部分分的规则。5.2 高频失分点速查表失分点具体表现正确做法HashMap初始容量不知道默认容量是16写成10或8记住16负载因子0.75扩容阈值12线程池拒绝策略把AbortPolicy和CallerRunsPolicy混为一谈AbortPolicy是直接抛异常CallerRunsPolicy是让提交任务的线程自己执行索引失效条件只记得“对索引列使用函数导致失效”不知道联合索引中间跳过列也失效最左前缀原则要理解WHERE a 1 AND c 2b没条件时c的索引用不上Spring事务传播行为只知道REQUIRED不知道REQUIRES_NEW会挂起当前事务REQUIRES_NEW是开启一个新事务并挂起当前事务内层异常不会回滚外层缓存一致性只说“先删缓存再更新DB”不解释为什么推荐先更新DB再删缓存删缓存失败用MQ补偿或延迟双删Redis持久化把RDB和AOF的使用场景搞反RDB适合对恢复速度要求高的场景有丢失风险AOF适合数据安全要求高的场景代码题边界条件链表为空、数组空、字符串为null的情况没考虑凡是手写代码先写边界判断稳定拿基础分时间复杂度假装看懂看到“O(n)”就不细想没考虑最坏情况排序、查找算法最坏情况、平均情况都要会分析尤其是快排退化到O(n²)的原因和条件5.3 代码题手写注意事项代码题交卷前一定要花30秒做三件事第一看边界条件。链表题checkhead null || head.next null数组题checkarr null || arr.length 0字符串题checks null || s.length() 0。第二看方法签名。返回类型是void还是具体类型方法名有没有拼错。笔试中的机器判题对方法名和参数列表大小写极其敏感一个小写字母错了整道题零分。第三看变量命名。笔试阅卷通常是人工看如果变量名是a、b、c这种无意义命名阅卷人会觉得你代码习惯不好。写cur、pre、slow、fast这种有语义的名字哪怕逻辑有瑕疵观感分也高。我还有一个自己的习惯代码写完之后在旁边用一行注释总结思路。比如链表反转写“// 迭代法pre指向已反转部分的头节点cur指向待反转节点”。这样做的好处是如果代码有bug但思路正确阅卷人可能会给过程分如果什么都不写直接交一个编译不过的代码就只能拿鸭蛋了。这个过程分在校招笔试里非常关键千万别忽视。最后再分享一点个人经验回过头来看格力的这套笔试题考的不是你的技术广度而是技术深度和思维方式。它默认你掌握了Java后端的主要技术栈然后通过这些看似基础的题目筛出那些真正理解底层原理、能独立分析问题的人。我还想强调一个容易被忽视的点笔试只是校招全流程中的一环它的核心目标不是拿满分而是让自己进入下一轮面试。所以遇到不会的题不要慌先把会做的做完再回来啃硬骨头。我在笔试时就有一道多选题完全拿不准最后少选了两个选项出来对答案发现少选给了一半分这个策略帮我稳住了分数。如果你正在准备制造业或传统企业的后端校招我建议你复习时把重心放在这五个方向Java集合源码、并发编程线程池/锁、Spring核心机制、MySQL索引与事务、Redis常见场景设计。把这五块内容吃透格力的题可以拿下大部分同类企业的笔试也大概率能过。这套题让我在那年秋招里拿到了好几个制造业大厂的面试机会希望这篇复盘也能帮到你。

相关新闻