1. 程式人生 > >2019年Java篇:螞蟻金服、拼多多、位元組跳動的面試總結

2019年Java篇:螞蟻金服、拼多多、位元組跳動的面試總結

上午9點,我還在去公司的公交上,突然收到螞蟻的面試電話,其實算不上真正的面試。面試官只是和我聊了下他們在做的事情,說的很詳細,然後和我溝通了下是否有興趣,我表示有興趣,後面就收到正式面試的通知,最後沒選擇去螞蟻表示抱歉。

當時我自己也準備出去看看機會,順便看看自己的實力。當時我其實挺糾結的,一方面現在部門也正需要我,還是可以有一番作為的,另一方面覺得近一年來進步緩慢,沒有以前飛速進步的成就感了,而且業務和技術偏於穩定,加上自己也屬於那種比較懶散的人,骨子裡還是希望能夠突破現狀,持續在技術上有所精進。

在開始正式的總結之前,還是希望各位同仁能否聽我繼續發洩一會,抱拳!

目標是啥?就我而言,短期目標是深入研究某一項技術,比如最近在研究mysql,那麼深入研究一定要動手實踐並且有所產出,這就夠了麼?還需要我們能夠舉一反三,結合實際開發場景想一想日常開發要注意什麼,這中間有沒有什麼坑?可以看出,要進步真的不是一件簡單的事,這種反人類的行為需要我們克服自我的弱點,逐漸形成習慣。真正牛逼的人,從不覺得認真學習是一件多麼難的事,因為這已經形成了他的習慣,就和早上起床刷牙洗臉那麼自然簡單。

扯了那麼多,開始進入正題,先後進行了螞蟻、拼多多和位元組跳動的面試。

準備過程

先說說我自己的情況,我2016先在螞蟻實習了將近三個月,然後去了我現在的老東家,2.5年工作經驗,可以說畢業後就一直老老實實在老東家打怪升級,雖說有螞蟻的實習經歷,但是因為時間太短,還是有點虛的。所以面試官看到我簡歷第一個問題絕對是這樣的。

“哇,你在螞蟻待過,不錯啊”,面試官笑嘻嘻地問到。“是的,還好”,我說。“為啥才三個月?”,面試官臉色一沉問到。“嘩啦啦解釋一通。。。”,我解釋道。“哦,原來如此,那我們開始面試吧”,面試官一本正經說到。

尼瑪,早知道不寫螞蟻的實習經歷了,後面仔細一想,當初寫上螞蟻不就給簡歷加點料嘛。

言歸正傳,準備過程其實很早開始了(當然這不是說我工作時老想著跳槽,因為我明白現在的老東家並不是終點,我還需要不斷提升),具體可追溯到從螞蟻離職的時候,當時出來也面了很多公司,沒啥大公司,面了大概5家公司,都拿到offer了。

工作之餘常常會去額外研究自己感興趣的技術以及工作用到的技術,力求把原理搞明白,並且會自己實踐一把。此外,買了N多書,基本有時間就會去看,補補基礎,什麼作業系統、資料結構與演算法、MySQL、JDK之類的原始碼,基本都好好溫習了(文末會列一下自己看過的書和一些好的資料)。我深知基礎就像“木桶效應”的短板,決定了能裝多少水。

此外,在正式決定看機會之前,我給自己列了一個提綱,主要包括Java要掌握的核心要點,有不懂的就查資料搞懂。我給自己定位還是Java工程師,所以Java體系是一定要做到心中有數的,很多東西沒有常年的積累面試的時候很容易露餡,學習要對得起自己,不要騙人。

剩下的就是找平臺和內推了,除了螞蟻,頭條和拼多多都是找人內推的,感謝螞蟻面試官對我的欣賞,以後說不定會去螞蟻咯。

平臺:脈脈、GitHub、v2

螞蟻金服

一面

一面就做了一道演算法題,要求兩小時內完成,給了長度為N的有重複元素的陣列,要求輸出第10大的數。典型的TopK問題,快排演算法搞定。

演算法題要注意的是合法性校驗、邊界條件以及異常的處理。另外,如果要寫測試用例,一定要保證測試覆蓋場景儘可能全。加上平時刷刷演算法題,這種考核應該沒問題的。

二面

自我介紹下唄

開源專案貢獻過程式碼麼?(Dubbo提過一個列印accesslog的bug算麼)

目前在部門做什麼,業務簡單介紹下,內部有哪些系統,作用和互動過程說下

Dubbo踩過哪些坑,分別是怎麼解決的?(說了異常處理時業務異常捕獲的問題,自定義了一個異常攔截器)

