分享2019年螞蟻金服面經(已拿Offer)!附答案!!

因爲做者面試過程當中高度緊張,本文中只列出了本身還記得的部分題目。java

經歷了漫長一個月的等待,終於在前幾天經過面試官獲悉已被螞蟻金服錄取,這期間的焦慮、痛苦自沒必要說,知道被錄取的那一刻,一全年的陰霾都一掃而空了。linux

筆者面的是阿里的Java研發工程師崗,面試流程是3輪技術面+1輪hr面。面試

1 意外的一面

一面的時候大概是3月12號,面完等了差很少半個月才忽然接到二面面試官的電話。一面多是簡歷面,因此問題比較簡單。算法

ArrayList和LinkedList區別

  • 1. 是否保證線程安全: ArrayList 和 LinkedList 都是不一樣步的,也就是不保證線程安全;數據庫

  • 2. 底層數據結構: Arraylist 底層使用的是Object數組;LinkedList 底層使用的是雙向鏈表數據結構(JDK1.6以前爲循環鏈表,JDK1.7取消了循環。注意雙向鏈表和雙向循環鏈表的區別,下面有介紹到!)編程

  • 3. 插入和刪除是否受元素位置的影響:ArrayList 採用數組存儲,因此插入和刪除元素的時間複雜度受元素位置的影響。 好比:執行add(E e)方法的時候, ArrayList 會默認在將指定的元素追加到此列表的末尾,這種狀況時間複雜度就是O(1)。可是若是要在指定位置 i 插入和刪除元素的話(add(int index, E element))時間複雜度就爲 O(n-i)。由於在進行上述操做的時候集合中第 i 和第 i 個元素以後的(n-i)個元素都要執行向後位/向前移一位的操做。 ② LinkedList 採用鏈表存儲,因此插入,刪除元素時間複雜度不受元素位置的影響,都是近似 O(1)而數組爲近似 O(n)。數組

  • 4. 是否支持快速隨機訪問: LinkedList 不支持高效的隨機元素訪問,而 ArrayList 支持。快速隨機訪問就是經過元素的序號快速獲取元素對象(對應於get(int index)方法)。瀏覽器

  • 5. 內存空間佔用: ArrayList的空 間浪費主要體如今在list列表的結尾會預留必定的容量空間,而LinkedList的空間花費則體如今它的每個元素都須要消耗比ArrayList更多的空間(由於要存放直接後繼和直接前驅以及數據)。緩存

什麼狀況會形成內存泄漏

在Java中,內存泄漏就是存在一些被分配的對象,這些對象有下面兩個特色:tomcat

  1. 這些對象是可達的,即在有向圖中,存在通路能夠與其相連;

  2. 這些對象是無用的,即程序之後不會再使用這些對象。

若是對象知足這兩個條件,這些對象就能夠斷定爲Java中的內存泄漏,這些對象不會被GC所回收,然而它卻佔用內存。

什麼是線程死鎖?如何解決?

認識線程死鎖

多個線程同時被阻塞,它們中的一個或者所有都在等待某個資源被釋放。因爲線程被無限期地阻塞,所以程序不可能正常終止。

以下圖所示,線程 A 持有資源 2,線程 B 持有資源 1,他們同時都想申請對方的資源,因此這兩個線程就會互相等待而進入死鎖狀態。


線程死鎖示意圖


下面經過一個例子來講明線程死鎖,代碼模擬了上圖的死鎖的狀況 (代碼來源於《併發編程之美》):

public class DeadLockDemo {    private static Object resource1 = new Object();//資源 1    private static Object resource2 = new Object();//資源 2    public static void main(String[] args) {        new Thread(() -> {            synchronized (resource1) {                System.out.println(Thread.currentThread() + "get resource1");                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println(Thread.currentThread() + "waiting get resource2");                synchronized (resource2) {                    System.out.println(Thread.currentThread() + "get resource2");                }            }        }, "線程 1").start();        new Thread(() -> {            synchronized (resource2) {                System.out.println(Thread.currentThread() + "get resource2");                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println(Thread.currentThread() + "waiting get resource1");                synchronized (resource1) {                    System.out.println(Thread.currentThread() + "get resource1");                }            }        }, "線程 2").start();    }}複製代碼

Output

Thread[線程 1,5,main]get resource1Thread[線程 2,5,main]get resource2Thread[線程 1,5,main]waiting get resource2Thread[線程 2,5,main]waiting get resource1複製代碼

線程 A 經過 synchronized (resource1) 得到 resource1 的監視器鎖,而後經過Thread.sleep(1000);讓線程 A 休眠 1s 爲的是讓線程 B 獲得執行而後獲取到 resource2 的監視器鎖。線程 A 和線程 B 休眠結束了都開始企圖請求獲取對方的資源,而後這兩個線程就會陷入互相等待的狀態,這也就產生了死鎖。上面的例子符合產生死鎖的四個必要條件。

學過操做系統的朋友都知道產生死鎖必須具有如下四個條件:

