S学长美团&&美团优选面经

美团

首先上来介绍自己

这里没什么说的,硬要说坑的话就是突出说了粮储那个项目,其实简历上Redis这块也蛮坑的,说实话有时间应该系统的学习下Redis了,不能每次问到都不会了。

问项目

因为前阵子看数据库看的比较多,所以一直把面试官往这里引导,不过问粮储的原因导致这里准备的不是很充分,索引加的有点莫名其妙,总结下来应该多看看索引的实际应用这里。感觉我应该说在公司名称上加索引要更好。

索引的原理

这里主要问了索引为什么使用B+树,感觉自己答得不是很好,首先B+树拥有B树的全部优点,每个节点增加了多个子节点,每个page可以容纳更多的节点,导致减少I/O次数,增加了性能。不同的是B+树的数据只在叶子节点存储,这样每个节点相比于B树更小,从而使树更浅。其次扫库扫表的能力更强,因为叶子节点是双向指针,我们可以从叶子节点开始查询,无需回到根节点重新查询。在排序与范围查找能力更强,因为其可以直接在叶子节点进行查询。

InnoDB有没有非聚集索引

这个答得太草率了,其实应该是有的,因为想到辅助索引存的是主键值,所以觉得没有,其实是错的。InnoDb里非聚簇索引都是辅助,像联合索引、前缀索引、唯一索引等都是非聚簇索引。

算法:遍历二叉树

这个其实应该写上的,回溯的想法是正确的,缺点是不该写循环,直接一条道遍历下去就好了。

线程池配置参数

因为线程池没好好看,这道题就答上了一个核心线程数和最大线程数。这里做个补充。有一个interface的阻塞队列,可由用户定制,有一个Set类型的workers,用来存储工作线程的集合,一个ReetrantLock类型的mainLock,一个线程池总共处理的任务数,一个最多的活跃线程数,还有拒绝策略。

了解的锁

自旋锁、偏向锁、公平锁、非公平锁、可重入锁、共享锁、排它锁、轻量级锁(轻量级锁可以看成重量级锁的退化版本,不使线程阻塞,而是采用自旋)

自旋锁的原理

CAS这个背的比较熟了

有哪些锁使用了CAS

AQS实现的锁都使用了CAS,还包括轻量级锁。

Redis可以存哪些类型

string、list、hash、set、sorted set

Redis底层数据结构

链表、双端链表、字典、整数集合、跳跃表、long类型的整数、简单动态字符串、压缩列表

项目为什么使用SpringBoot

其实就是问SpringBoot的优点 (1) Spring Boot使编码变简单 (2) Spring Boot使配置变简单 (3) Spring Boot使部署变简单 (4) Spring Boot使监控变简单

SpringMVC是怎么进行前后台连接的

  1. 发送请求到前端控制器(DispatcherServlet)
  2. 前端控制器请求HandlerMapping查找Handler(可以根据xml配置、注解进行查找)
  3. 处理器映射器HandlerMapping向前端控制器返回Handler
  4. 前端控制器调用处理器适配器去执行Handler
  5. 处理器适配器执行Handler
  6. Handler执行完给处理器适配器返回modelAndView
  7. 处理器适配器向前端控制器返回ModelAndView(ModelAndVIew是Springmvc底层的对象,包括Model、View)
  8. 前端控制器请求视图解析器去进行视图解析(根据逻辑视图名去解析真正的视图(jsp))
  9. 视图解析器向前端控制器返回view
  10. 前端控制器进行试图渲染(试图渲染:将模型数据(modelAndView对象中)填充到request域)
  11. 前端控制器向用户响应结果

你是如何学习Java的

这里答得是看书,看视频。思考了一下应该把写博客和研究github代码也加入进去,同时不能忘了动手操作。

美团优选

1.自我介绍

这次的自我介绍我觉得还是挺满意的,不过美中不足的是可能是没有详细的说明项目,导致根本没有问到有关项目的知识。

2.算法:二叉树的最近公共祖先

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null || p == root || q == root) {
            return root;
        }
        TreeNode pqInLeft = lowestCommonAncestor(root.left, p, q);
        TreeNode pqInRight = lowestCommonAncestor(root.right, p, q);
        if(pqInLeft == null) {
            return pqInRight;
        }
        if(pqInRight == null) {
            return pqInLeft;
        }
        return root;
    }
}

3.用Linux写出一个寻找重复数的代码

这方面是真的积累少了,答完这个我就把简历里Linux的内容去掉了…下面是在网上找的内容,这里做一下积累: Linux uniq 命令用于检查及删除文本文件中重复出现的行列,一般与 sort 命令结合使用。

uniq 可检查文本文件中重复出现的行列。

