上海某游戲小廠面試,也扛不住了...
大家好,我是小林。
今天分享一位同學(xué)面試上海某游戲公司的面經(jīng),同學(xué)的技術(shù)棧是Java后端,雖然不是大廠,但是一面面試也被問(wèn)了 25 多個(gè)問(wèn)題,時(shí)長(zhǎng)也接近 1 小時(shí)了
面試過(guò)程中,也問(wèn)到了 Linux socket 編程,游戲公司都會(huì)對(duì)網(wǎng)絡(luò)協(xié)議和網(wǎng)絡(luò)編程這一塊要求比較高,所以投游戲公司的同學(xué),需要重點(diǎn)準(zhǔn)備網(wǎng)絡(luò)方面的知識(shí)。
還有一點(diǎn),游戲公司的開(kāi)發(fā)崗除了技術(shù)要求之外,可能還會(huì)問(wèn)你一下你對(duì)游戲的興趣,平常玩什么游戲,對(duì)游戲有什么看法,因?yàn)楣ぷ鲀?nèi)容就是開(kāi)發(fā)游戲,如果對(duì)游戲沒(méi)有熱情,會(huì)覺(jué)得工作缺失了激情。
問(wèn)題記錄
介紹你的項(xiàng)目
balabal 了幾分鐘
Redis 緩存一致性
說(shuō)了旁路緩存策略
如果這個(gè)時(shí)候一波海量請(qǐng)求,你怎么保證他們能讀到數(shù)據(jù)
- 數(shù)據(jù)延遲肯定是有的
 - 我個(gè)人認(rèn)為可以做流量控制,限制讀請(qǐng)求數(shù)量
 - 當(dāng)然,如果非的讀的話??梢圆捎冒褎h除緩存策略改為更新緩存策略
 
說(shuō)說(shuō)Redis 數(shù)據(jù)結(jié)構(gòu)
Redis 有五大基本數(shù)據(jù)類型和四大新類型
五大基本類型是:
- String
 - Hash
 - List
 - Set
 - zset
 
每一種數(shù)據(jù)結(jié)構(gòu)根據(jù)自身的特性有不同的使用場(chǎng)景:
- string:
 
計(jì)數(shù)器,因?yàn)?Redis 是單線程模型的,所以redis執(zhí)行命令時(shí)原子性,所以他可以用來(lái)做計(jì)數(shù)器,例如 點(diǎn)贊計(jì)數(shù)、轉(zhuǎn)發(fā)、庫(kù)存數(shù)量等
分布式鎖:setnx key value ex 時(shí)間
- hash:
 Hash 是 key-value 鍵值對(duì),類似與 Java 的 HashMap, 查找時(shí)間復(fù)雜度是 o(l)
Hash 的底層數(shù)據(jù)結(jié)構(gòu)是hashtale 和壓縮表
當(dāng) 元素個(gè)小于 512 并且所有元素大小小于 64 字節(jié),采用壓縮列表作為底層數(shù)據(jù)結(jié)構(gòu)
反之采用 hashtable
它適合做購(gòu)物車(chē),用戶作為 id、商品 id 位 field、商品數(shù)量為 value
List (說(shuō)到 List 被面試面試官打斷了,下一個(gè))
事務(wù)了解嗎?
了解,acid 事務(wù)四大特性說(shuō)了一遍
事務(wù)隔離級(jí)別有哪幾種
- 四種
 
讀未提交
讀已提交
可重復(fù)讀
串行話
- 讀未提交就是一個(gè)A事務(wù)能讀到另一個(gè)B事務(wù)未提交的事務(wù),當(dāng)這個(gè)B事務(wù)發(fā)生回滾時(shí), A 事務(wù)讀到的是臟數(shù)據(jù)。它有臟讀、不可重復(fù)讀、幻讀問(wèn)題
 - 讀已提交就是只能讀到對(duì)方事務(wù)已經(jīng)提交的事務(wù),它解決了臟讀問(wèn)題,但是有不可重復(fù)讀和幻讀問(wèn)題(說(shuō)到這里突然被面試官打斷)
 
追問(wèn):隔離級(jí)別是由啥保證的
- mvvc 機(jī)制 和 鎖機(jī)制
 
可重復(fù)讀為什么完全不能解決幻讀
在可重復(fù)讀隔離級(jí)別下,事務(wù) A 第一次執(zhí)行普通的 select 語(yǔ)句時(shí)生成了一個(gè) ReadView,之后事務(wù) B 向表中新插入了一條 id = 5 的記錄并提交。接著,事務(wù) A 對(duì) id = 5 這條記錄進(jìn)行了更新操作,在這個(gè)時(shí)刻,這條新記錄的 trx_id 隱藏列的值就變成了事務(wù) A 的事務(wù) id,之后事務(wù) A 再使用普通 select 語(yǔ)句去查詢這條記錄時(shí)就可以看到這條記錄了,于是就發(fā)生了幻讀。
圖片
因?yàn)檫@種特殊現(xiàn)象的存在,所以我們認(rèn)為 MySQL Innodb 中的 MVCC 并不能完全避免幻讀現(xiàn)象。
進(jìn)程與線程的區(qū)別
常規(guī)八股
線程池有哪幾個(gè)類型的
- newSingleExecutor
 