  1. 互斥條件:該資源任意一個時刻只由一個線程佔用。

  2. 請求與保持條件:一個進程因請求資源而阻塞時,對已得到的資源保持不放。

  3. 不剝奪條件:線程已得到的資源在末使用完以前不能被其餘線程強行剝奪,只有本身使用完畢後才釋放資源。

  4. 循環等待條件:若干進程之間造成一種頭尾相接的循環等待資源關係。

如何避免線程死鎖?

咱們只要破壞產生死鎖的四個條件中的其中一個就能夠了。

破壞互斥條件

這個條件咱們沒有辦法破壞,由於咱們用鎖原本就是想讓他們互斥的(臨界資源須要互斥訪問)。

破壞請求與保持條件

一次性申請全部的資源。

破壞不剝奪條件

佔用部分資源的線程進一步申請其餘資源時,若是申請不到,能夠主動釋放它佔有的資源。

破壞循環等待條件

靠按序申請資源來預防。按某一順序申請資源,釋放資源則反序釋放。破壞循環等待條件。

咱們對線程 2 的代碼修改爲下面這樣就不會產生死鎖了。

new Thread(() -> {            synchronized (resource1) {                System.out.println(Thread.currentThread() + "get resource1");                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println(Thread.currentThread() + "waiting get resource2");                synchronized (resource2) {                    System.out.println(Thread.currentThread() + "get resource2");                }            }        }, "線程 2").start();複製代碼

Output

Thread[線程 1,5,main]get resource1Thread[線程 1,5,main]waiting get resource2Thread[線程 1,5,main]get resource2Thread[線程 2,5,main]get resource1Thread[線程 2,5,main]waiting get resource2Thread[線程 2,5,main]get resource2Process finished with exit code 0複製代碼

咱們分析一下上面的代碼爲何避免了死鎖的發生?

線程 1 首先得到到 resource1 的監視器鎖,這時候線程 2 就獲取不到了。而後線程 1 再去獲取 resource2 的監視器鎖,能夠獲取到。而後線程 1 釋放了對 resource一、resource2 的監視器鎖的佔用,線程 2 獲取到就能夠執行了。這樣就破壞了破壞循環等待條件,所以避免了死鎖。

紅黑樹是什麼?怎麼實現?時間複雜度?

紅黑樹(Red-Black Tree,簡稱R-B Tree),它一種特殊的二叉查找樹。紅黑樹是特殊的二叉查找樹,意味着它知足二叉查找樹的特徵:任意一個節點所包含的鍵值,大於等於左孩子的鍵值,小於等於右孩子的鍵值。除了具有該特性以外,紅黑樹還包括許多額外的信息。

紅黑樹的每一個節點上都有存儲位表示節點的顏色,顏色是紅(Red)或黑(Black)。紅黑樹的特性:

  1. 每一個節點或者是黑色,或者是紅色。

  2. 根節點是黑色。

  3. 每一個葉子節點是黑色。

  4. 若是一個節點是紅色的,則它的子節點必須是黑色的。

  5. 從一個節點到該節點的子孫節點的全部路徑上包含相同數目的黑節點。

關於它的特性,須要注意的是:

第一,特性(3)中的葉子節點,是隻爲空(NIL或null)的節點。

第二,特性(5),確保沒有一條路徑會比其餘路徑長出倆倍。於是,紅黑樹是相對是接近平衡的二叉樹。

img

具體實現代碼這裏不貼了,要實現起來,須要包含的基本操做是添加、刪除和旋轉。在對紅黑樹進行添加或刪除後,會用到旋轉方法。旋轉的目的是讓樹保持紅黑樹的特性。旋轉包括兩種:左旋 和 右旋。

紅黑樹的應用比較普遍,主要是用它來存儲有序的數據,它的查找、插入和刪除操做的時間複雜度是O(lgn)。

TCP 三次握手和四次揮手(面試常客)

爲了準確無誤地把數據送達目標處,TCP協議採用了三次握手策略。

漫畫圖解:

圖片來源:《圖解HTTP》

TCP三次握手


簡單示意圖:

TCP三次握手


