5 年 Java 经验,字节、美团
这个题不是很好理解,举个例子:线程池核心线程数是 5,当前工作线程数为 6(6>5,意味着当前可以触发线程回收),如果此时有 3 个线程同时超时没有获取到任务,这 3 个线程会都被回收销毁吗。
也是非常刁钻的一题,非常细节。但是即使我们记不得源码的细节了,还是有办法去推敲出来的。
思路:这道题的核心点在于有多个线程同时超时获取不到任务。正常情况下,此时会触发线程回收的流程。
但是我们知道,正常不设置 allowCoreThreadTimeOut 变量时,线程池即使没有任务处理,也会保持核心线程数的线程。
如果这边 3 个线程被全部回收,那此时线程数就变成了 3 个,不符合核心线程数 5 个,所以这边我们可以首先得出答案:不会被全部回收。这个时候面试官肯定会问为什么?
根据答案不难推测,为了防止本题的这种并发回收问题的出现,线程回收的流程必然会有并发控制。
what?又是并发控制,那不是又可以用到上面刚讲的“小技巧”?没错,源码中确实又是使用 CAS 来进行并发控制,从而保证在本例中只会有一个线程成功被回收。
本例相关源码在:getT****ask()?方法中。
多个 AOP 的顺序怎么定
通过 Ordered 和 PriorityOrdered 接口进行排序。
思路:这个问题其实我也也没准备过,但是我知道在 Spring 中有专门定义了 Ordered 和 PriorityOrdered 接口来实现排序功能,例如:对 BeanFactoryPostProcessor 的排序就是使用的这两个接口,所以这边我是直接猜测的用的这两个接口,结果还真是,所以说平时多积累还是挺重要的。
Object 的 wait()方法为什么需要先获取锁
这个问题说难也难,说简单也简单。
说简单是因为,大家应该都记得有道题目:“sleep 和 wait 的区别”,答案中有一项就是:“wait 会释放对象锁,sleep 不会”,既然要释放锁,那必然要先获取锁。
说难是因为如果没有联想到这个题目并且没有了解 wait() 的底层原理,可能就完全没头绪了。
在 JVM 源码中,wait() 的底层逻辑会释放当前占有的锁,在释放前会进行锁的检查,如果当前线程没有持有锁,则会直接抛出 IllegalMonitorStateException。
synchronize 底层维护了几个列表存放被阻塞的线程
这题是紧接着上一题的,很明显面试官想看看我是不是真的对 synchronize 底层原理有所了解。
synchronize 底层使用了 3 个双向链表来存放被阻塞的线程,3 个双向链表分别是:_cxq(Contention queue)、_EntryList(EntryList)、_WaitSet(WaitSet)。
当线程获取锁失败进入阻塞后,首先会被加入到?_cxq 链表,_cxq 链表的节点会被进一步转移到?_EntryList 链表。
当持有锁的线程释放锁后,_EntryList 链表头结点的线程会被唤醒,该线程称为 OnDeck 线程,然后该线程会尝试抢占锁。
而当我们调用 wait() 时,线程会被放入?_WaitSet,直到调用了 notify()/notifyAll()?后,线程才被重新放入?_cxq 或?_EntryList,默认放入?_cxq 链表头部。
****真题:算法题、手写代码
===================
****单链表反转、****合并两个有序链表、********版本号比较
送分题,出这种题说明你前面面的不错,笔试题只是走个过场,力扣原题:21、165、206。
多线程按顺序输出 ABC 若干次
思路:考察多线程基础,Semaphore、Lock + Condition、synchronize 都有解法。
单例模式
手写单例模式,加上以前几次的面试,我有印象的至少有两个大厂问过了,还是挺重要的。通常有五种:懒汉、饿汉、双重检测、静态内部类、枚举,参考之前的文章:《[单例模式详解](()》
手写阻塞队列
参考 ArrayBlockingQueue,实现 put 和 take 方法即可。
手写 HashMap
JDK 1.8 的版本有点太复杂了,可以写 JDK 1.7 的版本,使用链表 + 数组实现,实现 get 和 put 方法即可。
输出一个二叉树的宽度
思路:二叉树的层序遍历(力扣 102)的简单变形,记录下每层的节点个数,取最大值即可。
阿拉伯数字转汉字
例如:输入 123.123,输出一百二十三点一二三。
思路:将“零一二三四五六七八九”、“十百千万亿”这些结果用到的字符存到数组,然后将阿拉伯数字转字符串,遍历拼接结果。
我当时的思路是将整数部分和小数部分分开处理,小数部分比较容易,主要是整数部分比较难 《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 处理,整数部分我当时第一想法是从低位往高位遍历,然后按每一位拼接,例如 123,则拼出:三、二十、一百,最终组成:一百二十三。
这题思路不难想,方法应该有很多种,但是要能通过测试用例还是挺难的,很多细节需要处理,需要反复调试。
有序列表,找出所有两数之和为 10000 的组合
思路:可以用 HashMap 来存遍历过的数字,每次遍历时检查下 HashMap 里是否有目标数字,时间复杂度 O(n),空间复杂度为 O(n)。
如果面试官要求空间复杂度更优的解法,则可以用双指针,从列表的两边向中间扫,和小于 10000,则左指针右移,和大于 10000,则右指针左移,双指针理论上没有使用额外的空间。
单链表奇数节点移动到最前面
输入:a1->a2->a3->a4->a5
输出:a1->a3->a5->a2->a4
思路:也是硬写,不过这题还是有点规律的,只移动奇数节点,相当于移动一个,跳过一个,移动一个,跳过一个。
字符串的全排列
输入:s = "abc"
输出:["abc","acb","bac","bca","cab","cba"]
思路:回溯法,按顺序固定每一位,同时排除同一位出现重复的情况,剑指 Offer 38 题。
最长上升子序列
输入: [10,9,2,5,3,7,101,18]
输出: 4 ,最长的上升子序列是?[2,3,7,101],它的长度是?4。
思路:动态规划,力扣 300 题。
****真题:项目、架构、管理
===================
项目介绍
必问的题目,项目介绍主要有两个重点:
1、要让面试官知道你在做什么。可以从项目的背景开始,为什么要做这个项目,按项目的演进过程、分阶段介绍。
2、突出项目的亮点和关键技术。面试官毕竟只是在听一个他没接触过的项目,所以他会更容易去抓取候选人介绍中的一些感兴趣的“关键词语”来提问,例如:从 0 到 1、技术选型、性能优化、表达式引擎、规则引擎、平台化、技术重构、架构升级等等。
当然,你如果提到这些词,就要做好被追问的准备。
技术选型
技术选型主要比较几个维度:性能、稳定性、接入成本、社区活跃度、业务扩展性、业务特点等等,没有所谓最好的框架/工具,只有最合适自己的。
这边拿表达式引擎来作为例子:
我自己选用的是 Aviator,首先我会介绍 Aviator 的基本特点,然后跟 IKExpression、Groovy 进行对比,重点突出 Aviator 的优点:高性能、轻量级,并且强调 Aviator 已经足够满足业务需求,同时其作者在阿里方便进行交流等等。
做过最牛逼的功能
我经常看到有同学吐槽这个问题,但是这个问题说实话问的频率非常高,所以面试前还是得好好准备一下,争取能让面试官眼前一亮。此时不装逼,更待何时。
我这次讲的是一个性能优化的案例,将一个接口从性能提升了两个量级,不看过程只看结果还是有点吓人的。并且讲完案例后,我通常会继续分享一些自己在性能优化方面的研究和积累。
我们研究和积累的一些方案和技术可能并不适用于自己当前工作的业务场景,但是这些积累可能是很牛逼的,所以这时候你自己要去主动分享出来,让面试官看到你的亮点。
DDD(领域驱动设计)
这个东西最近挺火的,老板们也对这个感兴趣,因为看起来挺高大上的,并且自己也在简历里面写了,所以经常被问,印象中应该是这次面试被问的最多的。
DDD 不是一套框架,而是一种架构思想,所以每个人都可以有自己的理解和实践,只要你能讲出你的理解,并且讲出其优点即可。
可以围绕设计思想、核心解决的问题、分层架构、优缺点、项目中的应用去介绍。
平台化
也是老板们比较感兴趣的问题,这个东西就有点涉及到架构方面的知识了。当然,毕竟也 5 年经验了,这方面的东西确实得有一些了解了。
首先,介绍平台化的业务背景,通常是在一个场景下存在不同的业务模式,两者有区分,但是又有很多共性,所以这个时候去进行平台改造。
同时强调,在从业务模式从一个增加到两个的时候,进行平台化改造是性价比最高的,后续有新的模式就可以直接复用了。
平台化的核心思想:抽取公用逻辑,根据业务的差异点提供自定义扩展点,不同业务模式通过自定义扩展点实现自己的差异化逻辑,以达到抽象复用,提升新业务模式的开发效率。
项目管理********经验(PM)
5 年经验通常需要在项目或需求中去承担起一个负责人的角色,所以项目管理也是面试官很喜欢考察的。
总结来说,PM 的相关问题都是围绕以下来展开:如何保障项目的按时交付,遇到突发问题时怎么应对。
PM 常见的职责如下:
1)协调各端人员进行需求评审。
2)排期:协调好各端进行排期评估,预留各端人员时间资源,做好总体排期、里程碑设定。
3)约定项目沟通机制:根据项目判断是否需要统一项目室开发、各端之间如何同步进展及问题,如遇项目风险,及时向 PM 反馈,PM 可联合讨论,确定最终方案。
4)把控项目进度:及时了解各端的进度,及时了解项目风险(进度缓慢、人员请假等),及时与产品和业务沟通协调,及时作出风险应对。
5)需求变更控制:项目立项后,所有的需求变更,不得在原需求文档上进行修改。如需修改,需要与 PM 沟通确认。需求统一交给 PM,由 PM 沟通后邮件通知项目组成员。
6)质量控制:接口提供者,在项目联调前需要保证主体功能 OK;各端在联调前做好自测;QA 测试时保证环境稳定,不要随意部署。
7)同时作为后端负责人:进行详细的需求分析和拆解,安排好后端人员的开发,做好 codereview、方案设计。
8)项目结束后及时进行总结,观察项目目标达成情况,及时进行复盘。
稳定性保障
关于稳定性保障的回答思路可以从“事前预防预警”、“事中快速止损”、“事后复盘总结”去展开。
评论