科⼤讯⻜⼀⾯
科⼤讯⻜ Java ⾯试
正好,这⼏天看到科⼤讯⻜陆陆 续续 开奖了,科⼤讯⻜⾯试流程在 8 ⽉份就开始了,不少同学泡
了 1-2 个⽉,才开奖出来。
科⼤讯⻜办公地点是在合肥,25 届开发岗位的校招薪资,⼤概如下:

普通档:22k 〜 23k x 14 = 30w 〜32w (⼤部分⼈)
sp offer 档:26k x 14 = 36w
ssp offer 档:30k x 14 = 42w如果是研究⽣的话,合肥⼈才租房补贴⼀年 2w ,可以连续拿 3 年。
在合肥⼆线城市⼯作,拿接 近⼀线⼤⼚的薪资,简直不要太⾹了,性价⽐不要太⾼了!
话说回来,科⼤讯⻜的⾯试难度如何?
这次,就跟⼤家分享今 年秋招,科⼤讯⻜Java 后端开发的⾯经,这是⼀⾯,主要也是以技术拷打为主了 ,考察的知识点主要有 Java 并发编程、Java 集合、MySQL 、Redis 、Linux 命令,Nginx 。
我看了不 少科⼤讯⻜的⾯经,除了基本⼋股之外,还有⼀个特点,喜欢问⼀些Linux 命令和场景问
题的排查,这部分偏向实践,估计⾯试官希望招能直接⼲活的⼈。

科⼤讯⻜⼀⾯
sycronized 和locked 的区别?
Synchronized 编码更简单,锁机制由JVM 维护,在竞争不 激烈的情况下性能更好。Lock 功能更强⼤
更灵活,竞争激烈时性能较好。
区别如下:
来源:lock 是⼀个接⼝,⽽ synchronized 是java 的⼀个关键字, synchronized 是内置的语⾔
实现;
异常是否释放锁: synchronized 在发⽣异常时候会⾃动释放占有的锁,因此不会出现死锁;⽽
lock 发⽣异常时候,不会主动释放占有的锁,必须⼿动unlock 来释放锁,可能引起死锁的发⽣。
(所以最好将同步代码块⽤ try catch 包起来,finally 中写⼊unlock ,避免死锁的发⽣。)
是否响 应中断lock 等待锁过程中可以⽤ interrupt 来中断等待,⽽ synchronized 只能等待锁的
释放,不能响应中断;
是否知道获取锁:Lock 可以通过 trylock 来知道有没有获取锁,⽽ synchronized 不能;
Lock 可以提⾼多个线程进⾏读操作的效率。(可以通过 readwritelock 实现读写分离)
在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,⽽当竞争资源⾮常激烈时(即
有⼤量线程同时竞争),此时Lock 的性能要远远 优于 synchronized 。
hashmap put 的流程