只有一個(gè)核心線程,也是最大線程數(shù)。隊(duì)列采用的是 LinkedblockingQueue 無(wú)界阻塞隊(duì)列。極端情況下會(huì)有 OOM 問(wèn)題
它的工作原理是當(dāng)提交任務(wù)是當(dāng)沒(méi)有工作線程時(shí),會(huì)將任務(wù)放入到阻塞隊(duì)列中,
有核心線程時(shí),獲取阻塞隊(duì)列取任務(wù)執(zhí)行,執(zhí)行完了接著從阻塞隊(duì)列執(zhí)行
Keepalive存活時(shí)間是 0,因?yàn)楸緛?lái)就沒(méi)有非核心線程
它的場(chǎng)景是串行化的場(chǎng)景,因?yàn)樗挥幸粋€(gè)工作線程
- newCacheExecutor
 核心線程數(shù)是 0,隊(duì)列采用的是 SynchrousQueue 阻塞隊(duì)列。最大線程數(shù)是 Integer.Max_value 的默認(rèn)值,KeepAiveTime 是 60 s,也就是線程執(zhí)行完了處于空閑狀態(tài)時(shí),過(guò) 60 s 就會(huì)銷(xiāo)毀,如果頻繁的創(chuàng)建線程會(huì)產(chǎn)生 OOM 問(wèn)題
它的工作原理是提交任務(wù),沒(méi)有線程時(shí),任務(wù)放到阻塞隊(duì)列
創(chuàng)建核心線程時(shí)取隊(duì)列執(zhí)行任務(wù),插入一個(gè)元素必須等工作線程取出消費(fèi),如果隊(duì)列沒(méi)有任務(wù)則會(huì)阻塞
它的吞吐量比 newFixedExecutor 更高,它適用于并發(fā)量大但是任務(wù)執(zhí)行周期短的場(chǎng)景
newFixedExecutor
SheculedExecutor
周期性去執(zhí)行任務(wù)。隊(duì)列是 DeayQueue 延遲隊(duì)列,
它的工作原理是 當(dāng)工作線程數(shù)小于最大線程數(shù),首先會(huì)去創(chuàng)建線程去執(zhí)行任務(wù)
當(dāng)達(dá)到核心線程數(shù)時(shí),會(huì)將任務(wù)放入到阻塞隊(duì)列,
所謂周期性就是 他去任務(wù)隊(duì)列取出任務(wù)時(shí),會(huì)修改一個(gè) time 變量 位下次要執(zhí)行的時(shí)間
然后放入到隊(duì)列中
說(shuō)說(shuō)各層有哪些協(xié)議
- 應(yīng)用層:DNS、HTTP、IP
 - 傳輸層:TCP、UDP
 - 網(wǎng)絡(luò)層:IP、ICMP
 - 數(shù)據(jù)鏈路層:ARP
 - 物理層:不記得了
 
說(shuō)說(shuō)一個(gè)數(shù)據(jù)怎么在網(wǎng)絡(luò)各層分割報(bào)文的
發(fā)送數(shù)據(jù)方
- 傳輸層:加上 TCP 報(bào)文頭
 - 網(wǎng)絡(luò)層:加上 IP 頭
 - 數(shù)據(jù)鏈路層:加上幀頭和幀尾
 - 物理層:則是轉(zhuǎn)換為包含0、1的二進(jìn)制比特流
 
講講 TCP 三次握手
- 首先剛開(kāi)始雙方處于關(guān)閉連接狀態(tài),服務(wù)端處于監(jiān)聽(tīng)端口狀態(tài),也就是 Listen 狀態(tài)
 - 第一次握手:客戶端首先生成隨機(jī)初始化序列號(hào)seq = x,并放到 TCP 頭部的32位序號(hào)字段中,同時(shí)將 SYN 標(biāo)志設(shè)置為 1,表示這是一個(gè) SYN 報(bào)文,然后發(fā)送給服務(wù)端,接著客戶端處于 SYN_SENT
 - 第二次握手:服務(wù)端收到客戶端發(fā)送過(guò)來(lái)的 SYN 報(bào)文后,首先也會(huì)生成隨機(jī)初始化序列號(hào)seq = y,并放到 TCP 頭部的32位序號(hào)字段中, 并對(duì)客戶端的序列化 seq = x + 1 作未確認(rèn)應(yīng)答號(hào),然后放到 TCP 頭部的確認(rèn)應(yīng)答字段中,同時(shí)將 SYN 和 ACK 標(biāo)志設(shè)置為 1,表示這是一個(gè) SYN-ACK 報(bào)文。把該報(bào)文發(fā)送給客戶端后,服務(wù)端處于 SYC_RCVD
 - 第三次握手:客戶端收到服務(wù)端發(fā)送過(guò)來(lái)的 SYN_ACK 報(bào)文,會(huì)發(fā)送確認(rèn)報(bào)文給服務(wù)端,這個(gè)確認(rèn)報(bào)文是對(duì)服務(wù)端的初始序列化 seq = y + 1, 客戶端進(jìn)入 ESATBLISH 狀態(tài)
 - 服務(wù)端收到后,也進(jìn)入 ESTABLISHED 狀態(tài)
 
