工做三年終於社招進字節跳動!字節跳動,阿里,騰訊Java崗面試經驗彙總

前言

我大概我是從去年12月份開始看書學習,到今年的6月份,一直學到看你們的面經基本上百分之90以上都會,我就在5月份開始投簡歷,邊面試邊補充基礎知識等。也是有些辛苦。終因而在前不久拿到了字節跳動的offer,如今我也來寫面經,但願能幫助到你們!前端

面經

Java基礎

0.HashMap的源碼,實現原理,JDK8中對HashMap作了怎樣的優化。java

拉鍊結構,數組+鏈表,原理是hash找數組,衝突後拉鍊表,1.8優化爲會進化成紅黑樹提升效率,而且使用2^n來作容量值面試

引伸點:redis

  • equal & hashcode算法

  • 其餘地方的hash處理,如redis的hash、集羣slot等sql

  • 對hash算法類型的瞭解(安全哈希和非安全哈希如mermerhash)數據庫

  • 對hashMap實現的瞭解:取hashcode,高位運算,低位取模設計模式

  • 一致性hash(處理了什麼問題,在什麼場景用到)數組

  • 紅黑樹簡單描述

1.HaspMap擴容是怎樣擴容的,爲何都是2的N次冪的大小。緩存

在容量到達抵達負載因子*最大容量的時候進行擴容,負載因子的默認值爲0.75

2N的緣由:

  • hash的計算是經過hashcode高低位混合而後和容量的length進行與運算

  • 在length=2n的時候,與運算至關因而一個取模操做

  • 那麼在每次rehash完畢以後mod2N的意義在於要麼該元素是在原位置,要麼是在最高位偏移多一位的位置,提升效率

引伸點:

  • ConcurrentHashMap的擴容:1.7分段擴容以及1.8transfer併發協同的擴容

  • redis漸進式hash擴容處理

3.HashMap,HashTable,ConcurrentHashMap的區別。

Map線程不安全(沒有用任何同步相關的原語),Table安全(直接加syn),Concurrent提供更高併發度的安全(分段鎖思想orSyn+Cas)

引伸點:

  • 對線程安全的定義:如hashmap在1.7前會頭插死循環,可是在1.8改善後仍是不能叫線程安全,由於沒有可見性

  • 對鎖粒度的思考:在介於map和table之間存在tradeoff以後的均衡解

  • Syn和ReentranceLock的區別

  • 鎖升級

4.極高併發下HashTable和ConcurrentHashMap哪一個性能更好,爲何,如何實現的。

分兩種狀況討論:

  1. 極高併發讀:併發讀的狀況下,Table也爲讀加了鎖,沒有併發可言,ConcurrentMap讀鎖並無加併發,直接可讀,若讀resize的某個tab爲空則轉到新tab去讀,Node的元素val和指針next都是volatile修飾的,能夠保證可見性,因此concurrentMap獲勝

  2. 極高併發寫:在併發寫的狀況下,table也是直接加了Syn作鎖,強制串行,而且resize也只能單線程擴容,ConcurrentMap首先對於每一個數組都有併發度,其次在resize的時候支持多線程協同,因此concurrentMap獲勝

因此總體而言concurrentMap優點在於:

  1. 讀操做基於volatile可見性因此無鎖

  2. 寫操做優點在於一是粗粒度的數組鎖,二是協同resize

這個問題的思路是先分類討論而後描述細節最後在下結論

引伸點:

  • volatile的實現:保證內存可見、禁止指令重排序但沒法保證原子性

  • java內存模型

  • JVM作的並行優化、先行發生原則與指令重排序

  • 底層細節的熟悉

5.HashMap在高併發下若是沒有處理線程安全會有怎樣的安全隱患,具體表現是什麼。

1.7前死鎖,1.7後線程會獲取髒值致使邏輯不可靠

6.java中四種修飾符的限制範圍。

public:公用,誰來了都給你用

protected:包內使用,子類也可以使用

default:包內使用,子類不可以使用

private:本身用

7.Object類中的方法。

wait\hashcode\equal\wait\notify\getclass\tostring\nofityall\finalize

引伸點:

  • wait和sleep區別

  • hashcode存在哪兒(對象頭裏)

  • finalize做用:GC前執行,可是不必定能把這個函數跑完

  • getClass後能獲取什麼信息:引伸到反射