HashMap HashMap 的put() ⽅法⽤于向HashMap 中添加键值对,当调⽤HashMap 的put() ⽅法时,会按照以下详细流程执⾏(JDK8 1.8 版本):第⼀步:根据要添加的键的哈希码计算在数组中的位置(索引)。
第⼆步:检查该位置是否为空(即没有键值对存在)
如果为空,则直接在该位置创建⼀个新的Entry 对象来存储键值对。将要添加的键值对作为该
Entry 的键和值,并保存在数组的对应位置。将HashMap 的修改次数(modCount )加1,以便 在
进⾏迭代时发现并发修改。
第三步:如果该位置已经存在其他键值对,检查该位置的第⼀个键值对的哈希码和键是否与要添
加的键值对相同?
如果相同,则表⽰找到了相同的键,直接将新的值替换旧的值,完成更新操作。
第四步:如果第⼀个键值对的哈希码和键不相同,则需要遍历链表或红⿊树来查 找是否有相同的
键:
如果键值对集合是链表结构,从链表的头部开始逐个⽐较键的哈希码和equals() ⽅法,直到找到相同的键或达到链表末尾。
如果找到了相同的键,则使⽤新的值取代旧的值,即更新键对应的值。
如果没有找到相同的键,则将新的键值对添加到 链表的头部。
如果键值对集合是红⿊树结构,在红⿊树中使⽤哈希码和equals() ⽅法进⾏查找。根据键的哈希码,定位到红⿊树中的某个节点,然后逐个⽐较键,直到找到相同的键或达到红⿊树末尾。
如果找到了相同的键,则使⽤新的值取代旧的值,即更新键对应的值。
如果没有找到相同的键,则将新的键值对添加到 红⿊树中。
第五步:检查链表⻓度是否达到阈值(默认为8):
如果链表⻓度超过阈值,且HashMap 的数组⻓度⼤于等于64 ,则会将链表转换为红⿊树,以提
⾼查询效率。
第六步:检查负载因⼦是否超过阈值(默认为0.75 ):
如果键值对的数量(size )与数组的⻓度的⽐值⼤于阈值,则需要进⾏扩容操作。
第七步:扩容操作:
创建⼀个新的两倍⼤⼩的数组。
将旧数 组中的键值对重新计算哈希码并分配到新数 组中的位置。
更新HashMap 的数组引⽤和阈值参数。
第⼋步:完成添加操作。
此外,HashMap 是⾮线程安全的,如果在多线程环境下使⽤,需要采取额外的同步措施或使⽤线
程安全的ConcurrentHashMap 。
avl 树和红⿊树的区别?
平衡⼆叉树追求的是⼀种 “完全平衡” 状态:任何 结点的左右⼦树的⾼度差 不会超过 1,优势是
树的结点是很平均分配的。这个要求实在是太严了 ,导致每次 进⾏插⼊/删除节点的时候,⼏乎
都会破坏平衡树的第⼆个规则,进⽽我们都需要通过左旋和右旋来进⾏调整,使之再次成为⼀
颗符合要求的平衡树。
红⿊树不追求这种完全平衡状态,⽽是追求⼀种 “弱平衡” 状态:整个树最⻓路径不会超过最短
路径的 2 倍。优势是虽然牺牲 了⼀部分查找的性能效率,但是能够换取⼀部分维持树平衡状态
的成本。与平衡树不同的是,红⿊树在插⼊、删除等操作,不会像平衡树那样,频繁着破坏红
⿊树的规则,所以不需要频繁着调整,这也是我们为什么 ⼤多数情况下使⽤红⿊树的原因。
红⿊树插⼊的时间复杂度是多少?
红⿊树平衡,插⼊、删除、查找操作的时间复杂度都是O(logn) 。如何给数据库中数据加⾏级锁?
InnoDB 引擎是⽀持⾏级锁的,⽽ MyISAM 引擎并不⽀持⾏级锁。
普通的 select 语句是不会对记录加锁的,因为它属于快照读。如果要在查询时对记录加⾏锁,可
以使 ⽤下⾯这两个 ⽅式,这种查询会加锁的语句称为锁定读。
//对读取的记录加共享锁
select ... lock in share mode;
//对读取的记录加独占锁
select ... for update;上⾯这两条语句必须在⼀个事 务中,因为当事务提交了 ,锁就会被释放,所以在使⽤这两条语句
的时候,要加上 begin 、start transaction 或者 set autocommit = 0 。共享锁(S锁)满⾜读读 共享,读写互斥。独占锁(X锁)满⾜写写 互斥、读写互斥。