  • 客戶端–發送帶有 SYN 標誌的數據包–一次握手–服務端

  • 服務端–發送帶有 SYN/ACK 標誌的數據包–二次握手–客戶端

  • 客戶端–發送帶有帶有 ACK 標誌的數據包–三次握手–服務端

爲何要三次握手

三次握手的目的是創建可靠的通訊信道,說到通信,簡單來講就是數據的發送與接收,而三次握手最主要的目的就是雙方確認本身與對方的發送與接收是正常的。

第一次握手:Client 什麼都不能確認;Server 確認了對方發送正常

第二次握手:Client 確認了:本身發送、接收正常,對方發送、接收正常;Server 確認了:本身接收正常,對方發送正常

第三次握手:Client 確認了:本身發送、接收正常,對方發送、接收正常;Server 確認了:本身發送、接收正常,對方發送、接收正常

因此三次握手就能確認雙發收發功能都正常,缺一不可。

爲何要傳回 SYN

接收端傳回發送端所發送的 SYN 是爲了告訴發送端,我接收到的信息確實就是你所發送的信號了。

SYN 是 TCP/IP 創建鏈接時使用的握手信號。在客戶機和服務器之間創建正常的 TCP 網絡鏈接時,客戶機首先發出一個 SYN 消息,服務器使用 SYN-ACK 應答表示接收到了這個消息,最後客戶機再以 ACK(Acknowledgement[漢譯:確認字符 ,在數據通訊傳輸中,接收站發給發送站的一種傳輸控制字符。它表示確認發來的數據已經接受無誤。 ])消息響應。這樣在客戶機和服務器之間才能創建起可靠的TCP鏈接,數據才能夠在客戶機和服務器之間傳遞。

傳了 SYN,爲啥還要傳 ACK

雙方通訊無誤必須是二者互相發送信息都無誤。傳了 SYN,證實發送方到接收方的通道沒有問題,可是接收方到發送方的通道還須要 ACK 信號來進行驗證。


TCP四次揮手


斷開一個 TCP 鏈接則須要「四次揮手」:

  • 客戶端-發送一個 FIN,用來關閉客戶端到服務器的數據傳送

  • 服務器-收到這個 FIN,它發回一 個 ACK,確認序號爲收到的序號加1 。和 SYN 同樣,一個 FIN 將佔用一個序號

  • 服務器-關閉與客戶端的鏈接,發送一個FIN給客戶端