開始進入正題,說下你對執行緒安全的理解(多執行緒訪問同一個物件,如果不需要考慮額外的同步,呼叫物件的行為就可以獲得正確的結果就是執行緒安全)

事務有哪些特性?(ACID)

怎麼理解原子性?(同一個事務下,多個操作要麼成功要麼失敗,不存在部分成功或者部分失敗的情況)

樂觀鎖和悲觀鎖的區別?(悲觀鎖假定會發生衝突,訪問的時候都要先獲得鎖,保證同一個時刻只有執行緒獲得鎖,讀讀也會阻塞;樂觀鎖假設不會發生衝突,只有在提交操作的時候檢查是否有衝突)這兩種鎖在Java和MySQL分別是怎麼實現的?(Java樂觀鎖通過CAS實現,悲觀鎖通過synchronize實現。mysql樂觀鎖通過MVCC,也就是版本實現,悲觀鎖可以通過select... for update加上排它鎖)

HashMap為什麼不是執行緒安全的?(多執行緒操作無併發控制,順便說了在擴容的時候多執行緒訪問時會造成死鎖,會形成一個環,不過擴容時多執行緒操作形成環的問題再JDK1.8已經解決,但多執行緒下使用HashMap還會有一些其他問題比如資料丟失,所以多執行緒下不應該使用HashMap,而應該使用ConcurrentHashMap)怎麼讓HashMap變得執行緒安全?(Collections的synchronize方法包裝一個執行緒安全的Map,或者直接用ConcurrentHashMap)兩者的區別是什麼?(前者直接在put和get方法加了synchronize同步,後者採用了分段鎖以及CAS支援更高的併發)

jdk1.8對ConcurrentHashMap做了哪些優化?(插入的時候如果陣列元素使用了紅黑樹,取消了分段鎖設計,synchronize替代了Lock鎖)為什麼這樣優化?(避免衝突嚴重時連結串列多長,提高查詢效率,時間複雜度從O(N)提高到O(logN))

redis主從機制瞭解麼?怎麼實現的?

有過GC調優的經歷麼?(有點虛,答得不是很好)

有什麼想問的麼?

三面

簡單自我介紹下

監控系統怎麼做的,分為哪些模組,模組之間怎麼互動的?用的什麼資料庫?(MySQL)使用什麼儲存引擎,為什麼使用InnnoDB?(支援事務、聚簇索引、MVCC)

訂單表有做拆分麼,怎麼拆的?(垂直拆分和水平拆分)

水平拆分後查詢過程描述下

如果落到某個分片的資料很大怎麼辦?(按照某種規則,比如雜湊取模、range,將單張表拆分為多張表)

雜湊取模會有什麼問題麼?(有的,資料分佈不均,擴容縮容相對複雜 )

分庫分表後怎麼解決讀寫壓力?(一主多從、多主多從)

拆分後主鍵怎麼保證惟一?(UUID、Snowflake演算法)

Snowflake生成的ID是全域性遞增唯一麼?(不是,只是全域性唯一,單機遞增)

怎麼實現全域性遞增的唯一ID?(講了TDDL的一次取一批ID,然後再本地慢慢分配的做法)

Mysql的索引結構說下(說了B+樹,B+樹可以對葉子結點順序查詢,因為葉子結點存放了資料結點且有序)

主鍵索引和普通索引的區別(主鍵索引的葉子結點存放了整行記錄,普通索引的葉子結點存放了主鍵ID,查詢的時候需要做一次回表查詢)一定要回表查詢麼?(不一定,當查詢的欄位剛好是索引的欄位或者索引的一部分,就可以不用回表,這也是索引覆蓋的原理)

你們系統目前的瓶頸在哪裡?

你打算怎麼優化?簡要說下你的優化思路

有什麼想問我麼?

四面

介紹下自己

為什麼要做逆向?

怎麼理解微服務?

服務治理怎麼實現的?(說了限流、壓測、監控等模組的實現)

這個不是中介軟體做的事麼,為什麼你們部門做?(當時沒有單獨的中介軟體團隊,微服務剛搞不久,需要進行監控和效能優化)

說說Spring的生命週期吧

說說GC的過程(說了young gc和full gc的觸發條件和回收過程以及物件建立的過程)

CMS GC有什麼問題?(併發清除演算法,浮動垃圾,短暫停頓)

怎麼避免產生浮動垃圾?(記得有個VM引數設定可以讓掃描新生代之前進行一次young gc,但是因為gc是虛擬機器自動排程的,所以不保證一定執行。但是還有引數可以讓虛擬機器強制執行一次young gc)