⾏级锁的类型主要有三类:
Record Lock ,记录锁,也就是仅仅 把⼀条记录锁上;
Gap Lock ,间隙 锁,锁定⼀个范围,但是不包含记录本⾝;
Next-Key Lock :Record Lock + Gap Lock 的组合,锁定⼀个范围,并且锁定记录本⾝。
Record Lock
Record Lock 称为记录锁,锁住的是⼀条记录。⽽且记录锁是有 S 锁和 X 锁之分的:
当⼀个事 务对⼀条记录加了 S 型记录锁后,其他事 务也可以继续对该记 录加 S 型记录锁(S 型
与 S 锁兼容),但是不可以对该记 录加 X 型记录锁(S 型与 X 锁不兼容);当⼀个事 务对⼀条记录加了 X 型记录锁后,其他事 务既不可以对该记 录加 S 型记录锁(S 型与
X 锁不兼容),也不 可以对该记 录加 X 型记录锁(X 型与 X 锁不兼容)。
举个 例⼦,当⼀个事 务执⾏了下 ⾯这条语句:
mysql > begin;
mysql > select * from t_test where id = 1 for update;就是对 t_test 表中主 键 id 为 1 的这条记录加上 X 型的记录锁,这样其他事 务就⽆法对这条记录进
⾏修改了。

当事务执⾏ commit 后,事务过程中⽣成的锁都会被释放。
Gap Lock
Gap Lock 称为间隙 锁,只存在于可重复读隔离级别,⽬的是为了 解决可重复读隔离级别下幻读的
现象。
假设,表中有⼀个范围 id 为(3,5)间隙 锁,那么其他事 务就⽆法插⼊ id = 4 这条记录了,这样就有效的防⽌幻读现象的发⽣。

间隙 锁虽然存在 X 型间隙 锁和 S 型间隙 锁,但是并没有什么 区别,间隙 锁之间是兼容的,即两个 事务可以同时持有包含共同间隙 范围的间隙 锁,并不存在互斥关系,因为间隙 锁的⽬的是防⽌插
⼊幻影记录⽽提出的。
Next-Key Lock
Next-Key Lock 称为临 键锁 ,是 Record Lock + Gap Lock 的组合,锁定⼀个范围,并且锁定记录本
⾝。

