Day27 面经一篇
gap8个月后第一个面试啊,答的时候太紧张了,复盘一下我的凉经
某公司一面,3年java后端,薪资范围18k-29k
- 自我介绍
- 简历上近期工作经历是到2025年6月,你是因为什么离职,期间去干嘛了?
合同到期,跟公司协商离职,没续签;离职后给自己放了一个小长假,回来后在对自己的知识进行查漏补缺,提升自己。
正式提问环节
- ConcurrentHashMap了解吗?其中的size方法是怎么实现的?
size()方法在1.7和1.8中的实现是不同的,1.7在调用size时会把所有的segment都锁上,然后再去计算它的数量;而1.8是不会锁直接进行计算的。 准确回答应该是 1.7 调用size方法的时候不回加锁,先尝试三次不加锁获取sum,如果三次的结果都一样,就直接返回;如果不一样,就会给每个segment加锁再计算。 1.8 采用类似LongAdder的思想,搞了一个数组,每个线程在自己对应的下标进行累加,最后把数组里的数据归总统计
- volatile关键字了解吗?能不能保证原子性,为什么?
不能保证原子性,只能保证可见性,假如说你volatile修饰的是一个对象类型的数据,你只能看得到有线程对这个对象进行了修改,但是改了什么管不着。 准确回答应该是 一个数据修改了,告诉其他线程我修改了你们可以读了,这时候会有可能有多个线程同时读到这个数据并进行修改,这样原子性是保证不了的
- CountDownLatch/CyclicBarrier有用过吗?说一说它们的区别
实际工作中使用过CountDownLatch,没用过CyclicBarrier但有一定了解 CountDownLatch 是一次性使用,每次使用时都要new一个实例,构造器参数等于要执行的线程数,执行时要手动在线程里调用countDown方法说明我已经使用了一个,在主线程中调用await方法等待计数器为0,才会进行下一步操作。 CyclicBarrier 可以重复使用,同样也需要在实例化时传入需要执行的线程数,但他是在线程里面调用await方法等待其他线程执行完,内部会自动扣减计数,等到所有线程都调用await后才会回到主线程进行其他的工作。
- select * from test where b=2 and a >1 and c=3; 索引是(a,b,c)会走索引吗,为什么?如果是mysql8.0的话,哪些字段会走索引,哪些不会?
得看情况: 如果数据量太大的话,优化器可能认为走了索引还不如全表扫,干脆不走; 正常情况下的话还是匹配到a走索引,但是效率不高;在8.0的时候也是同样,只有a会走索引,其他的字段可能会通过索引下推过滤数据减少回表。
- 讲一讲覆盖索引和索引下推
覆盖索引是指在使用二级索引查询时,要查询的数据恰好都包含在二级索引内,不用回表,这时候就称为二级索引。 索引下推是指把部分条件下放至存储引擎层过滤以减少回表次数
- RR隔离级别,SQLA:update table set c= 10 where a between 10 and 20; SQLB:insert into table (a, b, c) values (15,20,30); 先执行SQLA,再执行SQLB,会出现什么情况?(未指定事务提交情况,需自行讨论,会不会死锁)
(这里没分情况考虑,就直接答了一句,SQLA会加行锁,SQLB阻塞,等A释放锁才会执行,不会造成死锁(寄)) 更准确的回答应该是 这里表结构未知,没有确定索引,应当分情况讨论
- 在不同事务中 a. 如果a有索引,但未提交,此时会给(10,20)这个区间上gap-lock,SQLB执行会被阻塞,等待SQLA提交才能执行成功; b. 如果a没有索引,未提交,此时会给表上表锁,SQLB被阻塞。 c. 如果SQLA已提交,不管此a有没有索引,时SQLB执行都无问题
- 在同一事务中 顺序执行,不存在竞争关系,不受自己所在的事务加锁的影响
- 说说你对分库分表的理解
我只讲水平/垂直分库/分表的概念(寄)
- 怎么保证Kafka的消息顺序消费?如果出现几千万条甚至上亿条消息积压,如果快速处理恢复?
(谁能知道,我kafka的知识是昨晚临时补的呀) 顺序消费:首先生产者->Broker端,是根据key做partition分区的,只要保证key一致,就能将一批消息塞到同一个partition里,利用FIFO的性质,天然保证这一有序性;然后消费者只要指定只有一个consumer能从这个partition中拿消息,那就一定是顺序性的。(怎么指定?死脑子忘了-通过继承AbstractPartitionAssignor类实现自定义消费策略) 消息积压:由于kafka同一个消费者组下的consumer与partition有对应关系,增加消费者去处理也只能增加到与partition一致的数量,所以我会选择创建一个新的topic,设置足够多的消费者和partition,然后将积压消息的topic内的消息转移到这个新的topic,然后再对原有设计改造,增加消费者数量去从新的消费者消费。
- 工作中用JDK哪个版本,使用的什么垃圾收集器?
用的JDK8,公司用的什么垃圾收集器没关注过,不过我认为不是CMS就是G1。(还好没深入问了,死脑子记不住啊)
- 对象什么时候会进入老年代?
年龄达到阈值的存活对象,Survivor区放不下的对象,大对象
- 频繁FULL GC怎么排查和解决
使用阿里开源的工具arthas,或者用jmap命令(死脑子忘记了什么命令,寄) 正确回答 开启GC日志确认 如果老年代使用率持续上升,FULL GC无法释放 用jmap -dump:live,format=b,file=heap.hprof pid 定位是否内存泄漏导致;要进行代码修复 如果是FULL GC前老年代突然暴涨 用jmap -histo:live pid 定位大对象;将大对象拆分处理 如果是MinorGC频繁,且每次都有大量对象进入老年代jstat -gcutil pid 1s 确认;调整新生代大小 如果FULL GC为 Metadata GC Threshold;调整元空间大小 如果是System.gc();找找代码哪里写了。
- @Conditional注解有用过吗?说说你的理解
条件注解我实际生产中没有使用过,但在spring boot中见得比较多,加载时根据条件加载类(寄)
- 怎么自定义一个Spring Boot starter?
(完了)starter本质上是一个依赖打包机制,所有东西都封装好,拿来开箱即用。但我没自己实现定义过(寄)
- netty有了解吗?
这个不清楚,没用过 (学不动了呀)
- 场景:请你设计一个多级缓存以保护数据库,要保证缓存的一致性,且缓存会存在热key,你会怎么做?
(寄)就讲到了防止缓存雪崩,延迟双删策略保证一致性
- 除了Java和前端的技术栈,你还接触过其他语言吗?
- 平时你会不会用一些AI工具编程,cursor、Claude code这些有了解和使用过吗?
- 你上一份工作的薪资是多少,以及你期望薪资是?
反问环节
- 公司的技术栈
- 工作氛围
