4/5 美团:“轻松”!深入JVM和MySQL,美团优选事业群一面你准备好了吗?
- 作者
- Name
- 青玉白露
- Github
- @white0dew
- Modified on
- Reading time
- 18 分钟
阅读:.. 评论:..
咱们来看一场美团优选事业群后端开发岗位的一面面试经历,面试官人很和善,整个过程既轻松又充实。这场面试不仅考察了基础知识,还涉及到了项目实战和算法。赶紧来看看,这样的面试你能hold住吗?
【提醒】通过这次面试经验,你将可以复习到以下知识点:
- Java集合类的使用及线程安全
- 并发编程的相关类和机制
- Java核心线程池概念和异常处理
- JVM内存结构和GC机制
- Linux命令和文件处理
- MySQL的存储引擎和索引优化
- 分布式系统的理解和实现
- 基础算法题目的解决思路
面试官: 你好,欢迎来到美团的面试。我们首先来聊聊集合类。你能说说ArrayList和LinkedList的区别及适用场景吗?
求职者: 当然可以。ArrayList基于动态数组实现,它支持快速随机访问,但是在中间插入和删除元素时效率相对较低,因为这会导致数组元素的移动。而LinkedList是基于双向链表实现的,适合频繁的插入和删除操作,但它的随机访问效率较低。所以如果我们需要频繁访问列表中的元素,应该使用ArrayList;如果我们需要频繁插入删除元素,应该使用LinkedList。
面试官: 那你知道如何将ArrayList变成线程安全的吗?
求职者: 我们可以使用Collections.synchronizedList方法来将ArrayList包装成线程安全的列表:
List list = Collections.synchronizedList(new ArrayList());
这样得到的list在并发环境下可以安全使用。
面试官: 对,那你听说过CopyOnWriteArrayList吗?它有什么缺点,适合什么样的场景?
求职者: CopyOnWriteArrayList是并发包中一个线程安全的ArrayList实现,它通过在每次修改时复制数组来实现线程安全。这种方式的缺点是写操作的开销很大,因为它需要复制整个数组。因此,CopyOnWriteArrayList适合读多写少的并发场景。
面试官: 很好。接下来我们聊聊HashMap。它线程安全吗?并且它在并发包里对应的线程安全的类是什么?
求职者: HashMap不是线程安全的。在并发包中,对应的线程安全类是ConcurrentHashMap。
面试官: 对。那ConcurrentHashMap是如何保证线程安全的?以及它为什么要将红黑树转化成链表?
求职者: ConcurrentHashMap使用了分段锁的机制,它将数据分为多个段,每个段独立加锁,从而减少锁竞争,提高并发访问效率。当链表中的节点太多时,会转换成红黑树来提高搜索效率,而当节点数量减少到一定程度时,为了减少内存占用和改善迭代性能,会将红黑树转换回链表。
面试官: 那你能说说Java中创建线程的几种方法,以及线程池的核心参数吗?
求职者: 在Java中可以通过继承Thread类或实现Runnable接口来创建线程。还可以通过实现Callable接口并结合FutureTask来创建可以返回结果的线程。线程池的核心参数包括核心线程数、最大线程数、工作队列、线程工厂、拒绝策略和保持活动时间等。
面试官: 那你对Executors工具类提供的四种常见线程池了解吗?例如,newCachedThreadPool里的阻塞队列是什么?有什么特点?
求职者: Executors提供了四种常见的线程池:newCachedThreadPool、newFixedThreadPool、newSingleThreadExecutor和newScheduledThreadPool。newCachedThreadPool的阻塞队列是SynchronousQueue,它没有容量,每一个插入操作必须等到另一个线程的移除操作,这种线程池适合执行很多短期异步的小程序或者负载较轻的服务器。
面试官: 接下来我们聊聊Java异常体系。能介绍一下吗?它的顶级父类是什么?
求职者: Java的异常体系主要分为两类:Error和Exception。Error是指在正常情况下不大可能出现的情况,这些情况通常是严重的、不可恢复的系统错误。Exception则是在程序运行期间可能出现的条件,可以进一步分为检查性异常(checked exceptions)和非检查性异常(unchecked exceptions,即运行时异常)。它们的顶级父类都是Throwable。
面试官: 好的,那在编码过程中如何处理异常,你有什么最佳实践吗?
求职者: 在编码过程中,我会遵循以下最佳实践来处理异常:
- 只捕获那些能够处理的异常。
- 尽量提供具体的而非通用的异常处理,这样有助于更好地调试和理解问题。
- 避免空的catch块,至少也应该记录异常信息。
- 在捕获异常后,考虑是否需要将它转换为另一种异常然后抛出,以便于调用者更好地理解和处理。
面试官: 了解了。那你对CountDownLatch和CyclicBarrier了解多少?
求职者: 我知道CountDownLatch是一个同步辅助类,用于延迟线程的进度直到其它线程的操作完成。CyclicBarrier则是一个同步辅助类,它允许一组线程相互等待,直到所有线程都到达一个公共屏障点。它们都可以用于多线程编程中,让线程在某个点上同步。
面试官: 那么,你能介绍一下JVM的内存结构和哪些地方会发生GC吗?
求职者: JVM的内存结构主要包括堆内存、方法区、程序计数器、虚拟机栈和本地方法栈。GC主要发生在堆内存中,这是大多数对象分配和回收的地方。方法区也可能会进行GC,主要是针对常量池的回收以及对类型的卸载。
面试官: 接下来,你能说说常见的GC算法和垃圾回收器吗?
求职者: 常见的GC算法包括标记-清除算法、复制算法、标记-整理算法和分代收集算法。垃圾回收器有很多种,例如Serial GC、Parallel GC、CMS GC、G1 GC等,它们各自适合不同的应用场景和系统配置。
面试官: 很好。那你知道如何用Linux命令统计一个文件的行数,以及grep命令的常用方法吗?
求职者: 可以使用wc -l
命令来统计文件的行数。grep命令用于文本搜索,常用的选项包括-i
忽略大小写、-r
递归搜索、-v
反转匹配等。例如,grep -i 'pattern' filename
可以在文件中不区分大小写地搜索给定的模式。
面试官: 谢谢你的回答。为了节约时间,我们直接进入到项目介绍部分。你能介绍一下你的SaaS短链接项目吗?
求职者: 当然。在我们的SaaS短链接项目中,我们为客户提供了短链接生成和管理服务。我们设计了一套算法来将长链接转换成短链接,并且优化了存储结构和查询性能。我们还使用了分表技术来应对大量数据,并且通过布隆过滤器来优化查询效率和降低数据库压力。为了保证缓存的一致性,我们使用了延迟双删策略,并且利用Canal监听数据库binlog来同步数据变化到缓存。
面试官: 很全面的介绍。你提到了缓存一致性,你们是如何保证的?比如说,Canal监听binlog的具体流程和MQ在其中起到的作用?
求职者: 为了保证缓存和数据库的一致性,我们采用了Canal来监听MySQL的binlog。Canal会将binlog中的变化捕获出来,并将这些变化转换成消息发送到MQ中。然后,我们的缓存系统会订阅这些消息,并根据消息内容来更新缓存。这样可以确保当数据库内容发生变化时,缓存也能够及时更新。
面试官: 对,那你能说说你们项目中为什么需要MQ,以及你了解的MQ的死信队列是什么吗?
求职者: 我们项目中使用MQ主要是为了解耦服务和提高系统的可伸缩性。通过MQ,我们可以让生产者和消费者异步地处理消息,这样就可以在系统各个部分之间进行平滑的通信。关于死信队列,它是用来处理无法正常消费的消息的特殊队列。如果一个消息由于某些原因被拒绝或者多次重试仍然失败,它就会被放入死信队列,然后我们可以对这些消息进行特殊处理,如错误报告或者人工干预。
面试官: 那你对MySQL的InnoDB引擎的底层数据结构了解吗?以及聚簇索引和非聚簇索引的区别?
求职者: InnoDB引擎使用B+树作为其底层数据结构,它支持事务和行级锁定。聚簇索引是InnoDB中的主要索引,它将数据行直接存储在索引的叶子节点中。非聚簇索引则是二级索引,它的叶子节点存储的是对应数据行的主键值。一个表只能有一个聚簇索引,因为它实际上就是表的物理存储顺序。
面试官: 那你知道索引失效的场景,以及abc联合索引在不同查询语句中的使用情况吗?
求职者: 索引失效的场景包括使用了不等于操作符、对索引列进行了运算或函数处理、使用了OR条件但索引列不在所有条件中都有等等。对于abc联合索引,如果查询语句中使用了a、ab或者abc作为条件,那么索引都会被使用。但如果查询条件中没有包含a,那么索引就不会被使用。
面试官: 很好。最后,你能谈谈MySQL的隔离级别会带来的问题,以及你是如何理解服务拆分和微服务的吗?
求职者: MySQL的隔离级别如果设置得不当,会带来脏读、不可重复读和幻读等问题。默认的隔离级别是可重复读(RR),它可以通过MVCC来防止脏读和不可重复读,但它并不能完全解决幻读问题。至于服务拆分和微服务,它们是构建大型系统时的一种架构风格。服务拆分是将系统拆分成多个小服务,每个服务职责单一、独立部署。微服务架构是一种特殊的服务拆分方式,它强调服务之间的轻量级通信、自治和可伸缩性。
面试官: 很全面的回答。接下来,我们来谈谈服务拆分。你是如何做服务拆分的?你是如何理解微服务的?
求职者: 服务拆分通常根据业务功能和业务团队的划分来进行。比如在我们的项目中,将用户服务、订单服务、支付服务等不同的业务功能进行拆分,每个服务都能独立部署和扩展。我理解的微服务,就是将一个大型的单体应用拆分成一组小的服务,每个服务运行在自己的进程中,服务之间通过HTTP REST API或者轻量级的消息传递机制进行通信。
面试官: 非常好。那么在一个请求到达服务器的过程中,gateway、nacos、feign分别起到什么作用?
求职者: 在请求到达服务器的过程中,gateway作为API网关,它负责请求的路由、负载均衡、校验等,它是微服务架构中的入口。Nacos用作服务发现和配置管理,它能够帮助服务之间找到对方并且获取必要的配置信息。Feign是一个声明式的HTTP客户端,它让调用远程服务就像调用本地方法一样简单。在整个请求流程中,当请求到达gateway后,gateway会通过Nacos获取服务实例的信息,然后通过Feign客户端调用实际的服务。
面试官: 那你知道Feign的数据交互格式是什么吗?
求职者: Feign的数据交互格式通常是JSON,它利用HTTP协议传输,通过序列化和反序列化,将Java对象转换成JSON格式的数据,这样可以在不同服务之间进行交互。 面试官: 那么你是**如何理解RPC(Remote Procedure Call)的? **
**求职者: RPC,远程过程调用,是一种计算机通信协议。它允许像调用本地服务一样调用另一台计算机上的服务。RPC隐藏了底层的通信细节,使开发者可以不用考虑网络细节,就能进行分布式系统的开发。RPC可以通过多种方式实现,包括HTTP、gRPC以及消息队列等。 **
面试官: 正确,RPC的核心就在于使远程方法的调用像本地方法一样自然。现在我们聊一聊分布式系统,你知道什么是分布式锁吗?Redisson的实现有什么特点?
求职者: 分布式锁是在分布式系统中用来同步不同节点间相同资源访问的机制。Redisson是一个基于Redis的Java库,它提供了分布式锁的实现。Redisson的特点是它使用了Redis的特性,如SETNX命令来实现锁的功能,并且可以支持可重入性,即同一线程可以多次获得同一把锁。
面试官: 很好。那你认为SETNX和设置过期时间这两步操作需要保证原子性吗?
求职者: 是的,这两步操作需要保证原子性,以防止在设置锁的过程中出现故障导致锁没有正确设置过期时间,这可能会引起死锁的情况。Redis的SET命令可以同时设置键值对和过期时间,从而保证了这两步操作的原子性。
面试官: 了解了。那你知不知道ThreadLocal?你能用ThreadLocal来实现一个可重入锁吗?
求职者: ThreadLocal是Java中一种线程局部存储的机制,它可以为每个使用该变量的线程提供一个独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其他线程。至于如何用它来实现可重入锁,我没有具体实践过,但理论上我们可以在ThreadLocal中存储一个计数器或者锁的拥有者信息,来帮助我们实现锁的可重入性。
面试官: 没错,ThreadLocal可以用来存储当前持有锁的线程和重入计数。接下来,谈谈倒排索引的概念。
求职者: 倒排索引是一种索引方法,它用来存储某个单词在文档或文档集合中的存储位置。它的核心思想是通过单词来查找文档。这种索引方式对于文本搜索尤其有用,如全文搜索引擎Elasticsearch中广泛使用倒排索引来提高搜索效率。
面试官: 非常好。今天的面试就到这里,你的回答很全面。感谢你的参与,我们会尽快给你反馈。现在有什么问题想要问我的吗?
求职者: 是的,我想了解一下优选事业群具体负责哪些业务?以及后端开发工程师在日常工作中的主要任务是什么样的?
面试官: 优选事业群主要负责美团的优选业务,包括商品推荐、订单处理、物流配送等。作为后端开发工程师,你的主要任务将包括业务逻辑的实现、系统性能优化、数据处理和服务稳定性保障等。我们注重技术的深度和广度,以及对业务的深刻理解。
求职者: 非常感谢你的解答,我对加入美团感到非常期待。
面试官: 我们也期待你的加入。再次感谢你今天的努力,希望你有一个愉快的一天。
美团-优选事业群-后端开发一面
八股(30min)
- ArrayList和LinkedList的区别和特点以及使用场景
- 如何将ArrayList变成线程安全
- 并发包里有一个线程安全的ArrayList你知道吗?(不知道)CopyOnWriteArrayList听说过吗?(没听过,讲了一下CopyOnWrite)
- CopyOnWrite有什么缺点?适合什么样的场景?
- HashMap线程安全吗?它在并发包里对应的线程安全的类叫什么?
- currentHashMap如何保证线程安全的?为什么要将红黑树转化成链表?
- Java有哪几种方法创建线程?
- 线程池的核心参数
- Executors工具类提供的四种常见的线程池说一下?newCachedThreadPool里的阻塞队列是什么?有什么特点?
- Java异常体系介绍一下?顶级父类是什么?(本来只答了Exception的,面试说Error也属于异常体系)
- 编码过程中如何处理异常,最佳实践?
- CountDownLatch和CyclicBarrier了解吗?(知道是什么,底层不了解)
- JVM内存结构?哪些地方会发生GC?
- 常见的GC算法?常见的垃圾回收器?
- Linux统计一个文件有多少行的命令?
- grep命令一般怎么使用?
项目(50min)
- 介绍SaaS短链接项目
- 短链生成长链的算法
- 前后端交互的数据格式是什么?
- 为什么选择分表?为什么选择水平分表?
- 分片键如何选择?为什么需要路由表?
- 布隆过滤器?你在项目中用到布隆过滤器两面性的哪一面?
- 项目中如何保证缓存一致性?
- 有哪些方法保证一致性?延迟双删一定可以吗?Canal监听binlog的具体流程你知道吗?这里面MQ起到什么作用?(不知道)
- 什么场景需要用到MQ?你的项目为什么需要MQ?
- MQ的死信队列了解吗?(美团里经常用,挺熟悉的,面试官说Canal监听binlog就用到了死信队列)
- MySQL的InnoDB引擎了解吗?底层数据结构是什么样的?
- 聚簇索引和非聚簇索引的区别?可以有多个聚簇索引吗?
- 索引失效的场景?
- abc联合索引,出了四个查询语句,问分别都用到了哪些索引
- MySQL的隔离性特点会带来什么问题?
- 默认隔离级别是什么?为什么RR可以解决幻读?
- MVCC机制,当前读和快照读
- 服务拆分怎么做的?你是如何理微服务?
- 请求到达服务器,gateway、nacos、feign分别起到什么作用?
- feign的数据交互格式是什么?
- 你是如何理解RPC的?(我说http、grpc、mq都可以算作rpc,面试官说核心就是一句话“调用远程方法如同调用本地方法”)
- 什么是分布式锁?Redisson的实现有什么特点?如何理解可重入?
- setnx 和 设置过期时间 两步需要保证原子性吗?
- 知道ThreadLocal吗?如何用ThreadLocal实现可重入锁?(不知道,没考虑过)
- 倒排索引的概念?(面试官希望我脱离ES聊倒排)
做题(10min)
- SQL题,面试官问我知不知道in 和not in,我说知道,面试官说那这题就不用做了
- 判断链表是否有环,set去重2min秒了,面试官说很好很符合公司实际开发情况,然后让我换一个空间复杂度低一点的方法,双指针2min秒了
- 面试官看我做得很快,笑着又出了一道返回有环链表的环,5min秒了
反问
- 什么业务
总结
美团面试官都温声细语,体验很好,问题也很基础,面试官夸我基础扎实知识完备,而且很多我答得不好的地方面试官都说没事没事已经答得很好了。然后面试官还教会了很多我没答上来的知识点,收获满满!赞美美团!而且美团的算法题也都是eazy和mid为主,太棒了!总体来说是体验很好收获良多的一次面试。
作者:是红鸢啊 链接:https://www.nowcoder.com/discuss/603257053682941952 来源:牛客网