強制young gc會有什麼問題?(STW停頓時間變長)

知道G1麼?(瞭解一點 )

回收過程是怎麼樣的?(young gc、併發階段、混合階段、full gc,說了Remember Set)

你提到的Remember Set底層是怎麼實現的?

有什麼想問的麼?

五面

五面是HRBP面的,和我提前預約了時間,主要聊了之前在螞蟻的實習經歷、部門在做的事情、職業發展、福利待遇等。阿里面試官確實是具有一票否決權的,很看重你的價值觀是否match,一般都比較喜歡皮實的候選人。HR面一定要誠實,不要說謊,只要你說謊HR都會去證實,直接cut了。

之前螞蟻實習三個月怎麼不留下來?

實習的時候主管是誰?

實習做了哪些事情?(尼瑪這種也問?)

你對技術怎麼看?平時使用什麼技術棧?(阿里HR真的是既當爹又當媽,)

最近有在研究什麼東西麼

你對SRE怎麼看

對待遇有什麼預期麼

最後HR還對我說目前穩定性保障部挺缺人的,希望我儘快回覆。

小結

螞蟻面試比較重視基礎,所以Java那些基本功一定要紮實。螞蟻的工作環境還是挺讚的,因為我面的是穩定性保障部門,還有許多單獨的小組,什麼三年1班,很有青春的感覺。面試官基本水平都比較高,基本都P7以上,除了基礎還問了不少架構設計方面的問題,收穫還是挺大的。

拼多多

面試前

面完螞蟻后,早就聽聞拼多多這個獨角獸,決定也去面一把。首先我在脈脈找了一個拼多多的HR,加了微信聊了下,發了簡歷便開始我的拼多多面試之旅。這裡要非常感謝拼多多HR小姐姐,從面試內推到offer確認一直都在幫我,人真的很nice。

一面

為啥螞蟻只待了三個月?沒轉正?(轉正了,解釋了一通。。。)

Java中的HashMap、TreeMap解釋下?(TreeMap紅黑樹,有序,HashMap無序,陣列+連結串列)

TreeMap查詢寫入的時間複雜度多少?(O(logN))

HashMap多執行緒有什麼問題?(執行緒安全,死鎖)怎麼解決?( jdk1.8用了synchronize + CAS,擴容的時候通過CAS檢查是否有修改,是則重試)重試會有什麼問題麼?(CAS(Compare And Swap)是比較和交換,不會導致執行緒阻塞,但是因為重試是通過自旋實現的,所以仍然會佔用CPU時間,還有ABA的問題)怎麼解決?(超時,限定自旋的次數,ABA可以通過原理變數AtomicStampedReference解決,原理利用版本號進行比較)超過重試次數如果仍然失敗怎麼辦?(synchronize互斥鎖)

CAS和synchronize有什麼區別?都用synchronize不行麼?(CAS是樂觀鎖,不需要阻塞,硬體級別實現的原子性;synchronize會阻塞,JVM級別實現的原子性。使用場景不同,執行緒衝突嚴重時CAS會造成CPU壓力過大,導致吞吐量下降,synchronize的原理是先自旋然後阻塞,執行緒衝突嚴重仍然有較高的吞吐量,因為執行緒都被阻塞了,不會佔用CPU )

如果要保證執行緒安全怎麼辦?(ConcurrentHashMap)

ConcurrentHashMap怎麼實現執行緒安全的?(分段鎖)

get需要加鎖麼,為什麼?(不用,volatile關鍵字)

volatile的作用是什麼?(保證記憶體可見性)

底層怎麼實現的?(說了主記憶體和工作記憶體,讀寫記憶體屏障,happen-before,並在紙上畫了執行緒互動圖)

在多核CPU下,可見性怎麼保證?(思考了一會,匯流排嗅探技術)

聊專案,系統之間是怎麼互動的?

系統併發多少,怎麼優化?

給我一張紙,畫了一個九方格,都填了數字,給一個MN矩陣,從1開始逆時針列印這MN個數,要求時間複雜度儘可能低(內心OS:之前貌似碰到過這題,最優解是怎麼實現來著)思考中。。。

可以先說下你的思路(想起來了,說了什麼時候要變換方向的條件,向右、向下、向左、向上,依此迴圈)

有什麼想問我的?

二面

自我介紹下

手上還有其他offer麼?(拿了螞蟻的offer)

部門組織結構是怎樣的?(這輪不是技術面麼,不過還是老老實實說了)