你剛剛說(shuō)的 Listen、SYN_SENT、SYN_RCVD、ESTABLISHED 狀態(tài)有什么含義?
- LISTEN 狀態(tài)表示監(jiān)聽(tīng)是否有連接到來(lái),當(dāng)有連接到來(lái)時(shí),它獲得已經(jīng)連接的 socket
 - SYN_SENT 表示 客戶端具備發(fā)送數(shù)據(jù)能力。但還不具備接受數(shù)據(jù)能力, 此時(shí)需要等待服務(wù)端的確認(rèn)
 - SYN_RCVD 表示服務(wù)端具備接受數(shù)據(jù)的能力和發(fā)送數(shù)據(jù)的能力,此時(shí)需要等待客戶端的確認(rèn)
 - ESTABLISHED 表示我已經(jīng)建立連接了,我可以發(fā)送數(shù)據(jù)了
 
客戶端發(fā)送了數(shù)據(jù)給服務(wù)端,服務(wù)端返回對(duì)方成功確認(rèn)收到的確認(rèn)信息,這個(gè)時(shí)候是否可以肯定服務(wù)端收到了數(shù)據(jù)
- 不一定,服務(wù)端有一個(gè)接受緩存區(qū),此時(shí)服務(wù)端還在處理前面的數(shù)據(jù),有可能服務(wù)端發(fā)生異常了,導(dǎo)致接收緩沖區(qū)的數(shù)據(jù)未被處理
 
那怎么解決這個(gè)問(wèn)題呢?
- 嗯,觸發(fā)重傳機(jī)制,客戶端重新發(fā)送數(shù)據(jù)?(懵逼)
 
客戶端想盡快關(guān)閉連接,應(yīng)該怎么辦?
- 發(fā)送 FIN 報(bào)文?
 - RST 報(bào)文好像也可以斷開(kāi)連接
 
Socket 編程了解過(guò)嗎,什么是 socket
- 了解過(guò)
 - Socket 是一個(gè)套接字
 
socket 的流程
不會(huì)(我搞 java 的,沒(méi)研究過(guò) socket 編程,完了)
基本 socket 做好了封裝,你了解嗎
剛開(kāi)始懵逼,后來(lái)想到才是 Netty 這個(gè)框架
Socket 和 http 有什么區(qū)別?
- Socket 是一個(gè)套接字接口
 - Http 是請(qǐng)求連接,http 是 tcp 連接的管理器
 
你說(shuō)說(shuō) spring 的生命周期?
大致分為五個(gè)階段,創(chuàng)建前準(zhǔn)備階段、實(shí)例化階段、依賴注入階段、容器緩存階段、實(shí)例銷(xiāo)毀階段
后面從說(shuō)了每個(gè)階段是干嘛的(面試官反應(yīng)邏輯講的不夠清楚,這里我就不列出來(lái)的)
事后復(fù)習(xí)總結(jié)如下:
- 創(chuàng)建前準(zhǔn)備階段:
 
Spring 啟動(dòng)后,掃描 @ComponentScan 注解配置的路徑下的所有 .class 文件,
類加載其根據(jù)類名加載獲取類的 Class 對(duì)象
判斷類上是否有 @Component、Service 等注解找出 bean 對(duì)象
給每個(gè)符合條件的 bean 創(chuàng)建 BeanDefintion 對(duì)象用于存放 Class 對(duì)象、作用域等信息,作用域包括 singletion、prototype、request 等,然后添加進(jìn) beanDefinitionMap, key 值存放 bean 的名字,value 是對(duì)應(yīng)的 BeanDefition
掃描 bean 對(duì)象
遍歷 beanDefinitionMap,創(chuàng)建
MyBatis 中 ${} 與 #{} 的區(qū)別
- 無(wú)法防止注入攻擊,在開(kāi)發(fā)中盡量使用{}
 - #{} 是占位符,預(yù)編譯處理,${} 是拼接符,字符串替換,沒(méi)有預(yù)編譯處理
 
感覺(jué)
面試官說(shuō)我們是做游戲開(kāi)發(fā),然后又問(wèn)我你平時(shí)喜歡打游戲嗎,我說(shuō)近些年很少打游戲的。以前很喜歡玩,后面覺(jué)得膩了,然后面試官說(shuō)做游戲開(kāi)發(fā)需要對(duì)游戲很了解的,對(duì)游戲很熱愛(ài)的,否則難干下去
反問(wèn)環(huán)節(jié)說(shuō)我基礎(chǔ)還算行,就是可能在業(yè)務(wù)方面可能不匹配
不足之處
socket編程不太熟悉,計(jì)網(wǎng)還需加強(qiáng)學(xué)習(xí)
Spring bean 的生命周期 沒(méi)有讓面試官聽(tīng)懂















 
 
 








 
 
 
 