  • 客戶端-發回 ACK 報文確認,並將確認序號設置爲收到序號加1

爲何要四次揮手

任何一方均可以在數據傳送結束後發出鏈接釋放的通知,待對方確認後進入半關閉狀態。當另外一方也沒有數據再發送的時候,則發出鏈接釋放通知,對方確認後就徹底關閉了TCP鏈接。

舉個例子:A 和 B 打電話,通話即將結束後,A 說「我沒啥要說的了」,B回答「我知道了」,可是 B 可能還會有要說的話,A 不能要求 B 跟着本身的節奏結束通話,因而 B 可能又巴拉巴拉說了一通,最後 B 說「我說完了」,A 回答「知道了」,這樣通話纔算結束。

上面講的比較歸納,推薦一篇講的比較細緻的文章:https://blog.csdn.net/qzcsu/article/details/72861891

忽然的二面

一面的時候大概是3月12號,面完等了差很少半個月才忽然接到二面面試官的電話。

介紹項目

Storm怎麼保證一致性

Storm是一個分佈式的流處理系統,利用anchor和ack機制保證全部tuple都被成功處理。若是tuple出錯,則能夠被重傳,可是如何保證出錯的tuple只被處理一次呢?Storm提供了一套事務性組件Transaction Topology,用來解決這個問題。

Transactional Topology目前已經再也不維護,由Trident來實現事務性topology,可是原理相同。

參考:https://dwz.cn/8bXRPexB

說一下 HashMap 以及它是否線程安全

HashMap 基於哈希表的 Map 接口的實現。HashMap 中,null 能夠做爲鍵,這樣的鍵只有一個;能夠有一個或多個鍵所對應的值爲null。HashMap 中 hash 數組的默認大小是16,並且必定是2的指數。Hashtable、HashMap都使用了 Iterator。而因爲歷史緣由,Hashtable還使用了Enumeration的方式 。HashMap 實現 Iterator,支持fast-fail。

哈希表是由數組+鏈表組成的,它是經過把key值進行hash來定位對象的,這樣能夠提供比線性存儲更好的性能。

img

HashMap不是線程安全的。

十億條淘寶購買記錄,怎麼獲取出現最多的前十個

這是一道典型的有限內存的海量數據處理的題目。通常這類題目的解答無非是如下幾種:

分治,hash映射,堆排序,雙層桶劃分,Bloom Filter,bitmap,數據庫索引,mapreduce等。

具體情形都有不少不一樣的方案。這類題目能夠到網上搜索一下,瞭解下套路,後面就基本都會了。

平時有沒有用linux系統,怎麼查看某個進程

ps aux|grep java 查看java進程ps aux 查看全部進程ps –ef|grep tomcat 查看全部有關tomcat的進程ps -ef|grep --color java 高亮要查詢的關鍵字kill -9 19979 終止線程號位19979的進程複製代碼

說一下 Innodb 和 MySIAM 的區別

MyISAM類型不支持事務處理等高級處理,而InnoDB類型支持。MyISAM類型的表強調的是性能,其執行數度比InnoDB類型更快,可是不提供事務支持,而InnoDB提供事務支持以及外部鍵等高級數據庫功能。

InnoDB不支持FULLTEXT類型的索引。

InnoDB 中不保存表的具體行數,也就是說,執行select count(

) from table時,InnoDB要掃描一遍整個表來計算有多少行,可是MyISAM只要簡單的讀出保存好的行數便可。注意的是,當count(
)語句包含 where條件時,兩種表的操做是同樣的。

對於AUTO_INCREMENT類型的字段,InnoDB中必須包含只有該字段的索引,可是在MyISAM表中,能夠和其餘字段一塊兒創建聯合索引。

DELETE FROM table時,InnoDB不會從新創建表,而是一行一行的刪除。

LOAD TABLE FROM MASTER操做對InnoDB是不起做用的,解決方法是首先把InnoDB表改爲MyISAM表,導入數據後再改爲InnoDB表,可是對於使用的額外的InnoDB特性(例如外鍵)的表不適用。

說一下jvm內存模型,介紹一下你瞭解的垃圾收集器

其實並無 jvm 內存模型的概念。應該是 Java 內存模型或者 jvm 內存結構,這裏面試者必定要聽清楚問的是哪一個,再回答。

能夠參考:

你說你是大數據方向的,瞭解哪些大數據框架

做者回答了一些zookeeper、storm、HDFS、Hbase等

其餘問題

  • 100個有序的整型,如何打亂順序?

  • 如何設計一個可靠的UDP協議?

二面大概就是這些,其中storm一致性這個問題被面試官懷疑了一下,就有點緊張,其實沒答錯,因此仍是要對知識掌握得更明確才行。

準備充足的三面

清明節的時候例外地沒有回家掃墓,由於知道本身的弱項是操做系統和海量數據題這塊,因此想着惡補這方面的知識,不過以後的面試意外的並無問到這方面的內容。

介紹項目

項目介紹完以後沒問太多

介紹一下HashMap

HashMap真的是面試高頻題,屢次面試都問到了,必定要掌握。

介紹一下併發

這裏能夠把整個併發的體系都說下,包括volatile、synchronized、lock、樂觀悲觀鎖、鎖膨脹、鎖降級、線程池等

銀行帳戶讀寫怎麼作

我說了讀寫鎖以及可能出現死鎖問題

說一下關係型數據庫和非關係型數據庫的區別

非關係型數據庫的優點:

  1. 性能:NOSQL是基於鍵值對的,能夠想象成表中的主鍵和值的對應關係,並且不須要通過SQL層的解析,因此性能很是高

  2. 可擴展性:一樣也是由於基於鍵值對,數據之間沒有耦合性,因此很是容易水平擴展。

使用場景:日誌、埋點、論壇、博客等

關係型數據庫的優點:

  1. 複雜查詢:能夠用SQL語句方便的在一個表以及多個表之間作很是複雜的數據查詢