系統有哪些模組,每個模組用了哪些技術,資料怎麼流轉的?(面試官有點禿頂,一看級別就很高)給了我一張紙,我在上面簡單畫了下系統之間的流轉情況

鏈路追蹤的資訊是怎麼傳遞的?(RpcContext的attachment,說了Span的結構:parentSpanId + curSpanId)

SpanId怎麼保證唯一性?(UUID,說了下內部的定製改動)

RpcContext是在什麼維度傳遞的?(執行緒)

Dubbo的遠端呼叫怎麼實現的?(講了讀取配置、拼裝url、建立Invoker、服務匯出、服務註冊以及消費者通過動態代理、filter、獲取Invoker列表、負載均衡等過程(嘩啦啦講了10多分鐘),我可以喝口水麼)

Spring的單例是怎麼實現的?(單例登錄檔)

為什麼要單獨實現一個服務治理框架?(說了下內部剛搞微服務不久,主要對服務進行一些監控和效能優化)

誰主導的?內部還在使用麼?

逆向有想過怎麼做成通用麼?

有什麼想問的麼?

三面

二面老大面完後就直接HR面了,主要問了些職業發展、是否有其他offer、以及入職意向等問題,順便說了下公司的福利待遇等,都比較常規啦。不過要說的是手上有其他offer或者大廠經歷會有一定加分。

小結

拼多多的面試流程就簡單許多,畢竟是一個成立三年多的公司。面試難度中規中矩,只要基礎紮實應該不是問題。但不得不說工作強度很大,開始面試前HR就提前和我確認能否接受這樣強度的工作,想來的老鐵還是要做好準備

位元組跳動

面試前

頭條的面試是三家裡最專業的,每次面試前有專門的HR和你約時間,確定OK後再進行面試。每次都是通過視訊面試,因為都是之前都是電話面或現場面,所以視訊面試還是有點不自然。也有人覺得視訊面試體驗很贊,當然蘿蔔青菜各有所愛。最坑的二面的時候對方面試官的網路老是掉線,最後很冤枉的掛了(當然有一些點答得不好也是原因之一)。所以還是有點遺憾的。

一面

先自我介紹下

聊專案,逆向系統是什麼意思

聊專案,逆向系統用了哪些技術

執行緒池的執行緒數怎麼確定?

如果是IO操作為主怎麼確定?

如果計算型操作又怎麼確定?

Redis熟悉麼,瞭解哪些資料結構?(說了zset) zset底層怎麼實現的?(跳錶)

跳錶的查詢過程是怎麼樣的,查詢和插入的時間複雜度?(說了先從第一層查詢,不滿足就下沉到第二層找,因為每一層都是有序的,寫入和插入的時間複雜度都是O(logN))

紅黑樹瞭解麼,時間複雜度?(說了是N叉平衡樹,O(logN))

既然兩個資料結構時間複雜度都是O(logN),zset為什麼不用紅黑樹(跳錶實現簡單,踩坑成本低,紅黑樹每次插入都要通過旋轉以維持平衡,實現複雜)

點了點頭,說下Dubbo的原理?(說了服務註冊與釋出以及消費者呼叫的過程)踩過什麼坑沒有?(說了dubbo異常處理的和列印accesslog的問題)

CAS瞭解麼?(說了CAS的實現)還了解其他同步機制麼?(說了synchronize以及兩者的區別,一個樂觀鎖,一個悲觀鎖)

那我們做一道題吧,陣列A,2*n個元素,n個奇數、n個偶數,設計一個演算法,使得陣列奇數下標位置放置的都是奇數,偶數下標位置放置的都是偶數

先說下你的思路(從0下標開始遍歷,如果是奇數下標判斷該元素是否奇數,是則跳過,否則從該位置尋找下一個奇數)

下一個奇數?怎麼找?(有點懵逼,思考中。。)

有思路麼?(仍然是先遍歷一次陣列,並對下標進行判斷,如果下標屬性和該位置元素不匹配從當前下標的下一個遍歷陣列元素,然後替換)

你這樣時間複雜度有點高,如果要求O(N)要怎麼做(思考一會,答道“定義兩個指標,分別從下標0和1開始遍歷,遇見奇數位是是偶數和偶數位是奇數就停下,交換內容”)

時間差不多了,先到這吧。你有什麼想問我的?

二面

面試官和藹很多,你先介紹下自己吧

你對服務治理怎麼理解的?

專案中的限流怎麼實現的?(Guava ratelimiter,令牌桶演算法)