8.接口和抽象類的區別,注意JDK8的接口能夠有實現。

接口:能夠imp多個接口,1.7以前不容許實現,1.8後能夠實現方法

抽象類:只能繼承一個類,抽象類中能夠存在默認實現方法

接口的語義是繼承該接口的類有該類接口的行爲

抽象類的語義是繼承該抽象類的類自己就是該抽象類

9.動態代理的兩種方式,以及區別。

  1. CGLIB:其本質是在內存中繼承了一個子類,能夠代理但願代理的那個類的全部方法

  2. JDK動態代理:實現InvocationHandler,經過生成一個Proxy來反射調用全部的接口方法

優劣:

  • CGLIB:會在內存中多存額外的class信息,對metaspace區的使用有影響,可是性能好,能夠訪問非接口的方法

  • JDK動態代理:本質是生成一個繼承全部接口的Proxy來反射調用方法,侷限性在於其只能代理接口的方法

引伸點:

  • Spring的AOP實現以及應用場景

  • 反射的開銷:檢查方法權限,序列化以及匹配入參

  • ASM

10.Java序列化的方式。

繼承Serializable接口並添加SerializableId(idea有組件能夠直接生成),ID其實是一個版本,標誌着序列化的結構是否相同

11.傳值和傳引用的區別,Java是怎麼樣的,有沒有傳值引用。

本質上來說Java傳遞的是引用的副本,實際上就是值傳遞,可是這個值是引用的副本,好比方法A中傳入了一個引用ref,那麼在其中將ref指向其餘對象並不影響在方法A外的ref,由於ref在傳入方法A的時候其實是指向同一個對象的另外一個引用,能夠稱之爲ref',ref'若直接修改引用的對象會影響ref,但若ref'指向其餘對象則和ref沒有關係了

12.一個ArrayList在循環過程當中刪除,會不會出問題,爲何。

分狀況討論:

  1. fori刪除,不會直接拋異常,可是會產生異常訪問

  2. foreach刪除(實際就是迭代器),會直接拋出併發修改異常,由於迭代器會進行獲取迭代器時的exceptModCount和真實的modCount的對比

引伸點:

  • 迭代器實現

  • ArrayList內部細節

13.@transactional註解在什麼狀況下會失效,爲何。

方法A存在該註解,同時被方法B調用,外界調用的是Class.B的方法,由於內部實際上的this.a的調用方式沒走代理類因此不會被切面切到

數據結構和算法

1.B+樹

出度爲m的一顆樹,節點的子女在[M/2,M]之間

葉子節點存儲全量信息

非葉子節點只充當索引進行葉子節點的路由(內存友好、局部性友好)

底層的葉子節點以鏈表的形式進行相連(範圍查找友好)