  2. 事務支持:使得對於安全性能很高的數據訪問要求得以實現。

使用場景:全部有邏輯關係的數據存儲

如何訪問鏈表中間節點

對於這個問題,咱們首先可以想到的就是先遍歷一遍整個的鏈表,而後計算出鏈表的長度,進而遍歷第二遍找出中間位置的數據。這種方式很是簡單。

若題目要求只能遍歷一次鏈表,那又當如何解決問題?

能夠採起創建兩個指針,一個指針一次遍歷兩個節點,另外一個節點一次遍歷一個節點,當快指針遍歷到空節點時,慢指針指向的位置爲鏈表的中間位置,這種解決問題的方法稱爲快慢指針方法。

說下進程間通訊,以及各自的區別

進程間通訊是指在不一樣進程之間傳播或交換信息。方式一般有管道(包括無名管道和命名管道)、消息隊列、信號量、共享存儲、Socket、Streams等。

訪問淘寶網頁的一個具體流程,從獲取ip地址,到怎麼返回相關內容

先經過DNS解析到服務器地址,而後反向代理、負載均衡服務器等,尋找集羣中的一臺機器來真正執行你的請求。還能夠介紹CDN、頁面緩存、Cookie以及session等。

這個過程還包括三次握手、HTTP request中包含哪些內容,狀態碼等,還有OSI七層分層能夠介紹。

服務器接到請求後,會執行業務邏輯,執行過程當中能夠按照MVC來分別介紹。

服務處理過程當中是否調用其餘RPC服務或者異步消息,這個過程包含服務發現與註冊,消息路由。

最後查詢數據庫,會不會通過緩存?是否是關係型數據庫?是會分庫分表仍是作哪些操做?

對於數據庫,分庫分表若是數據量大的話是有必要的,通常業務根據一個分表字段進行取模進行分表,而在作數據庫操做的時候,也根據一樣的規則,決定數據的讀寫操做對應哪張表。這種也有開源的實現的,如阿里的TDDL就有這種功能。分庫分表還涉及到不少技術,好比sequence如何設置 ,如何解決熱點問題等。

最後再把處理結果封裝成response,返回給客戶端。瀏覽器再進行頁面渲染。

焦慮的hr面

之因此說hr面焦慮,是由於面試前我還在看IG的半決賽(實在複習不下),接到電話的時候分外緊張,在一些點上答得不好。

遇到什麼挫折

這種問題主要考察面試者碰見困難是否能堅持下去,而且能夠看出他的解決問題的能力。

能夠簡單描述挫折,並說明本身如何克服,最終有哪些收穫。

職業規劃

代表本身決心,首先本身不許備繼續求學了,必須招工做了。而後說下本身不會短時間內換行業,或者換工做,本身比較喜歡,但願能夠堅持幾年看本身的興趣再規劃之類的。

對阿里的認識

這個比較簡答,誇就好了。

有什麼崇拜的人嗎

我說了詹姆斯哈登,hr小姐姐竟然笑了。

這個能夠說一些IT大牛。

但願去哪裏就業

這個問題果斷回答該公司所在的城市啊。

其餘問題

有什麼興趣愛好,能拿得上臺表演的有嗎

記憶深入的事情

總結

提早批更多的是考察基礎知識,大公司都有本身在用的框架,你進去後基本上得從新學這些框架,因此對他們來講,基礎是否紮實纔是考察的關鍵。

基礎包括: 操做系統、linxu、數據庫、數據結構、算法、java(基礎、容器、高併發、jvm)、計算機網絡等**

建議要投資知識,從寒假到如今,前後買了9個極客時間的課程、訂閱了H神的知識星球、噹噹買了四五本相關技術書籍…

雖然購買的課不少還來不及讀(慚愧)

當時我問一個Java羣的師兄,學不下了怎麼辦,他說,換種姿式繼續學,還別說,有時候失眠的時候,我都在看極客時間或知識星球催眠本身…

要對知識作好總結,雖然之前也有記錄簡書的習慣,可是大多數時候都是寫了不發表,本身作一個記憶的做用,3月份我給本身的要求就是,對每一個知識點要作到可以有本身的理解,而後寫一篇質量較好的博客總結。

面試建議是,必定要自信,勇於表達,面試的時候咱們對知識的掌握有時候很難面面俱到,把本身的思路說出來,而不是直接告訴面試官本身不懂,這也是能夠加分的。

相關文章
相關標籤/搜索