具體怎麼實現的?(要點是固定速率且令牌數有限)

如果突然很多執行緒同時請求令牌,有什麼問題?(導致很多請求積壓,執行緒阻塞)

怎麼解決呢?(可以把積壓的請求放到訊息佇列,然後非同步處理)

如果不用訊息佇列怎麼解決?(說了RateLimiter預消費的策略)

分散式追蹤的上下文是怎麼儲存和傳遞的?(ThreadLocal + spanId,當前節點的spanId作為下個節點的父spanId)

Dubbo的RpcContext是怎麼傳遞的?(ThreadLocal)主執行緒的ThreadLocal怎麼傳遞到執行緒池?(說了先在主執行緒通過ThreadLocal的get方法拿到上下文資訊,線上程池建立新的ThreadLocal並把之前獲取的上下文資訊設定到ThreadLocal中。這裡要注意的執行緒池建立的ThreadLocal要在finally中手動remove,不然會有記憶體洩漏的問題)

你說的記憶體洩漏具體是怎麼產生的?(說了ThreadLocal的結構,主要分兩種場景:主執行緒仍然對ThreadLocal有引用和主執行緒不存在對ThreadLocal的引用。第一種場景因為主執行緒仍然在執行,所以還是有對ThreadLocal的引用,那麼ThreadLocal變數的引用和value是不會被回收的。第二種場景雖然主執行緒不存在對ThreadLocal的引用,且該引用是弱引用,所以會在gc的時候被回收,但是對用的value不是弱引用,不會被記憶體回收,仍然會造成記憶體洩漏)

執行緒池的執行緒是不是必須手動remove才可以回收value?(是的,因為執行緒池的核心執行緒是一直存在的,如果不清理,那麼核心執行緒的threadLocals變數會一直持有ThreadLocal變數)

那你說的記憶體洩漏是指主執行緒還是執行緒池?(主執行緒 )

可是主執行緒不是都退出了,引用的物件不應該會主動回收麼?(面試官和記憶體洩漏槓上了),沉默了一會。。。

那你說下SpringMVC不同使用者登入的資訊怎麼保證執行緒安全的?(剛才解釋的有點懵逼,一下沒反應過來,居然回答成鎖了。大腦有點暈了,此時已經一個小時過去了,感覺情況不妙。。。)

這個直接用ThreadLocal不就可以麼,你見過SpringMVC有鎖實現的程式碼麼?(有點暈菜。。。)

我們聊聊mysql吧,說下索引結構(說了B+樹)

為什麼使用B+樹?( 說了查詢效率高,O(logN),可以充分利用磁碟預讀的特性,多叉樹,深度小,葉子結點有序且儲存資料)

什麼是索引覆蓋?(忘記了。。。)

Java為什麼要設計雙親委派模型?

什麼時候需要自定義類載入器?

我們做一道題吧,手寫一個物件池

有什麼想問我的麼?(感覺我很多點都沒答好,是不是掛了(結果真的是) )

小結

頭條的面試確實很專業,每次面試官會提前給你發一個視訊連結,然後準點開始面試,而且考察的點都比較全。

面試官都有一個特點,會抓住一個值得深入的點或者你沒說清楚的點深入下去直到你把這個點講清楚,不然面試官會覺得你並沒有真正理解。二面面試官給了我一點建議,研究技術的時候一定要去研究產生的背景,弄明白在什麼場景解決什麼特定的問題,其實很多技術內部都是相通的。很誠懇,還是很感謝這位面試官大大。

總結

從年前開始面試到頭條面完大概一個多月的時間,真的有點身心俱疲的感覺。最後拿到了拼多多、螞蟻的offer,還是蠻幸運的。頭條的面試對我幫助很大,再次感謝面試官對我的誠懇建議,以及拼多多的HR對我的囉嗦的問題詳細解答。

彩蛋:

本文到這裡就結束了,喜歡的朋友可以幫忙轉發和關注一下,感謝支援!

平時收集了很多面試的資料 也做了整理有需要的朋友可以獲取:867581223

還贈送Spring原始碼分析、Dubbo、Redis、Netty、zookeeper、Spring cloud、分散式資料

這份知識尤其適合:

1.近期想跳槽,要面試的Java程式設計師,查漏補缺,以便儘快彌補短板;

2.想了解“一線網際網路公司”最新招聘需求/技術要求,對比找出自身的長處和弱點所在,評估自己在現有市場上的競爭力如何;

3.還沒形成系統的Java知識體系,缺乏清晰的提升方向和學習路徑的程式設計師。

4.想去一線網際網