美团一面面经(已凉)
写在前面
今年真的是太太太卷了,我往届师兄在我投简历的前一年的相同时间都没投实习,依然拿到了蚂蚁的实习offer,但是今年我投的时候蚂蚁就已经没hc了,所以各位0offer选手还是要稳住心态,今年都不好过。关于这次美团面试首先还是学到了很多东西,同时难度也是真的有点高,完全是从面试官的生产环境碰到的问题来提问,问的八股很少很少,再加上这是我第一次面试,有些八股的回答也不是很完善,最后还是收到了感谢信。
面试问题
用户抖动同时发送两个请求,后台怎么拦截?
前端设置用户点击后禁用按钮。
单体服务器:
- 采用线程并发的方式处理,相同的请求同一时间只能被处理一次。
- 去重表:客户端请求服务器,服务器先将请求放入mysql的去重表中,该表根据请求的某个特殊字段(比如博客内容的md5格式)建立唯一索引或主键索引(需要去除日期等细微差别的影响),若表中已存在,插入失败
- 悲观锁:对写进行加锁操作
分布式情况:
- 利用redis的setex,key为用户id,value是对应内容,若请求在redis中可以找到,说明很短的时间内用户再次请求,可以认为是重复请求,直接返回即可
- 后端可以用消息队列或者缓存,过滤掉相同的请求
如果你要给外界暴露一个接口,接口应该在哪个层实现?
接口应该在service层实现,暴露接口,由不同的厂商自己实现。
mvc分层的原因,具体是怎么分层的,原则是什么
分层原因肯定是解耦合,降低不同层之间的依赖,以达到减小代码复杂度和提高复用性的目的。分层原则可以用功能的角度考虑。
view层:就负责视图相关的操作,进行视图展示,以及变量的获取,一般不要有复杂的计算和判断。
model层:负责事物信息的保存以及对信息的操作。
1. model层具体包括数据,对数据的行为和采用的方法
2. model应该是三层中业务逻辑最复杂的一层
3. 处理业务方面的逻辑理应该都放在model层
controller层:是model和view的桥梁,负责接收请求,然后调用不同的接口来实现请求,并将结果返回前端
1. controller越瘦越好
2. 只是起到数据在view和model中的传递作用
如何在多个方案中选择,需要考虑哪些因素?
面向对象:不同的对象方案的侧重点不同,比如军方更注重稳定性,准确性;企业同时会注重成本。
安全性:被攻击时有无防御机制,有无明显的漏洞
稳定性:结果的稳定和系统的稳定性
性能:哪种方案的性能更好,低延迟?低带宽?占用更少的资源?
成本:产品成本,人力成本和时间成本
某个博客评论很多,如何解决存储问题?
欢迎评论区大神解答。
评论的循环嵌套问题在数据库层面如何解决?
没太理解这个问题的意思,最后就说了个在serice层迭代处理,把它变为两层的结构显示在前台。
spring如何解决循环依赖?
循环依赖是scope的作用域设定为了prototype,设定为singleton(当时还没看框架的八股,不知道)
spring动态代理的实现?
1. JDK动态代理:代理的类必须实现接口。通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口,核心是invocationHandler接口和proxy类。
2. CGLIB动态代理:动态生成被代理类的子类。是一个代码生成的类库,可以在运行时动态的生成某个类的子类,所以如果某个类被标记为final,则无法使用CGLIB做动态代理。
jdk和cglib的性能差异,哪个更好
CGLib所创建的动态代理对象的性能依旧比JDK的所创建的代理对象的性能高不少(约10倍),但CGLib在创建代理对象时所花费的时间却比JDK动态代理高(约8倍),所以对于singleton的代理对象或者具有实例池的代理,因为无须频繁创建代理对象,所以比较适合用CGLib动态代理技术,反之适合用JDK动态代理技术。
JDK是基于反射机制,生成一个实现代理接口的匿名类,然后重写方法,实现方法的增强.
它生成类的速度很快,但是运行时因为是基于反射,调用后续的类操作会很慢.
而且他是只能针对接口编程的.
CGLIB是基于继承机制,继承被代理类,所以方法不要声明为final,然后重写父类方法达到增强了类的作用.
它底层是基于asm第三方框架,是对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理.
生成类的速度慢,但是后续执行类的操作时候很快.
可以针对类和接口.
分布式锁相关,实现,原理?
这个真的是一点都不知道,当时介绍时也没提自己会分布式的东西,属于问到知识盲区了
zset,hash的底层结构?
zset底层的存储结构包括ziplist或skiplist,在同时满足以下两个条件的时候使用ziplist,其他时候使用skiplist,两个条件如下:
- 有序集合保存的元素数量小于128个
- 有序集合保存的所有元素的长度小于64字节
当ziplist作为zset的底层存储结构时候,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员,第二个元素保存元素的分值。
当skiplist作为zset的底层存储结构的时候,使用skiplist按序保存元素及分值,使用dict来保存元素和分值的映射关系。
项目过程中遇到的问题?
从数据库底层开始,向上到前后端的交互
常见的并发容器,原理?
- concurrenthashmap
- concurrentLinkedQueue : 高效的并发队列,使用链表实现。可以看做一个线程安全的LinkedList,这是一个非阻塞队列。
- concurrentskiplistmap:跳表的实现。这是一个Map,使用跳表的数据结构进行快速查找。
- copyonwriteArrayList:: 线程安全的List,在读多写少的场合性能非常好,远远好于Vector。
- blockingqueue:阻塞队列。3个实现类,arrayblockqueue,linkedblockingqueue,priorityblockingqueue
reentrantlock,sychronized的底层原理:
一个基于aqs机制,一个基于监视器锁,说了一些具体的内容。
如何保证线程安全:
volatile关键字,两个锁,应该还有cas机制的(这个没说)
redis常用数据结构,统计月活为何用bitmap:
忘说list了,hash的底层结构忘了,bitmap是因为有位运算,速度更快
事务要放在controller层还是service层:
controller层,要么全进行,要么都失败
最后的手撕题:
链表反转,但是要自己实现链表的结构
总结:
回答的太啰嗦,有很多无效表达;回答问题的思考时间太短,很多问题没来得及深度思考就急着回答了;概念有些混了,八股还得背。
#实习##面经##Java##后端开发#