面经合集
泰豪软件 | 广州
用时差不多正好半小时,面的是泰豪软件(广州),面试官人感觉不错。第一次面试感觉没有想象中的那么紧张,八股和项目都问了一点。
上来自我介绍
八股:
- private,default,protected,public的区别;
- &和的区别;
- final关键字;
- break,continue,return;
- 单列集合,List和Set有什么区别;
- CopyOnWriteArrayList;
- 多线程同步有哪几种方式(就回答了synchronized和lock);
- 常用的线程池有哪几种(一开始想说那个英文方法名,磕巴了半天没说出来还,最后直接用中文说了);
- 线程之间是怎么传递数据的(没回答好,没准备这个八股);
- 创建线程有几种方式;
项目:
- 除了MySQL还了解过其它数据库吗(本科的时候学过Oracle,没了);
- 设计redis的缓存更新策略的时候,考虑哪些因素(1、过期时间,2、先更新数据库,再删除缓存,更新缓存。不知道 回答的对不对);
- 怎么解决缓存击穿和缓存穿透的(介绍了一下这俩是什么,然后回答的,缓存击穿答得不是很详细,有点混乱了);
后面就是聊天了 问了意向城市, 然后学习和做项目的时候有没有碰到什么问题,是怎么解决的
对前端有了解吗,vue,如果有这方面的学习愿不愿意了解一下
问了下如果通过最快什么时候能到岗
个人职业规划 反问环节,问了几个。最后面试官介绍了一下他们公司业务什么的
南北科技 | 广州
广州小厂,线下面。面试问的问题感觉很奇怪,总共聊了半小时 聊了好长时间本科的毕业设计和现在的研究方向
ArrayList的底层实现,扩容机制;
然后问扩容,Arraylist正在add元素的时候,新数组和旧数组怎么处理(不是往新数组里面拷贝旧数组的元素吗
HashMap链表的扩容机制,链表里面是values,values是怎么存储的;
答:得到在数组中的索引,如果该处节点是链表,会在链表中遍历有没有相同的key,如果有就更新value,没有就在链表末尾插入,最后判断链表长度是否达到阈值(8,这个阈值忘了,直接说的阈值),是的话就转化为红黑树,增加查找效率
问了下平时用什么开发工具
很大的表,用Select count去统计表的条数,发现特别慢,怎么优化 不会,一开始没听清楚瞎答了索引,然后又说什么select count(1),,自己都有点想笑哈哈哈
很大的表,发现不管干啥都慢,有什么办法优化 不会,想到了分库分表,没看这个八股, 然后又问分(区)表策略,没了解
后面就聊到我的本科毕业设计了
然后又问springboot怎么实现‘约定大于配置’的,不会
redis怎么实现分布式锁 setnx命令
又说看我这边是用了lua脚本,直接说的没学过,就是跟着视频用的
最后反问环节
亿迅科技 | 广州
线下面。全程大概半小时左右,都不是严格的问答,比较开放式的,感觉跟报菜名似的,全是八股项目几乎没问
- 聊到一些集合类,把List,Map,Set都介绍了一下,以及对应的使用场景
- ArrayList和LinkedList的区别
- ArrayList的扩容机制
- HashMap简单说了一下,都没涉及到put流程
- I/O,不熟
- 项目中怎么用的乐观锁悲观锁
- 网络编程,Socket,不熟
- NIO/BIO,不熟
- 序列化和反序列化,怎么让一部分数据不被序列化,第二个忘了
- Spring的IOC和AOP
- sql的全称,忘了。。-_-||
- 然后问的视图,存储过程,都没背。。
- 索引简单答了一下底层数据结构
- 表之间的连接
- JDBC,没看,
- String,StringBuffer,StringBulder
- ==和equals
后续10.8 OC
中科星图 | 北京
2024-12-14
自我介绍
问实习,做了啥,遇到了啥问题,叽里咕噜扯了一通
问我熟悉什么框架,必须boot啊,然后让我讲一下,讲不好,扯到spring讲讲ioc和aop了
然后问我注解,是通过反射吧好像,忘了
然后反问,聊了一下工作时间,做什么(全栈),。。
番茄小说
2024-12-21
Q:java并发编程并发的是线程还是进程?
A:线程,不过说的很紊乱,讲了很多没必要讲的东西
以下是gpt回答
解释:
- 线程 是程序中的一个执行单元,线程是轻量级的,它们共享进程的资源,如内存和文件句柄。在Java中,线程是通过实现
Runnable接口或继承Thread类来创建的。 - 进程 是操作系统分配资源的最小单位,每个进程都有自己独立的内存空间。Java程序通常运行在一个进程中,而该进程内可能有多个线程。
并发的定义:
- 并发 指的是多个任务的执行在时间上有重叠,而不一定是同时进行。通过多线程并发执行,Java能够在多核处理器上高效地利用多个CPU核心,但并发本身并不等同于并行。并行是指多个任务在同一时刻执行。
总结:
- Java并发编程中,“并发”是指 多个线程 的执行。
- 如果涉及多个进程,通常称之为 多进程 编程,而不属于并发的范畴。
Q:进程和线程的区别
A:一个进程可能就是会包含多个线程,线程可以理解为轻量级的进程,上下文切换这个开销一般是比较小的,线程可以共享这个进程的一些资源比如说内存空间(内存空间埋雷了)
Q:那你觉得你对于他们的底层结构了解吗,比如说你刚才提到了共享内存那你共享的资源嘛对吧那你能说一下比如说我启动了一个那个进程然后那进程跟线程之间应该是如何去申请这个资源以及实现资源共享呢。后续又补充了一点,比如说创建一个进程然后这个资源我是怎么申请的以及线程去怎么去共享这些资源的。
A:的一塌糊涂
Q:线程池的作用以及实现原理。
A:复用线程,实现原理不会(其实就是线程池处理任务的流程,不知道是这个题目,背了八股也没用上😭😭😭😭
以下是gpt回答
线程池的实现原理
线程池的核心思想是任务提交-线程复用。以下是线程池的基本组成和工作原理:
1. 基本组成
- 任务队列(Task Queue):
- 一个线程安全的队列,用于存储提交但尚未被执行的任务。
- 任务是实现了某种接口(如
Runnable或Callable)的对象。
- 工作线程(Worker Threads):
- 线程池中实际执行任务的线程集合。线程池在初始化时会创建一定数量的线程,并在任务提交后复用这些线程执行任务。
- 线程管理器:
- 管理线程的生命周期,维护线程池中线程的数量。
- 根据配置动态增加或减少线程数(如扩展或缩减线程池大小)。
- 任务提交接口:
- 提供给用户用于提交任务的方法,比如
execute()或submit()。
- 提供给用户用于提交任务的方法,比如
- 任务调度器:
- 从任务队列中获取任务并分配给工作线程。
- 如果任务队列为空,工作线程会进入等待状态。
2. 线程池的工作流程
- 线程池初始化:
- 根据配置,线程池创建一定数量的工作线程,并处于等待任务的状态。
- 任务提交:
- 用户通过线程池的接口(如
execute()或submit())提交任务,任务被添加到任务队列中。
- 用户通过线程池的接口(如
- 任务调度:
- 线程池中的工作线程会从任务队列中取出任务进行执行。
- 如果所有工作线程都在忙,任务会在任务队列中排队等待。
- 任务执行:
- 工作线程执行完任务后,线程不会被销毁,而是返回线程池继续等待新的任务。
- 动态扩展(可选):
- 如果任务队列过长且所有线程都在忙,线程池可以动态创建新的线程来处理任务(受最大线程数限制)。
- 线程回收:
- 如果线程池中某些线程长时间没有任务可执行,线程池可以销毁这些空闲线程以节省资源。
Q、如果没有锁机制的话在并发编程的场景会出现什么问题。
A:数据的一致性可能出现问题(问我还有没有补充,我也没想到其它的了
以下是在网上搜的,并发编程需要加锁的时候,如果就不加会怎么样?
- 数据不一致:多个线程同时访问和修改共享资源时,如果没有加锁,可能会导致数据竞争,即一个线程在读取数据的同时,另一个线程修改了数据,从而导致最终的数据状态与预期不符。例如,在多线程环境下,多个线程同时对同一个账户余额进行操作,如果不加锁,可能会出现余额被重复扣款或重复加款的情况。
- 竞态条件:竞态条件是指在多线程环境中,由于线程调度的不确定性,导致程序的行为依赖于不可预测的执行顺序。如果不加锁,可能会导致程序在某些情况下出现不可预期的行为,如死锁、饥饿等问题。
- 线程安全问题:在多线程编程中,多个线程可能会同时访问共享资源,这很容易导致数据的不一致性和竞态条件。如果不加锁,可能会导致线程安全问题,影响程序的正确性和稳定性。
- 死锁风险:死锁是指两个或多个线程互相等待对方释放资源,导致所有线程都无法继续执行。如果不加锁,可能会增加死锁的风险,尤其是在复杂的并发场景中。
- 难以调试:在多线程环境中,如果不加锁,可能会导致难以调试的问题。由于线程的执行顺序是不可预测的,错误可能在某些特定的执行路径下才会出现,这使得调试变得非常困难。
Q:项目:怎么实现优惠券的秒杀
A:这个基本答得是那么回事,就是乐观锁的cas
Q:什么叫乐观锁?为什么不用悲观锁?
A:适用读多写少,然后说了一下cas的实现(感觉都没答到点子上😅😅);用悲观锁就是影响性能,因为会频繁的更新数据
Q:select语句的执行过程
A:(这个答得应该大差不差,唯一画蛇添足的一点就是把废弃的那个缓存器也答上了,又给后面埋雷了😅😅😅😅)连接器——语法器——优化器——执行器
Q:缓存的粒度是什么?或者说它是怎么缓存的,缓存的东西是什么
A:直接说不清楚,缓存的应该是语句吧。然后问如果缓存了SELECT A = 1再来执行SELECT A = 1 AND B = 1能用到缓存吗?猜的能
以下来自gpt
存储常用或最近使用的数据和查询结果,提高了查询性能,减少了对底层存储的访问。 存储查询的完整结果集,下一次遇到相同的查询语句时,直接返回结果。 适用于简单的 SELECT 查询,尤其是少更新、多读取的场景。
默认情况下,SELECT A = 1 的缓存不能直接用于 SELECT A = 1 AND B = 1,因为两者查询条件和结果集不同。
Q:SELECT语句想做查询优化,从哪些方面去优化?
A:答了索引,避免查询不必要的列,数据量过大时从分表三点,问还有补充没,
以下来自gpt
优化 SELECT 语句的方法包括:
- 从表结构设计入手,建立合理的索引,优化字段类型,必要时分表或分区。
- 改进查询语句,减少不必要的字段、行和表,避免复杂计算。
- 提高数据访问效率,利用缓存和分页优化减少查询开销。
- 分析查询执行计划,通过工具发现潜在问题并调整查询结构和索引。
Q:索引的底层结构是啥?
A:说了B+树,然后问只有B+树么?还有其它结构吗,然后又回答了还有哈希
Q:从数据结构的角度来说,能影响B+树的查询性能的,是这个树的什么
A:树高
以下来自gpt
Q:我们怎么影响这个树的高度呢?通过哪些方式让这个树的高度更扁平一点?
A:不知道,瞎几把答了
以下来自gpt
树高主要受以下因素影响:
- 节点扇出数(由节点大小和键值大小决定)。
- 数据分布是否均匀。
- 数据量和磁盘块的大小。
- 键值的大小和排序。
问答18min。手撕环节。差不多三分钟说了一下思路。撕了差不多20min才跑通测试用例,
Q:题目:给中缀表达式转后缀表达式
思路:
- 遇到操作数(数字或变量):直接输出到结果中。
- 遇到左括号
(:直接压入操作符栈。 - 遇到右括号
):- 弹出栈顶的操作符并加入结果,直到遇到左括号(左括号本身不加入结果)。
- 遇到运算符(如
+,-,*,/):- 将栈顶优先级高于或等于当前操作符的运算符弹出并加入结果。
- 然后将当前操作符压栈。
- 遍历结束后:将栈中剩余的运算符依次弹出并加入结果。
算法
1
1 | // 定义运算符优先级 |
2
1 | private static final Map<Character, Integer> precedence = new HashMap<>(); |
3
1 | static { |
4
1 | precedence.put('+', 1); |
5
1 | precedence.put('-', 1); |
6
1 | precedence.put('*', 2); |
7
1 | precedence.put('/', 2); |
8
1 | precedence.put('(', 0); // 左括号优先级最低 |
9
1 | } |
10
1 |
11
1 | public static String infixToPostfix(String infix) { |
12
1 | // 栈:存储操作符 |
13
1 | Stack<Character> operatorStack = new Stack<>(); |
14
1 | // 结果字符串 |
15
1 | StringBuilder postfix = new StringBuilder(); |
16
1 |
17
1 | // 遍历表达式中的每个字符 |
18
1 | for (int i = 0; i < infix.length(); i++) { |
19
1 | char ch = infix.charAt(i); |
20
1 |
21
1 | // 如果是操作数(字母或数字),直接加入结果 |
22
1 | if (Character.isLetterOrDigit(ch)) { |
23
1 | postfix.append(ch); |
24
1 | } |
25
1 | // 如果是左括号,压入栈 |
26
1 | else if (ch == '(') { |
27
1 | operatorStack.push(ch); |
28
1 | } |
29
1 | // 如果是右括号,弹出运算符直到遇到左括号 |
30
1 | else if (ch == ')') { |
31
1 | while (!operatorStack.isEmpty() && operatorStack.peek() != '(') { |
32
1 | postfix.append(operatorStack.pop()); |
33
1 | } |
34
1 | if (!operatorStack.isEmpty() && operatorStack.peek() == '(') { |
35
1 | operatorStack.pop(); // 弹出左括号 |
36
1 | } |
37
1 | } |
38
1 | // 如果是运算符 |
39
1 | else { |
40
1 | // 弹出栈顶优先级大于等于当前运算符的运算符 |
41
1 | while (!operatorStack.isEmpty() && precedence.get(operatorStack.peek()) >= precedence.get(ch)) { |
42
1 | postfix.append(operatorStack.pop()); |
43
1 | } |
44
1 | // 当前运算符压入栈 |
45
1 | operatorStack.push(ch); |
46
1 | } |
47
1 | } |
48
1 |
49
1 | // 遍历结束后,弹出栈中剩余的运算符 |
50
1 | while (!operatorStack.isEmpty()) { |
51
1 | postfix.append(operatorStack.pop()); |
52
1 | } |
53
1 |
54
1 | // 返回后缀表达式 |
55
1 | return postfix.toString(); |
56
1 | } |
美团暑期AI面
2025-03-08
- TCP重传机制有哪些触发条件?超时重传和快速重传的区别?
- 解释Linux管道的概念,给出一个使用管道的例子
- 对explain关键字的理解,包括它的用途如何使用典型输出信息的含义,以及如何利用这些信息进行查询优化
- 自动装箱和拆箱?给出一个例子
- hashCode和equals的关系?为什么要重写hashcode和equals
- 解释Java中的线程,如何创建和启动一个线程
- 设计一个简单的文章热度计算系统考虑浏览量评论数和分享数等因素
- 追问:是否考虑过时间因素对文章热度的影响?比如,一篇文章中发布后的不同时间段内热度的变化情况,如果考虑的话,你会如何将时间因素整合到热度计算中呢?
- 在编程学习中如何处理挫折感和持续保持学习动力的?举一个具体的例子
尖峰合讯 | 上海
2025-03-03
自我介绍
面向对象三大特征,然后分别介绍一下
一个类能不能继承多个类
==和equals的区别
常用集合
ArrayList如何去重
答:借助hashSet
hashmap并发下有什么问题
mybatis的#和 $有什么区别
mybatis如何分页
答:使用limit关键字。还有一个pagehelper插件这个没答到
索引失效有哪些情况
漏答了模糊匹配和表达式计算这两个
拦截器和过滤器的区别(不会
创建线程的方式
runable和callable的区别
start和run有什么区别
能直接调用run方法吗
我用过git哪些命令
然后反问。问了一下进入做什么业务以及可能用到什么技术栈。不过感觉这个可能有点坑,实习到五月底之前不能离职否则有违约金,而且实习生当正式工用。
过了俩小时打电话OC,拒绝了
wxg-企业微信
2025-03-21
就给了三道题,然后面试官人就没了,最后也就做出来一道,直接就结束面试了。。。
1.(mid),给一个含有n个数的数组,然后有一个魔法值(初始为0),依次遍历数组,魔法值可以选择加当前数或者减当前数,加对应UP,减对应DOWN,最后要求魔法值的绝对值最小,还要输出对应的操作(UP,DOWN这些)用的dp通过0.2,实在没思路了这题
2.背包变种(easy),唯一和背包不同的是背包里面物品的重量不能有重复的
3.子序列计数(hard)给n个这样的序列,比如[2,5]对应的是数组{2,3,4,5},[1,3]对应的{1,2,3},然后问n个序列的可能的子序列总共有多少思路是对n个数组求全排列,不过这个和全排列不一样的是,子序列的长度只能为2,没做出来
S线-腾讯hr与管理线
2025-03-31
自我介绍
实习遇到的最大的挑战
(由于做的都是crud,就介绍了一下,然后后续没有展开)
八股
- 进程和线程的区别
- 线程的状态
- 什么是线程安全
- Java里面是怎么保证线程安全的(答的有点乱感觉)
- 线程之间的通信方式
- 数据库的隔离级别,哪种级别可以解决幻读
- 常见的日志类型
- MVCC是什么
- Redis的数据结构
- 持久化机制
- 缓存穿透及其解决方案
- HTTP和HTTPS的区别
- HTTPS加密的过程
- 为什么传输的时候不用非对称加密(答:比对称加密慢。然后又问具体慢多少,这个是唯一没答上来的。。。)
- SQL注入
手撕:
- 最长递增子序列
反问
美云智数 | 佛山
2025-04-10
自我介绍
然后问了一些上段实习的大致情况
- springboot的一些特性(答的感觉不是特别好,就说了ioc,aop和事务管理)
- springboot的自动配置(不会,没看。。)
- bean的生命周期(答的也不太熟悉)
- 切面的作用,实现(实现没答好)
- sql注入
- 讲一下我了解的微服务组件
- sql优化的一些手段或方法
- Redis的数据类型及使用场景
- 分布式锁(详细介绍了自己实现的,然后顺带讲了一点Redisson)
- 然后问了一下用的ai工具
20多分钟结束
下午就oc了
腾讯云智(测开)| 武汉
2025-04-17
自我介绍(提到了平时会记录一些自己的学习过程和遇到的bug,然后面试官问有没有一些bug可以聊一下的,我瞬间傻了,因为记录的bug很少,且确实没什么印象了,随便说了一些然后面试官问这种bug写到博客里面是干啥用的,,,刚开局水晶就裂条缝。。)
然后问了一点之前实习
八股
面相对象三大特征(答的不太流畅)
重载和重写的区别(✅)
然后又问哪些场景会用到重载(❌)
- 构造器重载:多种初始化方式
- 工具类方法:支持多种输入类型或不同参数组合
Java数据类型(浮点型两个忘了答了,给String答上去了,哎,没想好就开始答了!!!❌)
Java中的引用类型(一时也没转过弯来,强软弱虚那四个❌)
springboot的源码有没有看过,spring的原理什么的(答的是通过一个map对bean进行管理)。依赖注入的原理(在运行时可以通过反射获得对象的信息进行一个注入)❌
怎么去理解进程和线程,它们之间的一个差异是什么(这段我的评价是语无伦次,语言能力太差,没组织好语言)一个进程里面可以包含线程,协程吗?(可以),线程里面可以包含进程吗(不能),线程里面可以包含协程吗?(可以)
封包解包的流程(❌)
怎么去理解MySQL的事务,它有哪些特点(持久性答的磕磕绊绊,一致性答的更是一塌糊涂)
举例哪些场景要开启一个事务,如果不开启事务会造成什么样的影响(一个人去取钱,但是由于系统原因数据库没有存储更新的数据,钱却被取走了。然后实在想不出来例子了,他给了一个场景)
用户a和b取同一个账户的钱,取之前要查询余额,这个过程用不用加事务(不用,因为不涉及数据库内容的修改),这时有个c用户往这个账户存了100块钱,如果没有事务,a用户看到的钱是多少呢?(答的是可能会看到c转账之前的余额)问怎么分析的(我说了要看查询的时机,然后又问有没有其他的因素,我说要看c用户这个操作有没有成功执行,问还有呢?说不下去了),然后又换了一个话题,如果把查询和插入都加上事务,会造成什么结果,有什么问题,影响(反问了一个特别蠢的问题,问这俩操作是不是同一个事务,然后面试官说查询和新增可能是同一个接口,查询和新增不可能是一个接口…然后还把问题给忘了。。。又问了一遍,然后还是没想出来),面试官估计到这就判给我“判死刑”了,然后说那我们问一些基础的吧
MySQL的一些语句(连表查询,排序,分组,组合查询(这个想了一会才想起来是union))
Redis数据类型有哪些(✅)
写了一个Java代码,要运行起来经历几个过程(经历哪些程序,才能跑起来)提示可以从Java的运行原理解决这个问题,然后我答了类加载的过程。。。。❌
首先要经过编译器(javac)编译成字节码文件,如果是热点代码就走JIT可以直接运行(保存的有机器码),否则就是由解释器解释成机器码再执行
jvm运行时数据区(✅)
最后一个是测试相关的问题,小程序可以输入三个参数,代表三条边(看录音的时候才发现好像提了个“长度”),返回结果会显示这是不是一个三角形,以及是个什么样的三角形,针对这个小程序去设计一个测试场景, 答三条边是相连的且不平行,某个边和另一个边相连且是终点相交,然后是什么样的三角形可以根据三角形的性质去判断❌
岗位和地点了解吗(安全测开,武汉)
没了。然后光速挂
总结:1.比如在答数据类型那里,答的太快了,没思考好答案就直接答了
2.回答的时候,“额”太多,然后答的不够流畅,语速可以放慢,然后逻辑要清晰,
钛动科技 | 广州 | 一面
2025-06-23
- 介绍了上一段实习
- 产出1-慢查询的排查过程是怎样的(没上线,就说的是测试接口的时候发现慢)
- 为什么离职(第二段实习:内部文档不清晰主要原因,第一段:学校有事情)
- 用过线程池的哪些参数
- 拒绝策略有哪些
- 问项目是不是开源项目,然后我说是学习项目然后做了一些改动,改了哪里为什么改,然后就是异步下单那里由Redis的发布订阅机制改为rabbitmq
- CAS怎么实现的,项目里怎么做的
- bean的生命周期
- 用过哪些Redis的数据类型,zset用在哪些场景,还有哪些数据类型,还有一些高级数据类型(这里答的了解过但没用过)
- Redis为什么快
- 主要还是基于内存操作
- 多路复用机制
- 高效的数据结构
- 了解过Kafka吗
- 介绍一下Rabbitmq呗(讲了一些匹配模式,死信队列,还有broker包括交换机,队列这些)
- 了解过jdk新版本吗(了解21有一个虚拟现场,不过说错了,这个是利于IO频繁的任务,我说成计算频繁的任务了)
- 对于公司内的一些流程有什么想法
反问:
问了一下业务和实习生人数,明天二面
钛动科技 | 广州 | 二面
2025-06-24
回头再补充,OC了正在干
Cider | 广州 | 一面挂
2025-07-24
自我介绍
挑一个经历(实习、项目)介绍一下项目背景,做了什么,难点,怎么解决的
CAS怎么解决的超卖
这种操作有什么问题?
如果竞争比较高的情况下,会产生大量无效重试,造成系统性能下降。但他想问的是ABA问题
ABA问题
我直接说的从业务上避免了,不会出现扣减库存的时候又补充库存这种情况
如果有这种情况(也就是可能出现ABA问题),怎么解决
(实际就是想问的ABA解决方案),然后介绍了一下带版本号的CAS,通过版本可以确认有没有发生ABA
MQ异步下单怎么下单的
这个没答好,有点忘记了
布隆过滤器
布隆过滤器的哈希算法
直接说的不了解,然后面试官又引导到HashMap的哈希算法,就说了那个干扰处理什么高位低位的
session共享问题以及怎么解决的
用token+Redis
如果前端用cookie+Redis能不能解决
这里确实没有考虑过,面试官说这里最关键的问题不在于前端传过来的是cookie或token,而是在于后端存于Redis中还是服务器中
双写一致性问题怎么解决的
先删缓存再更新DB,这里怎么说呢,感觉我俩讨论的有点混乱
为什么不采用先更新缓存再更新数据库这种策略呢?
答了一个可能会造成无效写比较多,比如现在更新了一个缓存,但DB还没更新完,又来了一个更新操作,导致之前的缓存更新没用上就又要再次更新;
然后问还有呢,不知道
然后他说删除比较快,更新慢。。。
为什么不先更新数据库再删缓存呢?
还是往时序问题那上面答的,但好像不是他想要的答案
他说主要这两个操作不能保证同时成功或失败,如果先更新数据库,再删除缓存,更新数据库成功了,删缓存失败,会导致读到脏数据。如果是先删除缓存,再更新数据库,删缓存失败了,更新
Java的新特性
就说了虚拟线程,利于IO操作;然后又问为什么虚拟线程相比平台线程可以提高IO效率
jdk17的模式匹配有了解过吗
JVM的垃圾收集器知道哪些
说了CMS和G1,ZGC这个不了解
然后现场写代码,可用ai辅助,跑通了测试接口
给你一个ChatGPT接口,要求实现一个功能,传递一段代码,返回单元测试用例。
基本要求:实现HTTP接口进阶要求:提供更好的体验,比如实现一个简单的HTML页面等
如何验收:如果有实现完整功能,则直接演示;如果只实现了接口,则需要提供一个接口,给你一段代码,在postman等工具跑通接口;
Deepseek API Key: sk-bbdaa0a47e00495f9dbbe293eee210a0API文档:https://api-docs.deepseek.com/zh-cn/
接口测试请求参数:
1 | { |
商汤 | 深圳 | 一面
2025-09-02
自我介绍(不知道为什么面试官那里拿到的还是我上个版本的简历,尴尬,那个里面Redis都写错了)
实习/项目中遇到的困难,或者说觉得比较有亮点的东西 (这个问题要好好准备一下,怎么和上次cider面试官的起手动作一样都是问这个)
A:介绍的是项目中,引入mq提升响应速度,然后一个顺序消费,只答到了Topic模式下的tag来实现,具体怎么做的没答好,不太熟这块
消费方收到消息如何处理幂等✅
A:数据库层面——联合唯一索引
在数据库层面处理还要处理后才知道是重复消息,有没有办法在处理之前就给它排除掉?✅
A:消息ID,消费之前判断消息有没有被消费过;或者用Redis缓存消息ID,如果存在就说明消费过了
然后又问我如何保证顺序执行的?❌
A:这个我是真没招了,忘了。因为我一开始说的是预期是ABA执行,有可能是AAB执行,这样就混乱了,后面就开始问八股了
线程怎么停止?❌——已解决
A:这个还真忘了。。。答了interupt,然后真不知道了,给wait都答上去了😅面试官还贴心的指出interupt不会停止线程,只是会中断IO
synchronized加到类的成员方法和静态方法有什么区别?✅
A:知道那个意思,但答的感觉不太好,没梳理好语言。另外它们之间不会产生互斥。因为使用的是不同的锁,一个线程可以同时进入一个对象的同步实例方法和一个同步静态方法。
synchronized和Lock的区别✅——已完善
A:从实现方式,公平锁,可中断三个方面答的
Springbean的生命周期✅——已完善
A:实例化——属性赋值——初始化——销毁
如果想用springboot在启动后初始化一些东西,怎么实现?❌❌❌❌❌
A:一开始想答spring-boot-starer的,但感觉那个不是初始化环境的吗,没答
你知道springcloud的哪些组件?✅❌——已了解
A:注册中心nacos,网关gateway,服务调用feign,没了,又问其他组件,没答出来,估计是想问seata(分布式事务)
有没有了解熔断器的一些原理❌
A:没用过,答了可以停止服务
Redis的数据结构✅
A:五种基础数据结构
Hash有哪些操作方法❌——问的有点细了吧
A:hput。。。
Redis有哪几种部署方式,工作机制❌——已解决
A:集群,主从什么的,答的看过忘了
持久化方式有哪几种✅
A:答了三种
AOF方式会不会丢数据,什么情况下会丢数据呢?❌——已解决
A:答的可能最后一条命令没有写AOF日志,Redis宕机,丢失这条命令,但感觉面试官好像并不满意这个答案,好像不对。是回答错了
优化SQL语句会从哪些方面入手✅
A:索引,查询字段,避免深度分页,优化表结构或者分库分表
创建索引的原则✅
A:数据量够多,区分度大,联合索引符合最左前缀匹配原则
反问,做什么业务,有几面。全程差不多30min
秋招第一面 | 浙江大华 | 一面
自我介绍(被评价“还挺简洁的”)
volatile关键字有什么作用?✅
A:Volatile 主要用于并发编程中,保证共享变量的可见性,同时防止指令重排序,避免因指令重排序导致运算结果混乱,主要就是这两个作用。
怎么防止指令重排序的?✅
A:它通过在代码前后插入内存屏障,来防止指令重排序。
这个关键字修饰的变量是线程安全的吗?✅
A:不是,因为它不能保证原子性。
ThreadLocal 是怎么解决线程安全问题的? ✅
A:它通过为每个线程分配一个本地的局部变量,避免对共享变量的竞争,从而解决线程安全问题。
平时使用 ThreadLocal 的时候有什么需要注意的吗?✅
A:需要注意手动 remove ThreadLocal 对象,否则可能会引起内存泄露。因为 ThreadLocal 底层使用的是 ThreadLocalMap,其 key 是 ThreadLocal 实例的弱引用,value 是我们保存变量的强引用,不手动 remove 就可能导致内存泄露。
有了解雪花算法吗?介绍一下。 ❌
A:雪花算法我了解不多,结构有点忘了,它好像可以解决分布式环境下同一时间出现重复 ID 的问题,是常用的分布式 ID 生成方式之一。
Redis 中 key 经常有过期时间,它的失效策略有哪些?❌(太可惜了这个,第一种策略是给每个设置过期时间的key设置一个定时器,到时间立即清除)
A:第一种是每隔一段时间对过期的 key 进行删除;第二种是惰性删除,只有访问到 key 时,发现它过期了才会删除;第三种是定期删除,每隔一段时间扫描一定批量的 key,剔除其中过期的 key。
数据库中 CHAR 和 VARCHAR 有什么区别?一般如何选择? ❌
A:CHAR 是固定长度的字符串类型,VARCHAR 是可变长度的字符串类型,VARCHAR 尾部会用空格填充。如果字段是固定长度,一般用 CHAR;如果字段长度不固定,一般用 VARCHAR。
既然 VARCHAR 使用灵活,不容易出问题,是不是 CHAR 就没用了?选 CHAR 有什么好处吗? ❌
A:CHAR 更节省空间,空间利用率更高,还能让数据排列更规整。
MyBatis 里面 #号和 $ 符有什么区别? ✅
A:#号生成预编译 SQL 语句时,会生成占位符来填充传入的数据;$ 符会直接拼接传入的数据,如果用户恶意输入,可能会有 SQL 注入问题,用 #号可以避免这个问题。
什么场景下可以选择 $ 符? ✅❌(对又不太对)
A:不涉及安全性问题的时候应该可以用,但一般情况下都是直接用 #号。
DSA:“在参数是SQL语法本身的一部分而非用户输入的值,且参数值来源绝对安全、可控(如来自系统内部配置或经过严格白名单校验)时,才可以使用$。”
现有一个工程,里面有 1000 个以前写的未加日志的接口,现在想给所有接口加出入参日志,怎么实现? ✅
A:可以用 AOP(面向切面编程),先扫描接口,然后打印出入参信息。
用 AOP 实现加日志后,额外需求是:部分接口出参很大(如大列表),打印日志有压力,想选择性地让某些接口不打印出参日志,该怎么做? ✅❌(对但不够优雅,不完全对吧算是)
A:可以设计另一种切面,把不需要打印出参日志的接口和需要打印的接口独立开来,用不同的切面分别处理,不需要打印出参日志的接口就用新设计的切面。
DSA:
首选方案是使用自定义注解。我会定义一个
@NoReturnLog的注解。在切面的@Around通知中,通过反射判断当前执行的方法是否带有这个注解。如果带了,就在最后打印日志时跳过出参的打印,只打印方法执行完毕的信息。这样做的优点是控制精确、代码无侵入、非常灵活,并且只需要维护一个切面。通过配置中心或配置文件动态控制
如果希望不修改代码就能动态开关某些日志,可以采用配置方案。
具体做法:
- 在应用配置文件(如
application.yml)或配置中心里,定义一个列表,存放需要禁用出参日志的方法全限定名。 - 在切面中,注入这个配置列表。
- 判断当前执行的方法名是否在“禁用列表”中。
优点:可以动态配置,无需重启应用。
缺点:配置起来比较麻烦,需要写完整的方法名,不如注解直观。- 在应用配置文件(如
在原有切点表达式中排除(简单但不够灵活)
你可以修改切点表达式,直接排除掉那些已知的、出参很大的方法。
1
2
3
public void apiPointcut() {}优点:实现简单。
缺点:非常不灵活。硬编码在切点里,每增加一个方法都要修改切面代码,难以维护。不适用于大量方法。
设计一个分布式系统的共享配置服务,从零实现,没有现成组件,打算怎么去做? (开放性题目,就让我随便说说)
A:这可能涉及配置中心的底层原理,我不太了解,只能猜想一下。可以搭建一个统一的服务器,在服务器上统一编写配置信息,各个机器启动时,从这个服务器注入配置信息。另外,现在有 Nacos、阿波罗等成熟组件,自己实现的话可能也是类似的思路。
简单介绍一下在广州泰动科技的实习项目,做了什么业务?
项目中提到高并发场景下 DB 和缓存不一致的问题,缓存指的是 Redis 吗?怎么解决不一致的?Redis 里的数据是从 DB 查一遍放进去的吗?
时长约18min,无反问
秋招第二面 | ??? | 一面
自我介绍
你能简单阐述一下 HashMap 以及 ConcurrentHashMap 的底层实现原理以及它们两个的主要区别吗? ✅
简述 ArrayList 和 LinkedList 的区别以及它们的底层实现,ArrayList 和 LinkedList 各自的使用情况是什么? ✅
能阐述一下 JVM 内存模型包括哪些吗? ❌
A:回答错了,回答成JVM的组成了,
new 一个对象,它会存在 JVM 内存模型的哪一块区域? ✅
简述类加载的过程 ✅
索引类型有哪些? ✅
创建表时用多个字段创建索引,这种索引类型叫什么? ✅
使用联合索引需要注意哪些事项? ✅
深分页怎么解决✅
RocketMQ 和 RabbitMQ 的主要区别是什么? ✅
Redis 常用的数据类型以及它们对应使用的情景有哪些? ✅
在广告中心混量交付平台项目中,主要负责哪些模块或者功能的开发?
分页查询为什么会有性能瓶颈啊?
面试官建议:简历上写的实习内容没有深入了解,比如
- DB和MQ异步刷新解决了什么问题,怎么去做的实现(这些都没有提到)
- 工厂和策略模式,可以说一些涉及的核心的类,增加可信度
为什么用消息队列去更新Redis呢?
如果在执行失败的线程中一直重试,还没等执行成功,此时如果项目「重启」了,那这次重试请求也就「丢失」了,那这条数据就一直不一致了。
所以,这里我们必须把重试或第二步操作放到另一个「服务」中,这个服务用「消息队列」最为合适。这是因为消息队列的特性,正好符合我们的需求:
- 消息队列保证可靠性:写到队列中的消息,成功消费之前不会丢失(重启项目也不担心)
- 消息队列保证消息成功投递:下游从队列拉取消息,成功消费后才会删除消息,否则还会继续投递消息给消费者(符合我们重试的场景)
至于写队列失败和消息队列的维护成本问题:
- 写队列失败:操作缓存和写消息队列,「同时失败」的概率其实是很小的
- 维护成本:我们项目中一般都会用到消息队列,维护成本并没有新增很多