附上最近更新的面經(jīng):
某大佬的20+公司面試題總結(jié)和自己的補(bǔ)充
一面
自我介紹下自己顾犹,不超過3分鐘(實(shí)際上我的自我介紹不到一分鐘)
你感覺比本科階段自己進(jìn)步了多少咧擂,有哪些進(jìn)步
研究生期間最大的進(jìn)步是什么
你覺得你適合從事哪個方向的開發(fā)
synchronized與lock的區(qū)別届榄,使用場景杉编〈笤郏看過synchronized的源碼沒
JVM自動內(nèi)存管理窒篱,Minor GC與Full GC的觸發(fā)機(jī)制
了解過JVM調(diào)優(yōu)沒焕刮,基本思路是什么
如果CPU使用率較高,GC頻繁且GC時間長墙杯,可能就需要JVM調(diào)優(yōu)了配并。
基本思路就是讓每一次GC都回收盡可能多的對象,
對于CMS來說霍转,要合理設(shè)置年輕代和年老代的大小荐绝。該如何確定它們的大小呢一汽?這是一個迭代的過程避消,可以先采用JVM的默認(rèn)值,然后通過壓測分析GC日志召夹。
如果看年輕代的內(nèi)存使用率處在高位岩喷,導(dǎo)致頻繁的Minor GC,而頻繁GC的效率又不高监憎,說明對象沒那么快能被回收纱意,這時年輕代可以適當(dāng)調(diào)大一點(diǎn)。
如果看年老代的內(nèi)存使用率處在高位鲸阔,導(dǎo)致頻繁的Full GC偷霉,這樣分兩種情況:如果每次Full GC后年老代的內(nèi)存占用率沒有下來,可以懷疑是內(nèi)存泄漏褐筛;如果Full GC后年老代的內(nèi)存占用率下來了类少,說明不是內(nèi)存泄漏,要考慮調(diào)大年老代渔扎。
對于G1收集器來說硫狞,可以適當(dāng)調(diào)大Java堆,因?yàn)镚1收集器采用了局部區(qū)域收集策略晃痴,單次垃圾收集的時間可控残吩,可以管理較大的Java堆。
如何設(shè)計(jì)存儲海量數(shù)據(jù)的存儲系統(tǒng)
海量數(shù)據(jù)的解決方案:
頁面上:
使用緩存倘核;頁面靜態(tài)化技術(shù)泣侮;
數(shù)據(jù)庫層面:
分離數(shù)據(jù)庫中活躍的數(shù)據(jù);批量讀取和延遲修改紧唱;讀寫分離活尊;使用NoSQL和Hadoop等技術(shù)祖凫;分布式部署數(shù)據(jù)庫;應(yīng)用服務(wù)和數(shù)據(jù)服務(wù)分離酬凳;
其他方面:
使用搜索引擎搜索數(shù)據(jù)庫中的數(shù)據(jù)惠况;進(jìn)行業(yè)務(wù)的拆分;
高并發(fā)情況下的解決方案:
應(yīng)用程序和靜態(tài)資源文件進(jìn)行分離宁仔,靜態(tài)資源可以使用CDN稠屠;
集群與分布式;
使用Nginx反向代理翎苫;
緩存的實(shí)現(xiàn)原理权埠,設(shè)計(jì)緩存要注意什么
將熱點(diǎn)數(shù)據(jù)放在內(nèi)存中,用戶查詢時命中內(nèi)存中的數(shù)據(jù)而不用到數(shù)據(jù)庫中查詢
注意緩存的一致性煎谍,緩存雪崩攘蔽、擊穿、穿透的問題
淘寶熱門商品信息在JVM哪個內(nèi)存區(qū)域
呐粘?满俗?,不應(yīng)該在緩存中嘛作岖,然后落地在數(shù)據(jù)庫里唆垃,跟JVM有屁關(guān)系
操作系統(tǒng)的頁式存儲
把內(nèi)存分成大小相同的內(nèi)存頁,然后程序通過頁表來查詢到自己的存儲位置痘儡,這樣就可以使用不連續(xù)的內(nèi)存來加載程序
事實(shí)上現(xiàn)在都用虛擬內(nèi)存的方式辕万,把程序分段加載到虛擬內(nèi)存中,再把內(nèi)存分頁沉删,通過段表渐尿、頁表的形式來映射程序在內(nèi)存中的位置
volatile關(guān)鍵字的如何保證內(nèi)存可見性
volatile修飾的變量保證其每個寫操作后都更新到主內(nèi)存,每個讀操作都到主內(nèi)存中更新矾瑰,具體的話是在JVM層面砖茸,在修飾的變量前后加關(guān)鍵字
順帶一提volatile還能防止指令重排,這兩者的實(shí)現(xiàn)方式都是內(nèi)存屏障脯倚。
happen-before原則
如果前一個操作的執(zhí)行結(jié)果必須對后一個操作可見渔彰,那就不允許這兩個操作進(jìn)行重排序,且happen-befor具有傳遞性
Lucene全文搜索的原理
先將全文由分詞器進(jìn)行分詞推正,會提取出關(guān)鍵詞和頻率恍涂,然后這個關(guān)鍵詞后面也會跟著一個鏈表,這個鏈表記錄了有個關(guān)鍵詞的文檔植榕。我們通過關(guān)鍵詞搜索就可以找到這串鏈表再沧,也就得到了所要的文檔了。
你覺得自己適合哪方面的開發(fā)尊残,為什么
JavaWeb的后端開發(fā)炒瘸,一個當(dāng)然是對這方面感興趣淤堵,涉及范圍廣,然后目前掌握的比較多的也是這方面的內(nèi)容顷扩,技能比較熟練拐邪,自己認(rèn)識的圈子也是這個圈子里的人,如果遇到問題也容易解決隘截,自己也有一套這方面的學(xué)習(xí)方法扎阶,如果去學(xué)習(xí)其他的話,倒不是走出舒適區(qū)的問題婶芭,而是對于現(xiàn)階段的我來說东臀,不能做到在短時間內(nèi)取得階段性的成果
想去哪里實(shí)習(xí),杭州犀农?
二面
自我介紹下自己惰赋,不超過3分鐘(我的自我介紹仍然不超過1分鐘)
你說你熟悉并發(fā)編程,那么你說說Java鎖有哪些種類呵哨,以及區(qū)別(果然深度不一樣)
公平鎖/非公平鎖
這個是在ReentrankLock中實(shí)現(xiàn)的赁濒,synchronized沒有,是用一個隊(duì)列實(shí)現(xiàn)的仇穗,在公平鎖好理解流部,就是先進(jìn)這個隊(duì)列的戚绕,也先出隊(duì)列獲得資源纹坐,而非公平鎖的話,則是還沒有進(jìn)隊(duì)列之前可以與隊(duì)列中的線程競爭嘗試獲得鎖舞丛,如果獲取失敗耘子,則進(jìn)隊(duì)列,此時也是要乖乖等前面出隊(duì)才行
可重入鎖
如果一個線程獲得過該鎖球切,可以再次獲得谷誓,主要是用途就是在遞歸方面,還有就是防止死鎖吨凑,比如在一個同步方法塊中調(diào)用了另一個相同鎖對象的同步方法塊
獨(dú)享鎖/共享鎖
共享鎖可以由多個線程獲取使用捍歪,而獨(dú)享鎖只能由一個線程獲取。
對ReentrantReadWriteLock其讀鎖是共享鎖鸵钝,其寫鎖是獨(dú)占鎖
讀鎖的共享鎖可保證并發(fā)讀是非常高效的糙臼,讀寫,寫讀恩商,寫寫的過程是互斥的变逃。其中獲得寫鎖的線程還能同時獲得讀鎖雹食,然后通過釋放寫鎖來降級塘安。讀鎖則不能升級
互斥鎖/讀寫鎖
上面講的獨(dú)享鎖/共享鎖就是一種廣義的說法,互斥鎖/讀寫鎖就是具體的實(shí)現(xiàn)。
互斥鎖在Java中的具體實(shí)現(xiàn)就是ReentrantLock
讀寫鎖在Java中的具體實(shí)現(xiàn)就是ReadWriteLock
樂觀鎖/悲觀鎖
樂觀鎖就是樂觀的認(rèn)為不會發(fā)生沖突逛犹,用cas和版本號實(shí)現(xiàn)
悲觀鎖就是認(rèn)為一定會發(fā)生沖突,對操作上鎖
分段鎖
在1.7的concurrenthashmap中有分段鎖的實(shí)現(xiàn)供屉,具體為默認(rèn)16個的segement數(shù)組往产,其中segement繼承自reentranklock,每個線程過來獲取一個鎖撒犀,然后操作這個鎖下連著的map探橱。
偏向鎖/輕量級鎖/重量級鎖
在jdk1.6中做了第synchronized的優(yōu)化,
偏向鎖指的是當(dāng)前只有這個線程獲得绘证,沒有發(fā)生爭搶隧膏,此時將方法頭的markword設(shè)置成0,然后每次過來都cas一下就好嚷那,不用重復(fù)的獲取鎖
輕量級鎖:在偏向鎖的基礎(chǔ)上胞枕,有線程來爭搶,此時膨脹為輕量級鎖魏宽,多個線程獲取鎖時用cas自旋獲取腐泻,而不是阻塞狀態(tài)
重量級鎖:輕量級鎖自旋一定次數(shù)后,膨脹為重量級鎖队询,其他線程阻塞派桩,當(dāng)獲取鎖線程釋放鎖后喚醒其他線程。(線程阻塞和喚醒比上下文切換的時間影響大的多蚌斩,涉及到用戶態(tài)和內(nèi)核態(tài)的切換)
自旋鎖:在沒有獲取鎖的時候铆惑,不掛起而是不斷輪詢鎖的狀態(tài)
如何保證內(nèi)存可見性
volatile 通過內(nèi)存屏障
synchronized 通過修飾的程序段同一時間只能由同一線程運(yùn)行,釋放鎖前會刷新到主內(nèi)存
Http請求的過程與原理
三次握手與四次揮手送膳?
通過HTTP網(wǎng)絡(luò)請求過程中的TCP協(xié)議
TCP連接的特點(diǎn)
相較于UDP來說员魏,更加安全可靠,是面向連接,傳輸?shù)脑捠且粤鞯男问絺鬏?br>
TCP連接如何保證安全可靠的
為什么TCP連接需要三次握手叠聋,兩次不可以嗎撕阎,為什么
不可以兩次握手只能一方確認(rèn)自己的收發(fā)沒有問題,而另一方的收沒問題碌补,發(fā)可能存在問題
AOP的原理
靜態(tài)織入虏束,動態(tài)代理
JDK動態(tài)代理與cglib實(shí)現(xiàn)的區(qū)別(這個,醉得很厲害)
接口(反射)/繼承
那么你說說代理的實(shí)現(xiàn)原理唄
1.創(chuàng)建一個接口
2.創(chuàng)建一個實(shí)現(xiàn)了這個接口的實(shí)現(xiàn)類
3.創(chuàng)建一個實(shí)現(xiàn)了這個接口的代理類厦章,在代理類中實(shí)例化實(shí)現(xiàn)類镇匀,并且調(diào)用實(shí)現(xiàn)類中的方法
看過Spring源碼沒,說說Ioc容器的加載過程吧
簡單概括:
1.刷新預(yù)處理
2.將配置信息解析闷袒,注冊到BeanFactory
3.設(shè)置bean的類加載器
4.如果有第三方想再bean加載注冊完成后坑律,初始化前做點(diǎn)什么(例如修改屬性的值,修改bean的scope為單例或者多例。)晃择,提供了相應(yīng)的模板方法冀值,后面還調(diào)用了這個方法的實(shí)現(xiàn),并且把這些個實(shí)現(xiàn)類注冊到對應(yīng)的容器中
5.初始化當(dāng)前的事件廣播器
6.初始化所有的bean
7.廣播applicationcontext初始化完成宫屠。
//來自于AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
//進(jìn)行加鎖處理
synchronized (this.startupShutdownMonitor) {
// 進(jìn)行刷新容器的準(zhǔn)備工作列疗,比如設(shè)定容器開啟時間,標(biāo)記容器已啟動狀態(tài)等等
prepareRefresh();
// 讓子類來刷新創(chuàng)建容器
// 這步比較關(guān)鍵浪蹂,這步完成后抵栈,配置文件就會解析成一個個 Bean 定義,注冊到 BeanFactory 中坤次,
// 當(dāng)然古劲,這里說的 Bean 還沒有初始化,只是配置信息都提取出來了缰猴,
// 注冊也只是將這些信息都保存到了注冊中心(說到底核心是一個 beanName-> beanDefinition 的 map)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 設(shè)置 BeanFactory 的類加載器产艾,添加幾個 BeanPostProcessor,手動注冊幾個特殊的 bean
prepareBeanFactory(beanFactory);
try {
// 這里需要知道 BeanFactoryPostProcessor 這個知識點(diǎn)滑绒,
//Bean 如果實(shí)現(xiàn)了此接口闷堡,那么在容器初始化以后,Spring 會負(fù)責(zé)調(diào)用里面的 postProcessBeanFactory 方法疑故。
// 這里是提供給子類的擴(kuò)展點(diǎn)杠览,到這里的時候,所有的 Bean 都加載纵势、注冊完成了踱阿,但是都還沒有初始化
// 具體的子類可以在這步的時候添加一些特殊的 BeanFactoryPostProcessor 的實(shí)現(xiàn)類或做點(diǎn)什么事
postProcessBeanFactory(beanFactory);
// 調(diào)用 BeanFactoryPostProcessor 各個實(shí)現(xiàn)類的 postProcessBeanFactory(factory) 方法
invokeBeanFactoryPostProcessors(beanFactory);
// 注冊 BeanPostProcessor 的實(shí)現(xiàn)類,注意看和 BeanFactoryPostProcessor 的區(qū)別
// 此接口兩個方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
// 兩個方法分別在 Bean 初始化之前和初始化之后得到執(zhí)行吨悍。注意扫茅,到這里 Bean 還沒初始化
registerBeanPostProcessors(beanFactory);
// 初始化當(dāng)前 ApplicationContext 的 MessageSource
initMessageSource();
// 初始化當(dāng)前 ApplicationContext 的事件廣播器
initApplicationEventMulticaster();
// 從方法名就可以知道,典型的模板方法(鉤子方法)育瓜,
// 具體的子類可以在這里初始化一些特殊的 Bean(在初始化 singleton beans 之前)
onRefresh();
// 注冊事件監(jiān)聽器,監(jiān)聽器需要實(shí)現(xiàn) ApplicationListener 接口
registerListeners();
// 初始化所有的 singleton beans(lazy-init 的除外)
// 重點(diǎn)方法將會在下一個章節(jié)進(jìn)行說明
finishBeanFactoryInitialization(beanFactory);
// 最后栽烂,廣播事件躏仇,ApplicationContext 初始化完成
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + ex);
}
// 銷毀已經(jīng)初始化的 singleton 的 Beans,以免有些 bean 會一直占用資源
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// 把異常往外拋
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
了解過字節(jié)碼的編譯過程嗎(這個還真不知道)
三面
自我介紹腺办,不超過3分鐘(這次好像時間更久了焰手,也就2分鐘多點(diǎn))
說一下你對哪個項(xiàng)目比較熟悉
數(shù)據(jù)庫項(xiàng)目
為什么做這個項(xiàng)目
當(dāng)時公司里為了整改balabala
項(xiàng)目采用了什么架構(gòu),數(shù)據(jù)庫如何設(shè)計(jì)的
簡單是MVC架構(gòu)怀喉,數(shù)據(jù)庫
數(shù)據(jù)庫由哪些表书妻,為什么有這些表
主要有哪些核心模塊,模塊之間如何通信的
session放在哪里
如何保存會話狀態(tài)躬拢,有哪些方式躲履、區(qū)別如何
cookie 保存在客戶端见间,容易篡改
session 保存在服務(wù)端,連接較大的話會給服務(wù)端帶來壓力工猜,分布式的情況下可以放在數(shù)據(jù)庫中米诉,
優(yōu)點(diǎn):
1:簡單且高性能
2:支持分布式與集群
3:支持服務(wù)器斷電和重啟
4:支持 tomcat、jetty 等運(yùn)行容器重啟
缺點(diǎn):
1篷帅、需要檢查和維護(hù)session過期史侣,手動維護(hù)cookie;
2魏身、不能有頻繁的session數(shù)據(jù)存染鳌;
token 多終端或者app的話一定要這個箭昵,
隨著技術(shù)的發(fā)展李皇,分布式web應(yīng)用的普及,通過session管理用戶登錄狀態(tài)成本越來越高宙枷,因此慢慢發(fā)展成為token的方式做登錄身份校驗(yàn)掉房,然后通過token去取redis中的緩存的用戶信息,隨著之后jwt的出現(xiàn)慰丛,校驗(yàn)方式更加簡單便捷化卓囚,無需通過redis緩存,而是直接根據(jù)token取出保存的用戶信息诅病,以及對token可用性校驗(yàn)哪亿,單點(diǎn)登錄更為簡單。
JWT的token包含三部分?jǐn)?shù)據(jù):
- Header:頭部贤笆,通常頭部有兩部分信息:
- 聲明類型蝇棉,這里是JWT
- 加密算法,自定義
我們會對頭部進(jìn)行base64加密(可解密)芥永,得到第一部分?jǐn)?shù)據(jù)- Payload:載荷篡殷,就是有效數(shù)據(jù),一般包含下面信息:
- 用戶身份信息(注意埋涧,這里因?yàn)椴捎胋ase64加密板辽,可解密,因此不要存放敏感信>息)
- 注冊聲明:如token的簽發(fā)時間棘催,過期時間劲弦,簽發(fā)人等
這部分也會采用base64加密,得到第二部分?jǐn)?shù)據(jù)- Signature:簽名醇坝,是整個數(shù)據(jù)的認(rèn)證信息邑跪。一般根據(jù)前兩步的數(shù)據(jù), 再加上服務(wù)的>的密鑰(secret)
(不要泄漏,最好周期性更換)画畅,通過加密算法生成砸琅。用于驗(yàn)證整個數(shù)據(jù)完整和可靠性(不要泄漏,最好周期性更換)夜赵,
通過加密算法生成明棍。用于驗(yàn)證整個數(shù)據(jù)完整和可靠性
分布式session如何管理,你有哪些方案
Redis做緩存持久化存儲session
數(shù)據(jù)庫存儲session
學(xué)過數(shù)據(jù)結(jié)構(gòu)和算法嗎(當(dāng)然)寇僧,你說說二分搜索的過程
二分搜索有一點(diǎn)要求就是數(shù)據(jù)有已經(jīng)排序好的摊腋,假設(shè)是自然排序的,拿到目標(biāo)數(shù)據(jù)后查找中間的值嘁傀,如果大了兴蒸,就去右邊一部分的中間值比較,小了就去左邊一部分的中間值
說一下快排的過程细办,寫一下偽代碼
取一個值橙凳,然后設(shè)置兩個指針,一個指針先從后到前開始遍歷笑撞,遇到小于這個值的就停止岛啸,然后另一個指針從前到后遍歷,遇到大于這個值的就停止茴肥,知道這兩個指針相遇坚踩,此時交換這個值與相遇的時候指針的值,以這個坐標(biāo)為邊界兩邊開始遞歸
了解哪設(shè)計(jì)模式瓤狐,舉例說說在jdk源碼哪些用到了你說的設(shè)計(jì)模式
單例:ioc容器
模板:ioc瞬铸、springmvc
建造者模式:lombok
工廠:ioc
代理:aop
訂閱/發(fā)布:消息隊(duì)列,redis的pub/sub
你有什么問我嗎(仍然上面三個問題)
四面:
來個自我介紹唄础锐,不超過3分鐘
介紹下你最熟悉的項(xiàng)目
項(xiàng)目使用了什么架構(gòu)嗓节,亮點(diǎn)是什么
MVC,用到Lucene皆警,用aop實(shí)現(xiàn)了權(quán)限的管理
平時主要學(xué)習(xí)什么課程
Java拦宣、數(shù)據(jù)結(jié)構(gòu)、數(shù)學(xué)建模
你目前的研究方向是什么
家是哪的
喜歡看什么書
大概什么時候能來實(shí)習(xí)呢
四面總結(jié)
五面
自我介紹下吧
做了哪些項(xiàng)目
看你在問題中說你在杭州看到很多商販?zhǔn)褂酶犊疃S碼耀怜,你對支付寶怎么看
每天有那么多人使用支付寶恢着,這些數(shù)據(jù)如果給你存儲,你會怎么設(shè)計(jì)呢(不是說HR不問技術(shù)問題嗎财破?不愧是阿里的HR)
為什么想來支付寶實(shí)習(xí)呢
技術(shù)棧、對移動支付比較好奇从诲,
你身邊同學(xué)如何評價你左痢、老師呢
如果與同事發(fā)生了意見的不一致,你會如何解決呢
首先就是要確保雙方都理解了對方的意思,因?yàn)橛行┦菧贤ú怀浞謱?dǎo)致的俊性,然后同時綜合對比不同意見略步,可能會對工作內(nèi)容產(chǎn)生的影響,并且會根據(jù)利弊來選擇方法