大家好,我是小林。
今天分享一位同学面试上海某游戏公司的面经,同学的技术栈是Java后端,虽然不是大厂,但是一面面试也被问了 25 多个问题,时长也接近 1 小时了
面试过程中,也问到了 Linux socket 编程,游戏公司都会对网络协议和网络编程这一块要求比较高,所以投游戏公司的同学,需要重点准备网络方面的知识。
还有一点,游戏公司的开发岗除了技术要求之外,可能还会问你一下你对游戏的兴趣,平常玩什么游戏,对游戏有什么看法,因为工作内容就是开发游戏,如果对游戏没有热情,会觉得工作缺失了激情。
问题记录
介绍你的项目
balabal 了几分钟
Redis 缓存一致性
说了旁路缓存策略
如果这个时候一波海量请求,你怎么保证他们能读到数据
说说Redis 数据结构
Redis 有五大基本数据类型和四大新类型
五大基本类型是:
每一种数据结构根据自身的特性有不同的使用场景:
计数器,因为 Redis 是单线程模型的,所以redis执行命令时原子性,所以他可以用来做计数器,例如 点赞计数、转发、库存数量等
分布式锁:setnx key value ex 时间
Hash 是 key-value 键值对,类似与 Java 的 HashMap, 查找时间复杂度是 o(l)
Hash 的底层数据结构是hashtale 和压缩表
当 元素个小于 512 并且所有元素大小小于 64 字节,采用压缩列表作为底层数据结构
反之采用 hashtable
它适合做购物车,用户作为 id、商品 id 位 field、商品数量为 value
List (说到 List 被面试面试官打断了,下一个)
事务了解吗?
了解,acid 事务四大特性说了一遍
事务隔离级别有哪几种
读未提交
读已提交
可重复读
串行话
追问:隔离级别是由啥保证的
可重复读为什么完全不能解决幻读
在可重复读隔离级别下,事务 A 第一次执行普通的 select 语句时生成了一个 ReadView,之后事务 B 向表中新插入了一条 id = 5 的记录并提交。接着,事务 A 对 id = 5 这条记录进行了更新操作,在这个时刻,这条新记录的 trx_id 隐藏列的值就变成了事务 A 的事务 id,之后事务 A 再使用普通 select 语句去查询这条记录时就可以看到这条记录了,于是就发生了幻读。
图片
因为这种特殊现象的存在,所以我们认为 MySQL Innodb 中的 MVCC 并不能完全避免幻读现象。
进程与线程的区别
常规八股
线程池有哪几个类型的
只有一个核心线程,也是最大线程数。队列采用的是 LinkedblockingQueue 无界阻塞队列。极端情况下会有 OOM 问题
它的工作原理是当提交任务是当没有工作线程时,会将任务放入到阻塞队列中,
有核心线程时,获取阻塞队列取任务执行,执行完了接着从阻塞队列执行
Keepalive存活时间是 0,因为本来就没有非核心线程
它的场景是串行化的场景,因为他只有一个工作线程
核心线程数是 0,队列采用的是 SynchrousQueue 阻塞队列。最大线程数是 Integer.Max_value 的默认值,KeepAiveTime 是 60 s,也就是线程执行完了处于空闲状态时,过 60 s 就会销毁,如果频繁的创建线程会产生 OOM 问题
它的工作原理是提交任务,没有线程时,任务放到阻塞队列
创建核心线程时取队列执行任务,插入一个元素必须等工作线程取出消费,如果队列没有任务则会阻塞
它的吞吐量比 newFixedExecutor 更高,它适用于并发量大但是任务执行周期短的场景
newFixedExecutor
SheculedExecutor
周期性去执行任务。队列是 DeayQueue 延迟队列,
它的工作原理是 当工作线程数小于最大线程数,首先会去创建线程去执行任务
当达到核心线程数时,会将任务放入到阻塞队列,
所谓周期性就是 他去任务队列取出任务时,会修改一个 time 变量 位下次要执行的时间
然后放入到队列中
说说各层有哪些协议
说说一个数据怎么在网络各层分割报文的
发送数据方
讲讲 TCP 三次握手
你刚刚说的 Listen、SYN_SENT、SYN_RCVD、ESTABLISHED 状态有什么含义?
客户端发送了数据给服务端,服务端返回对方成功确认收到的确认信息,这个时候是否可以肯定服务端收到了数据
那怎么解决这个问题呢?
客户端想尽快关闭连接,应该怎么办?
Socket 编程了解过吗,什么是 socket
socket 的流程
不会(我搞 java 的,没研究过 socket 编程,完了)
基本 socket 做好了封装,你了解吗
刚开始懵逼,后来想到才是 Netty 这个框架
Socket 和 http 有什么区别?
你说说 spring 的生命周期?
大致分为五个阶段,创建前准备阶段、实例化阶段、依赖注入阶段、容器缓存阶段、实例销毁阶段
后面从说了每个阶段是干嘛的(面试官反应逻辑讲的不够清楚,这里我就不列出来的)
事后复习总结如下:
Spring 启动后,扫描 @ComponentScan 注解配置的路径下的所有 .class 文件,
类加载其根据类名加载获取类的 Class 对象
判断类上是否有 @Component、Service 等注解找出 bean 对象
给每个符合条件的 bean 创建 BeanDefintion 对象用于存放 Class 对象、作用域等信息,作用域包括 singletion、prototype、request 等,然后添加进 beanDefinitionMap, key 值存放 bean 的名字,value 是对应的 BeanDefition
扫描 bean 对象
遍历 beanDefinitionMap,创建
MyBatis 中 ${} 与 #{} 的区别
感觉
面试官说我们是做游戏开发,然后又问我你平时喜欢打游戏吗,我说近些年很少打游戏的。以前很喜欢玩,后面觉得腻了,然后面试官说做游戏开发需要对游戏很了解的,对游戏很热爱的,否则难干下去
反问环节说我基础还算行,就是可能在业务方面可能不匹配
不足之处
socket编程不太熟悉,计网还需加强学习
Spring bean 的生命周期 没有让面试官听懂