2.快速排序,堆排序,插入排序(其實八大排序算法都應該瞭解

快排:核心是分治logn

堆排:基於二叉樹nlogn

插入:暴力n2

3.一致性Hash算法,一致性Hash算法的應用

一致性hash,將整個hash的輸出空間當成一個環,環中設立多個節點,每一個節點有值,當對象的映射知足上個節點和這個節點中間值的時候它就落到這個節點當中來

應用:redis緩存,好處是平滑的數據遷移和快速的rebalance

引伸點:

  • 一致性hash熱點怎麼處理:虛擬節點

  • redis如何實現的:客戶端尋址

JVM

1.JVM的內存結構。

程序計數器:計算讀到第幾行了,相似一個遊標

方法棧:提供JVM方法執行的棧空間

本地方法棧:提供native方法執行的棧空間

堆:存對象用的,young分eden,s0,s1,分配比例大概是8:1:1,Old只有一個區

方法區:1.8後爲metaspace,存class信息,常量池(後遷移到堆中),編譯出來的熱點代碼等

引伸點:

  • heap何時發生溢出

  • stack何時發生溢出
  • 方法區何時發生溢出
  • hotspot code的機制
  • 流量黑洞如何產生的

2.JVM方法棧的工做過程,方法棧和本地方法棧有什麼區別。

方法棧是JVM方法使用的,本地方法棧是native方法使用的,在hotspot實際上是用一個

3.JVM的棧中引用如何和堆中的對象產生關聯。

引用保存地址,直接能夠查找到堆上對應地址的對象

4.能夠了解一下逃逸分析技術。

方法中開出來的local變量若是在方法體外不存在的話則稱之爲沒法逃逸

  • 能夠直接分配在棧上,隨着棧彈出直接銷燬,省GC開銷

  • 消除全部同步代碼,由於本質上就是個單線程執行

引伸點:

JVM編譯優化:

  • 逃逸分析

  • 棧上分配

  • 分層編譯與預熱

  • 棧上替換

  • 常量傳播

  • 方法內聯

    ...

5.GC的常見算法,CMS以及G1的垃圾回收過程,CMS的各個階段哪兩個是Stop the world的,CMS會不會產生碎片,G1的優點。

常見算法:

  1. 標記清楚:存在內存碎片,下降內存使用效率

  2. 標記整理:整理可分爲複製整理和原地整理,不存在內存碎片,可是須要額外的cpu算力來進行整理,若爲複製算法還須要額外的內存空間

CMS流程:

  1. 初始標記(stw):得到老年代中跟GCRoot以及新生代關聯的對象,將其標記爲root

  2. 併發標記:將root標記的對象所關聯的對象進行標記

  3. 重標記:在併發標記階段,並無stw,因此會有一些髒對象產生,即標記完畢以後又產生關聯對象修改

  4. 最終標記(stw):最終肯定全部沒有髒對象的存活對象

  5. 併發清理:併發的清理全部死亡對象

  6. Reset:重設程序爲下一次FGC作準備

CMS優劣:

  • 優勢:

    • 不像PN以及Serial同樣全程須要stw,只須要在兩個標記階段stw便可

    • 併發標記、清楚來提高效率,減小stw的時間和總體gc時間

    • 在最終標記前經過預設次數的重標記來清理髒頁減小stw時間
  • 缺點:

    • 仍然存在stw

    • 基於標記清楚算法的GC,節省算力可是會產生內存碎片

    • 併發標記和清楚會形成cpu的高負擔

G1流程:

這個我只懂個大概,以下

分塊分代回收,可分爲youngGC和MixedGC,特色是可預測的GC時間(即所謂的軟實時特性)

引伸點:

  • 是否進行過線上分析

  • GC日誌是否讀過,裏面有什麼信息

  • 大家應用的YGC和FGC頻率以及時間是多少

  • 你清楚當前應用YGC最多的通常是什麼嗎

業務相關:

  • 在線上大部分curd業務當中,實際上形成ygc影響較嚴重且可優化的是日誌系統

  • 對dump出來的堆進行分析的話裏面有很大一塊是String,而其中大機率會是日誌中的各類入參出參

  • 優化方案有不少:

    • 將不須要打日誌的地方去除全量日誌打印功能

    • 日誌在不一樣環境分級打印

    • 只打出錯誤狀態的日誌

    • 在大促期間關閉非主要日誌打印

    • 同步改異步等

6.標記清除和標記整理算法的理解以及優缺點。

上文已答

7.eden survivor區的比例,爲何是這個比例,eden survivor的工做過程。

8:2

定性的來說:大部分對象都只有極短的存活時間,基本就是函數run到尾就釋放了,因此給新晉對象的buffer須要佔較多的比例,而s區能夠相對小一點來容納長時間存活的對象,較小的另外一個緣由是在幾回年齡增加後對象會進入老年代

定量的來說:實驗所得,也能夠根據本身服務器的狀況動態調整(不過筆者沒調過)

8.JVM如何判斷一個對象是否該被GC,能夠視爲root的都有哪幾種類型。

沒有被GCRoot所關聯

Root對象:(tips:不用硬記,針對着JVM內存區域來理解便可)

  1. 函數棧上的引用:包括虛擬機棧和native棧

  2. static類的引用:存在方法區內

  3. 常量池中的常量:堆中

引伸點:

  • gc roots和ref count的區別

9.強軟弱虛引用的區別以及GC對他們執行怎樣的操做。

強:代碼中正常的引用,存在即不會被回收

軟:在內存不足的時候會對其進行GC,可用於緩存場景(相似redis淘汰)

弱:當一個對象只有弱引用關聯的時候會被下一次GC給回收

虛:又稱幽靈引用,基本沒啥用,在GC的時候會感知到

引伸點:

  • 每一個引用的使用場景

  • 是否在源碼或者項目中看到過or使用過這幾種引用類型(ThreadLocal裏用了WeakReference)

10.Java是否能夠GC直接內存。

在GC過程當中若是發現堆外內存的Ref被使用則GC

11.Java類加載的過程。

12.雙親委派模型的過程以及優點。

13.經常使用的JVM調優參數。

14.dump文件的分析。

15.Java有沒有主動觸發GC的方式(沒有)。

多線程

1.Java實現多線程有哪幾種方式。

2.Callable和Future的瞭解。

3.線程池的參數有哪些,在線程池建立一個線程的過程。

4.volitile關鍵字的做用,原理。

5.synchronized關鍵字的用法,優缺點。

6.Lock接口有哪些實現類,使用場景是什麼。

7.可重入鎖的用處及實現原理,寫時複製的過程,讀寫鎖,分段鎖(ConcurrentHashMap中的segment)

8.悲觀鎖,樂觀鎖,優缺點,CAS有什麼缺陷,該如何解決。

9.ABC三個線程如何保證順序執行。

10.線程的狀態都有哪些。

11.sleep和wait的區別。

12.notify和notifyall的區別。

13.ThreadLocal的瞭解,實現原理。

數據庫相關

1.常見的數據庫優化手段

  1. log同步刷盤改異步刷盤

  2. 集羣的話強雙寫改異步同步

  3. 針對sql優化(explain慢sql)

  4. 添加索引

2.索引的優缺點,什麼字段上創建索引

優勢:查的快,支持range

缺點:大部分查詢實際須要回表,索引創建會額外消耗內存和磁盤,對開發者的sql也有要求

字段:區分度大的字段

3.數據庫鏈接池。

4.durid的經常使用配置。

計算機網絡

1.TCP,UDP區別。

2.三次握手,四次揮手,爲何要四次揮手。

3.長鏈接和短鏈接。

4.鏈接池適合長鏈接仍是短鏈接。

設計模式

1.觀察者模式

2.代理模式

舉例子JDK動態代理,經過一層proxy對真實對象進行代理,進行一些額外操做(e.g.:加強行爲、負載均衡等)

3.單例模式,有五種寫法,能夠參考文章單例模式的五種實現方式

  1. 普通單例

  2. lazyloading+syn單例

  3. lazyloading+doublecheck單例

  4. 枚舉

  5. 最後一種不知道,查了發現是靜態內部類單例,利用靜態內部類第一次訪問才加載的機制實現lazyloading

4.能夠考Spring中使用了哪些設計模式

分佈式相關

1.分佈式事務的控制。

2.分佈式鎖如何設計。

3.分佈式session如何設計。

4.dubbo的組件有哪些,各有什麼做用。

duboo不熟悉

5.zookeeper的負載均衡算法有哪些。

zookeeper就會個zab,不過負載均衡無非是公平輪詢、加權輪詢、隨機輪詢或者維護某些資源信息的動態路由這幾種

6.dubbo是如何利用接口就能夠通訊的。

不太熟,估計涉及到服務註冊以及序列化反序列化相關內容

緩存相關

1.redis和memcached的區別。

2.redis支持哪些數據結構。

3.redis是單線程的麼,全部的工做都是單線程麼。

4.redis如何存儲一個String的。

5.redis的部署方式,主從,集羣。

6.redis的哨兵模式,一個key值如何在redis集羣中找到存儲在哪裏。

7.redis持久化策略。

框架相關

1.SpringMVC的Controller是如何將參數和前端傳來的數據一一對應的。

2.Mybatis如何找到指定的Mapper的,如何完成查詢的。

3.Quartz是如何完成定時任務的。

4.自定義註解的實現。

5.Spring使用了哪些設計模式。

6.Spring的IOC有什麼優點。

7.Spring如何維護它擁有的bean。

一些較新的東西

1.JDK8的新特性,流的概念及優點,爲何有這種優點。

2.區塊鏈瞭解

3.如何設計雙11交易總額面板,要作到高併發高可用。

最後

但願我總結的這些東西對大家會有幫助,大家看完以後有什麼的不懂的歡迎在下方留言討論,也能夠私信問我,我通常看完以後都會回的,也能夠關注個人公衆號:前程有光,立刻金九銀十跳槽面試季,整理了1000多道將近500多頁pdf文檔的Java面試題資料,文章都會在裏面更新,整理的資料也會放在裏面。

相關文章
相關標籤/搜索