语法 uniq [-cdu][-f<栏位>][-s<字符位置>][-w<字符位置>][–help][–version][输入文件][输出文件] 参数:

  • c或–count 在每列旁边显示该行重复出现的次数。
  • d或–repeated 仅显示重复出现的行列。
  • f<栏位>或–skip-fields=<栏位> 忽略比较指定的栏位。
  • s<字符位置>或–skip-chars=<字符位置> 忽略比较指定的字符。
  • u或–unique 仅显示出一次的行列。
  • w<字符位置>或–check-chars=<字符位置> 指定要比较的字符。
  • -help 显示帮助。
  • -version 显示版本信息。
  • [输入文件] 指定已排序好的文本文件。如果不指定此项,则从标准读取数据;
  • [输出文件] 指定输出的文件。如果不指定此选项,则将内容显示到标准输出设备(显示终端)。
3.1 算法:寻找数组中的重复数
class Solution {
    public int findRepeatNumber(int[] nums) {
        HashSet set = new HashSet<>();
        for(int i = 0; i < nums.length; i++) {
            if(!set.contains(nums[i])) {
                set.add(nums[i]);
            } else {
                return nums[i];
            }
        }
        return -1;
    }
}
3.1.1 用HashMap的算法复杂度呢?

因为上道题我用的HashMap,所以就有了这道题。很简单:O(n)。

3.2 如果这个重复数的文件超出内存怎么办?

分批处理,这里做一个积累: https://blog.csdn.net/liaonanfeng88/article/details/103629506

4.场景题:转账

用事务

5.事务的隔离等级

事务隔离级别脏读不可重复读幻读
读未提交(read-uncommitted)
不可重复读(read-committed)
可重复读(repeatable-read)
串行化(serializable)

6.可重复读的原理

这个参考自己的文章就行了,不过还没更新到= =

7.说一下ThreadPoolExecutor的成员变量

这个参考我的博文 http://182.92.213.85/articles/44

8.说一下工作队列,最大线程数,核心线程数

这个参考同样我的博文 http://182.92.213.85/articles/44

8.1工作队列满了是直接申请到最大线程数么?
8.2 你觉得核心线程数和最大线程数之间应该如何设置呢

这个根本没准备,所幸就用25%了,然后说是因为HashMap的启发,但事实肯定不是这样的。

对于CPU密集型任务,由于CPU密集型任务的性质,导致CPU的使用率很高,如果线程池中的核心线程数量过多,会增加上下文切换的次数,带来额外的开销。因此,一般情况下线程池的核心线程数量等于CPU核心数+1。(注:这里核心线程数不是等于CPU核心数,是因为考虑CPU密集型任务由于某些原因而暂停,此时有额外的线程能确保CPU这个时刻不会浪费。但同时也会增加一个CPU上下文切换,因此核心线程数是等于CPU核心数?还是CPU核心数+1?可以根据实际情况来确定)

对于I/O密集型任务,由于I/O密集型任务CPU使用率并不和很高,可以让CPU在等待I/O操作的时去处理别的任务,充分利用CPU。因此,一般情况下线程的核心线程数等于2*CPU核心数。(注:有些公司会考虑所需要的CPU阻塞系数,即核心线程数=CPU核心数/(1-阻塞系数))

对于混合型任务,由于包含2种类型的任务,故混合型任务的线程数与线程时间有关。一般情况下:线程池的核心线程数=(线程等待时间/线程CPU时间+1)*CPU核心数;在某种特定的情况下还可以将任务分为I/O密集型任务和CPU密集型任务,分别让不同的线程池去处理,但有一个前提–分开后2种任务的执行时间相差不太大。

8.3 HashMap的扩容机制

这个不久就会更新的

8.3.1 HashMap的原理

同上

9. 垃圾回收算法

  1. Mark-Sweep(标记-清除)算法
  2. Copying(复制)算法
  3. Mark-Compact(标记-整理)算法(压缩法)
  4. Generational Collection(分代收集)算法

10. 如何判断对象需要回收?

GC-root(这里问我对象调用是怎么回事,是调用方法么?我说是,但感觉有问题,这里我会去查查,查到了就会更新)

11. JVM用到了什么垃圾回收算法

目前大部分垃圾收集器对于新生代都采取复制算法,因为新生代中每次垃圾回收都要回收大部分对象,也就是说需要复制的操作次数较少,但是实际中并不是按照1:1的比例来划分新生代的空间的,一般来说是将新生代划分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden空间和其中的一块Survivor空间,当进行回收时,将Eden和Survivor中还存活的对象复制到另一块Survivor空间中,然后清理掉Eden和刚才使用过的Survivor空间。

而由于老年代的特点是每次回收都只回收少量对象,一般使用的是标记-整理算法(压缩法)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值