假设,表中有⼀个范围 id 为(3,5] 的 next-key lock ,那么其他事 务即不能插⼊ id = 4 记录,也不能修改 id = 5 这条记录。所以,next-key lock 即能保护该记 录,⼜能阻⽌其他事 务将新纪录插⼊到被保护记录前⾯的间隙
中。
next-key lock 是包含间隙 锁+记录锁的,如果⼀个事 务获取了 X 型的 next-key lock ,那么另外⼀
个事 务在获取相同范围的 X 型的 next-key lock 时,是会被阻塞的。
⽐如,⼀个事 务持有了范围为 (1, 10] 的 X 型的 next-key lock ,那么另外⼀个事 务在获取相同范围的 X 型的 next-key lock 时,就会被阻塞。
虽然相同范围的间隙 锁是多个事 务相互兼容的,但对于记录锁,我们是要考虑 X 型与 S 型关系,X
型的记录锁与 X 型的记录锁是冲突的。
如果和redis ⽆法连接,如何排查原因?
⽹络闪断:先排查⽹络问题,⽐如检查⽹络连接是否正常。确保⽹络连接稳定,没有断开或中
断。检查⽹络带宽是否耗尽。如果⽹络带宽达到极限,可能会导致闪断。你可以联系⽹络管理
员或提供商以解决带宽问题。
Redis 连接拒绝:确认maxclients 设置。在Redis 配置⽂件(redis.conf) 中,找到maxclients 设置项,确保其值⾜够⼤以容纳你的并发连接数。你可以通过修改配置⽂件来增加maxclients 的值。
连接溢出:进程可打开的最⼤⽂件数控制(ulimit -n) 是限制系统中同时存在的⽂件描述符数量的设置。对于Redis 来说,⾼并发情况下需要处理⼤量的连接,因此需要增⼤该值。
如果redis 内存不⾜,你认为是什么 原因
没有开启内存淘汰策略,导致 Redis ⽆法运⽤内存淘汰策略来淘汰不常⽤的内存数据。
在 Redis ⻓时间运⾏的情况下,由于频繁的插⼊和删除操作,可能会导致内存碎⽚,导致可⽤
内存减少。
单 Redis 节点的内存⽆法扛住激增的⽤⼾数据,这时候需要考虑构建 Redis 集群来应对内存不
⾜的问题。
为什么 redis 购物⻋⽤hash 不⽤ string
使⽤ Hash 类型来实现购物⻋有⼏个明显 的优势,相⽐使⽤ String 类型:
结构化数据:Hash 类型允许将购物⻋中的每个商品表⽰为⼀个字段-值对(field-value pair ),
其中字段可以是商品的 ID ,值可以是商品的数量或其他属性。这种结构化可以使 得数据更加清
晰和易于管理
节省内存:在 Redis 中,Hash 类型对于存储⼩数量的字段-值对(例如购物⻋中的商品)通常
会使 ⽤更⾼效的内存编码⽅式。当 Hash 中的成员少于⼀定数量时,Redis 会使 ⽤压缩算法来减
少内存消耗。
操作灵活性:使⽤ Hash 类型,你可以对购物⻋进⾏更复杂的操作,⽐如只更新某个商品的数
量,⽽不需要将整个购物⻋类型的数据取出和再存储。对于多个购物⻋的操作,Hash 可以显著
提⾼效率。
⽅便查询与修改:使⽤ Hash 类型的购物⻋,可以更⽅便地查询和修改特定商品的信息,例如
获取某个商品的数量,⾮常简单,只需要进⾏⼀次 HGET 操作。
讲⼀下Nginx 的负载均衡策略
Nginx ⽀持的负载均衡算法包括:
轮询:按照顺序依次将请求分配给后端服务器。这种算法最简单,但是也⽆法处理某个节点变
慢或者客⼾端操作有连续性的情况。
IP 哈希:根据客⼾端IP 地址 的哈希值来确定分配请求的后端服务器。适⽤于需要保持同⼀客⼾端
的请求始终发送到同⼀台后 端服务器的场景,如会话保持。
URL 哈希:按访问的URL 的哈希结果来 分配请求,使每个URL 定向到⼀台后 端服务器, 可以进⼀
步提⾼后端缓存服务器的效率。
最短响应时间:按照后端服务器的响应时间来分配请求,响应时间短的优先分配。适⽤于后端
服务器性能不均的场景,能够将请求发送到响应时间快的服务器, 实现负载均衡。
加权轮询:按照权重分配请求给后端服务器, 权重越⾼的服务器获得更多的请求。适⽤于后端
服务器性能不同的场景,可以根据服务器权重分配请求,提⾼⾼性能服务器的利⽤率。
linux 命令怎么看 cpu 占⽤率?
可以通过 top 命令来查 看系统的 cpu 占⽤率和各 个进程的 cpu 占⽤率。

死锁的时候cpu 利⽤率是⾼还是低?为什么 ?
这个关键是看⽤了什么 锁:
如果是⽤了⾃旋锁,拿不到锁的时候,忙等待,反复探测锁状态,直到拿到锁,进⼊临界区,
这种情况会消耗CPU ,如果发⽣死锁的话,cpu 利⽤率就会⽐较⾼。
如果是互斥锁,拿不到锁就让线程休眠的,这时候就相当于放弃了 cpu ,不会消耗 cpu ,如果
发⽣死锁的话,cpu 利⽤率就不会升⾼的。
linux 命令怎么看进程占⽤的端⼝?
可以通过 lsof 或者 netstate 命令查看,⽐如查看 80 端⼝。
lsof :
[root@xiaolin ~]# lsof -i :80COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 929 root 6u IPv4 15249 0t0 TCP *:http (LISTEN)
nginx 929 root 7u IPv6 15250 0t0 TCP *:http (LISTEN)
nginx 934 nginx 6u IPv4 15249 0t0 TCP *:http (LISTEN)netstate :
[root@xiaolin ~]# netstat -napt | grep 80tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 929/nginx: master p
