前言
今天為大家整理了目前互聯網出現率最高的大廠面試題,所謂八股文也就是指文章的八個部分,文體有固定格式:由破題、承題、起講、入題、起股、中股、后股、束股八部分組成,題目一律出自四書五經中的原文。
初中級和中高級都有,包括 Java 基礎,JVM 知識面試題庫,開源框架面試題庫,操作系統面試題庫,多線程面試題庫,Tcp 面試題庫,架構設計與分布式面試題庫,算法面試題庫,數據庫面試題庫,消息隊列面試題庫,緩存面試題庫
而JAVA面試八股文也就是為了考驗大家的JAVA基礎功底,所以強烈建議背誦全文。
1、并發編程三要素?
(1)?原子性
原子性指的是一個或者多個操作,要么全部執行并且在執行的過程中不被其他操作打斷,要 么就全部都不執行。
(2)?可見性
可見性指多個線程操作一個共享變量時,其中一個線程對變量進行修改后,其他線程可以立 即看到修改的結果。
(3)?有序性
有序性,即程序的執行順序按照代碼的先后順序來執行。
2、實現可見性的方法有哪些?
synchronized 或者 Lock:保證同一個時刻只有一個線程獲取鎖執行代碼,鎖釋放之前把最新的值刷新到主內存,實現可見性。
3、多線程的價值?
(1) 發揮多核 CPU 的優勢
多線程,可以真正發揮出多核 CPU 的優勢來,達到充分利用 CPU 的目的,采用多線程的方式去同時完成幾件事情而不互相干擾。
(2) 防止阻塞
從程序運行效率的角度來看,單核 CPU 不但不會發揮出多線程的優勢,反而會因為在單核CPU 上運行多線程導致線程上下文的切換,而降低程序整體的效率。但是單核 CPU 我們還是要應用多線程,就是為了防止阻塞。試想,如果單核 CPU 使用單線程,那么只要這個線程阻塞了,比方說遠程讀取某個數據吧,對端遲遲未返回又沒有設置超時時間,那么你的整個程序在數據返回回來之前就停止運行了。多線程可以防止這個問題,多條線程同時運行, 哪怕一條線程的代碼執行讀取數據阻塞,也不會影響其它任務的執行。
(3) 便于建模
這是另外一個沒有這么明顯的優點了。假設有一個大的任務 A,單線程編程,那么就要考慮很多,建立整個程序模型比較麻煩。但是如果把這個大的任務 A 分解成幾個小任務,任務 B、任務 C、任務 D,分別建立程序模型,并通過多線程分別運行這幾個任務,那就簡單很多了。
4、創建線程的有哪些方式?
(1) 繼承 Thread 類創建線程類
(2) 通過 Runnable 接口創建線程類
(3) 通過 Callable 和 Future 創建線程
(4) 通過線程池創建
5、創建線程的三種方式的對比?
(1) 采用實現 Runnable、Callable 接口的方式創建多線程。優勢是:
線程類只是實現了 Runnable 接口或 Callable 接口,還可以繼承其他類。在這種方式下,多個線程可以共享同一個 target 對象,所以非常適合多個相同線程來處理同一份資源的情況, 從而可以將 CPU、代碼和數據分開,形成清晰的模型,較好地體現了面向對象的思想。
劣勢是:編程稍微復雜,如果要訪問當前線程,則必須使用 Thread.currentThread()方法。
(2) 使用繼承 Thread 類的方式創建多線程優勢是:
編寫簡單,如果需要訪問當前線程,則無需使用 Thread.currentThread()方法,直接使用 this
即可獲得當前線程。劣勢是:
線程類已經繼承了 Thread 類,所以不能再繼承其他父類。
(3) Runnable 和 Callable 的區別
1、Callable 規定(重寫)的方法是 call(),Runnable 規定(重寫)的方法是 run()。
2、Callable 的任務執行后可返回值,而 Runnable 的任務是不能返回值的。
3、Call 方法可以拋出異常,run 方法不可以。
4、運行 Callable 任務可以拿到一個 Future 對象,表示異步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,并檢索計算的結果。通過 Future 對象可以了解任務執行情況,可取消任務的執行,還可獲取執行結果。
6、線程的狀態流轉圖
線程的生命周期及五種基本狀態:
7、Java 線程具有五中基本狀態
(1) 新建狀態(New):
當線程對象對創建后,即進入了新建狀態,如:Thread t= new MyThread();
(2) 就緒狀態(Runnable):
當調用線程對象的 start()方法(t.start();),線程即進入就緒狀態。處于就緒狀態的線程, 只是說明此線程已經做好了準備,隨時等待 CPU 調度執行,并不是說執行了 t.start()此線程立即就會執行;
(3) 運行狀態(Running):
當 CPU 開始調度處于就緒狀態的線程時,此時線程才得以真正執行,即進入到運行狀態。注:就 緒狀態是進入到運行狀態的唯一入口,也就是說,線程要想進入運行狀態執行,首先必須處于就緒狀態中;
(4) 阻塞狀態(Blocked):
處于運行狀態中的線程由于某種原因,暫時放棄對 CPU 的使用權,停止執行,此時進入阻塞狀態,直到其進入到就緒狀態,才 有機會再次被 CPU 調用以進入到運行狀態。根據阻塞產生的原因不同,阻塞狀態又可以分為三種:
1) 等待阻塞:運行狀態中的線程執行 wait()方法,使本線程進入到等待阻塞狀態;
2) 同步阻塞:線程在獲取 synchronized 同步鎖失敗(因為鎖被其它線程所占用), 它會進入同步阻塞狀態;
3) 其他阻塞:通過調用線程的 sleep()或 join()或發出了 I/O 請求時,線程會進入到阻塞狀態。當 sleep()狀態超時、join()等待線程終止或者超時、或者 I/O 處理完畢時,線程重新轉入就緒狀態。
(5) 死亡狀態(Dead):
線程執行完了或者因異常退出了 run()方法,該線程結束生命周期。
8、什么是線程池?有哪幾種創建方式?
線程池就是提前創建若干個線程,如果有任務需要處理,線程池里的線程就會處理任務,處理完之后線程并不會被銷毀,而是等待下一個任務。由于創建和銷毀線程都是消耗系統資源的,所以當你想要頻繁的創建和銷毀線程的時候就可以考慮使用線程池來提升系統的性能。
java 提供了一個
java.util.concurrent.Executor 接口的實現用于創建線程池。
9、四種線程池的創建:
(1) newCachedThreadPool 創建一個可緩存線程池
(2) newFixedThreadPool 創建一個定長線程池,可控制線程最大并發數。
(3) newScheduledThreadPool 創建一個定長線程池,支持定時及周期性任務執行。
(4) newSingleThreadExecutor 創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務。
10、線程池的優點?
(1) 重用存在的線程,減少對象創建銷毀的開銷。
(2) 可有效的控制最大并發線程數,提高系統資源的使用率,同時避免過多資源競爭,避免堵塞。
(3) 提供定時執行、定期執行、單線程、并發數控制等功能。
11、常用的并發工具類有哪些?
(1)?CountDownLatch
(2)?CyclicBarrier
(3) Semaphore
(4) Exchanger
12、CyclicBarrier 和 CountDownLatch 的區別
(1) CountDownLatch 簡單的說就是一個線程等待,直到他所等待的其他線程都執行完成并且調用 countDown()方法發出通知后,當前線程才可以繼續執行。
(2) cyclicBarrier 是所有線程都進行等待,直到所有線程都準備好進入 await()方法之后, 所有線程同時開始執行!
(3) CountDownLatch 的計數器只能使用一次。而 CyclicBarrier 的計數器可以使用 reset() 方法重置。所以 CyclicBarrier 能處理更為復雜的業務場景,比如如果計算發生錯誤,可以重置計數器,并讓線程們重新執行一次。
( 4 ) CyclicBarrier 還提供其他有用的方法, 比如 getNumberWaiting 方法可以獲得CyclicBarrier 阻塞的線程數量。isBroken 方法用來知道阻塞的線程是否被中斷。如果被中斷返回 true,否則返回 false。
13、synchronized 的作用?
在 Java 中,synchronized 關鍵字是用來控制線程同步的,就是在多線程的環境下,控制synchronized 代碼段不被多個線程同時執行。synchronized 既可以加在一段代碼上,也可以加在方法上。
14、volatile?關鍵字的作用
對于可見性,Java 提供了 volatile 關鍵字來保證可見性。當一個共享變量被 volatile 修飾時,它會保證修改的值會立即被更新到主存,當有其他線程需要讀取時,它會去內存中讀取新值。從實踐角度而言,volatile 的一個重要作用就是和?CAS?結合,保證了原子性,詳細的可以參見
java.util.concurrent.atomic 包下的類,比如 AtomicInteger。
15、什么是 CAS
CAS 是 compare and swap 的縮寫,即我們所說的比較交換。
cas 是一種基于鎖的操作,而且是樂觀鎖。在 java 中鎖分為樂觀鎖和悲觀鎖。悲觀鎖是將資源鎖住,等一個之前獲得鎖的線程釋放鎖之后,下一個線程才可以訪問。而樂觀鎖采取了一種寬泛的態度,通過某種方式不加鎖來處理資源,比如通過給記錄加 version 來獲取數據, 性能較悲觀鎖有很大的提高。
CAS 操作包含三個操作數 —— 內存位置(V)、預期原值(A)和新值(B)。如果內存地址里面的值和 A 的值是一樣的,那么就將內存里面的值更新成 B。CAS 是通過無限循環來獲取數據的,若果在第一輪循環中,a 線程獲取地址里面的值被 b 線程修改了,那么 a 線程需要自旋,到下次循環才有可能機會執行。
java.util.concurrent.atomic 包 下 的 類 大 多 是 使 用 CAS 操 作 來 實 現 的
(AtomicInteger,AtomicBoolean,AtomicLong)。
16、CAS 的問題
(1) CAS 容易造成 ABA 問題
一個線程 a 將數值改成了 b,接著又改成了 a,此時 CAS 認為是沒有變化,其實是已經變化過了,而這個問題的解決方案可以使用版本號標識,每操作一次 version 加 1。在 java5 中,已經提供了 AtomicStampedReference 來解決問題。
(2) 不能保證代碼塊的原子性
CAS 機制所保證的知識一個變量的原子性操作,而不能保證整個代碼塊的原子性。比如需要保證 3 個變量共同進行原子性的更新,就不得不使用 synchronized 了。
(3) CAS 造成 CPU 利用率增加
之前說過了 CAS 里面是一個循環判斷的過程,如果線程一直沒有獲取到狀態,cpu 資源會一直被占用。
17、什么是 Future?
在并發編程中,我們經常用到非阻塞的模型,在之前的多線程的三種實現中,不管是繼承thread 類還是實現 runnable 接口,都無法保證獲取到之前的執行結果。通過實現 Callback 接口,并用 Future 可以來接收多線程的執行結果。
Future 表示一個可能還沒有完成的異步任務的結果,針對這個結果可以添加 Callback 以便在任務執行成功或失敗后作出相應的操作。
18、什么是 AQS
AQS 是AbustactQueuedSynchronizer 的簡稱,它是一個 Java 提高的底層同步工具類,用一個 int 類型的變量表示同步狀態,并提供了一系列的 CAS 操作來管理這個同步狀態。
AQS 是一個用來構建鎖和同步器的框架,使用 AQS 能簡單且高效地構造出應用廣泛的大量的同步器,比如我們提到的 ReentrantLock,Semaphore,其他的諸如 ReentrantReadWriteLock, SynchronousQueue,FutureTask?等等皆是基于 AQS 的。
19、AQS 支持兩種同步方式:
(1) 獨占式
(2) 共享式
這樣方便使用者實現不同類型的同步組件,獨占式如 ReentrantLock,共享式如 Semaphore, CountDownLatch,組 合 式 的 如 ReentrantReadWriteLock。總之,AQS 為使用提供了底層支撐,如何組裝實現,使用者可以自由發揮。
20、ReadWriteLock 是什么
首先明確一下,不是說 ReentrantLock 不好,只是 ReentrantLock 某些時候有局限。如果使用 ReentrantLock,可能本身是為了防止線程 A 在寫數據、線程 B 在讀數據造成的數據不一致,但這樣,如果線程 C 在讀數據、線程 D 也在讀數據,讀數據是不會改變數據的, 沒有必要加鎖, 但是還是加鎖了, 降低了程序的性能。因為這個, 才誕生了讀寫鎖ReadWriteLock 。 ReadWriteLock 是 一 個 讀 寫 鎖 接 口 , ReentrantReadWriteLock 是ReadWriteLock 接口的一個具體實現,實現了讀寫的分離,讀鎖是共享的,寫鎖是獨占的, 讀和讀之間不會互斥,讀和寫、寫和讀、寫和寫之間才會互斥,提升了讀寫的性能。
21、FutureTask 是什么
這個其實前面有提到過,FutureTask 表示一個異步運算的任務。FutureTask 里面可以傳入一個 Callable 的具體實現類,可以對這個異步運算的任務的結果進行等待獲取、判斷是否已經完成、取消任務等操作。當然,由于 FutureTask 也是 Runnable 接口的實現類,所以FutureTask 也可以放入線程池中。
22、synchronized 和 ReentrantLock 的區別
synchronized 是和 if、else、for、while 一樣的關鍵字,ReentrantLock 是類,這是二者的本質區別。既然 ReentrantLock 是類,那么它就提供了比 synchronized 更多更靈活的特性,可以被繼承、可以有方法、可以有各種各樣的類變量,ReentrantLock 比 synchronized 的擴展性體現在幾點上:
(1) ReentrantLock 可以對獲取鎖的等待時間進行設置,這樣就避免了死鎖
(2) ReentrantLock 可以獲取各種鎖的信息
(3) ReentrantLock 可以靈活地實現多路通知
另外,二者的鎖機制其實也是不一樣的。ReentrantLock 底層調用的是 Unsafe 的 park 方法加鎖,synchronized 操作的應該是對象頭中 mark word,這點我不能確定。
23、什么是樂觀鎖和悲觀鎖
(1) 樂觀鎖:
就像它的名字一樣,對于并發間操作產生的線程安全問題持樂觀狀態,樂觀鎖認為競爭不總 是會發生,因此它不需要持有鎖,將比較-替換這兩個動作作為一個原子操作嘗試去修改內存中的變量,如果失敗則表示發生沖突,那么就應該有相應的重試邏輯。
(2) 悲觀鎖:
還是像它的名字一樣,對于并發間操作產生的線程安全問題持悲觀狀態,悲觀鎖認為競爭總 是會發生,因此每次對某資源進行操作時,都會持有一個獨占的鎖,就像 synchronized,不管三七二十一,直接上了鎖就操作資源了。
24、線程 B 怎么知道線程 A 修改了變量
(1) volatile 修飾變量
(2) synchronized 修飾修改變量的方法
(3) wait/notify
(4) while 輪詢
25、synchronized、volatile、CAS 比較
(1) synchronized 是悲觀鎖,屬于搶占式,會引起其他線程阻塞。
(2) volatile 提供多線程共享變量可見性和禁止指令重排序優化。
(3) CAS 是基于沖突檢測的樂觀鎖(非阻塞)
26、sleep 方法和 wait 方法有什么區別?
這個問題常問,sleep 方法和 wait 方法都可以用來放棄 CPU 一定的時間,不同點在于如果線程持有某個對象的監視器,sleep 方法不會放棄這個對象的監視器,wait 方法會放棄這個對象的監視器
27、ThreadLocal?是什么?有什么用?
ThreadLocal 是一個本地線程副本變量工具類。主要用于將私有線程和該線程存放的副本對象做一個映射,各個線程之間的變量互不干擾,在高并發場景下,可以實現無狀態的調用, 特別適用于各個線程依賴不通的變量值完成操作的場景。簡單說 ThreadLocal 就是一種以空間 換 時 間 的 做 法 , 在 每 個 Thread 里 面 維 護 了 一 個 以 開 地 址 法 實 現 的
ThreadLocal.ThreadLocalMap,把數據進行隔離,數據不共享,自然就沒有線程安全方面的問題了。
28、為什么 wait()方法和 notify()/notifyAll()方法要在同步塊中被調用
這是 JDK 強制的,wait()方法和 notify()/notifyAll()方法在調用前都必須先獲得對象的鎖
29、多線程同步有哪幾種方法?
Synchronized 關鍵字,Lock 鎖實現,分布式鎖等。
30、線程的調度策略
線程調度器選擇優先級最高的線程運行,但是,如果發生以下情況,就會終止線程的運行:
(1) 線程體中調用了 yield 方法讓出了對 cpu 的占用權利
(2) 線程體中調用了 sleep 方法使線程進入睡眠狀態
(3) 線程由于 IO 操作受到阻塞
(4) 另外一個更高優先級線程出現
(5) 在支持時間片的系統中,該線程的時間片用完
31、ConcurrentHashMap 的并發度是什么
ConcurrentHashMap 的并發度就是 segment 的大小,默認為 16,這意味著最多同時可以有16 條線程操作 ConcurrentHashMap,這也是 ConcurrentHashMap 對 Hashtable 的最大優勢,任何情況下,Hashtable 能同時有兩條線程獲取 Hashtable 中的數據嗎?
32、Linux 環境下如何查找哪個線程使用 CPU 最長
(1) 獲取項目的 pid,jps 或者 ps -ef | grep java
(2) top -H -p pid,順序不能改變
33、Java 死鎖以及如何避免?
Java 中的死鎖是一種編程情況,其中兩個或多個線程被永久阻塞,Java 死鎖情況出現至少兩個線程和兩個或更多資源。
Java 發生死鎖的根本原因是:在申請鎖時發生了交叉閉環申請
34、死鎖的原因
(1) 是多個線程涉及到多個鎖,這些鎖存在著交叉,所以可能會導致了一個鎖依賴的閉環。例如:線程在獲得了鎖 A 并且沒有釋放的情況下去申請鎖 B,這時,另一個線程已經獲得了鎖 B,在釋放鎖 B 之前又要先獲得鎖 A,因此閉環發生,陷入死鎖循環。
(2) 默認的鎖申請操作是阻塞的。
所以要避免死鎖,就要在一遇到多個對象鎖交叉的情況,就要仔細審查這幾個對象的類中的 所有方法,是否存在著導致鎖依賴的環路的可能性。總之是盡量避免在一個同步方法中調用 其它對象的延時方法和同步方法。
35、怎么喚醒一個阻塞的線程
如果線程是因為調用了 wait()、sleep()或 者 join()方法而導致的阻塞,可以中斷線程,并且通過拋出 InterruptedException 來喚醒它;如果線程遇到了 IO 阻塞,無能為力,因為 IO 是操作系統實現的,Java 代碼并沒有辦法直接接觸到操作系統。
36、不可變對象對多線程有什么幫助
前面有提到過的一個問題,不可變對象保證了對象的內存可見性,對不可變對象的讀取不需 要進行額外的同步手段,提升了代碼執行效率。
37、什么是多線程的上下文切換
多線程的上下文切換是指 CPU 控制權由一個已經正在運行的線程切換到另外一個就緒并等待獲取 CPU 執行權的線程的過程。
38、如果你提交任務時,線程池隊列已滿,這時會發生什么
這里區分一下:
(1)如果使用的是無界隊列 LinkedBlockingQueue,也就是無界隊列的話,沒關系,繼續添加任務到阻塞隊列中等待執行,因為 LinkedBlockingQueue 可以近乎認為是一個無窮大的隊列,可以無限存放任務
( 2 ) 如果 使 用的 是 有界 隊 列 比如 ArrayBlockingQueue , 任務 首 先會 被 添加 到ArrayBlockingQueue 中,ArrayBlockingQueue 滿了,會根據 maximumPoolSize 的值增加線程數量,如果增加了線程數量還是處理不過來,ArrayBlockingQueue 繼續滿,那么則會使用拒絕策略 RejectedExecutionHandler 處理滿了的任務,默認是 AbortPolicy
39、Java 中用到的線程調度算法是什么
搶占式。一個線程用完 CPU 之后,操作系統會根據線程優先級、線程饑餓情況等數據算出一個總的優先級并分配下一個時間片給某個線程執行。
40、什么是線程調度器(Thread Scheduler)和時間分片(TimeSlicing)?
線程調度器是一個操作系統服務,它負責為 Runnable 狀態的線程分配 CPU 時間。一旦我們創建一個線程并啟動它,它的執行便依賴于線程調度器的實現。時間分片是指將可用的CPU 時間分配給可用的 Runnable 線程的過程。分配 CPU 時間可以基于線程優先級或者線程等待的時間。線程調度并不受到 Java 虛擬機控制,所以由應用程序來控制它是更好的選擇(也就是說不要讓你的程序依賴于線程的優先級)。
41、什么是自旋
很多 synchronized 里面的代碼只是一些很簡單的代碼,執行時間非常快,此時等待的線程
都加鎖可能是一種不太值得的操作,因為線程阻塞涉及到用戶態和內核態切換的問題。既然synchronized 里面的代碼執行得非常快, 不妨讓等待鎖的線程不要被阻塞, 而是在synchronized 的邊界做忙循環,這就是自旋。如果做了多次忙循環發現還沒有獲得鎖,再阻塞,這樣可能是一種更好的策略。
42、Java Concurrency API 中的 Lock 接口(Lock interface)是什么?對比同步它有什么優勢?
Lock 接口比同步方法和同步塊提供了更具擴展性的鎖操作。他們允許更靈活的結構,可以具有完全不同的性質,并且可以支持多個相關類的條件對象。
它的優勢有:
(1) 可以使鎖更公平
(2) 可以使線程在等待鎖的時候響應中斷
(3) 可以讓線程嘗試獲取鎖,并在無法獲取鎖的時候立即返回或者等待一段時間
(4) 可以在不同的范圍,以不同的順序獲取和釋放鎖
43、單例模式的線程安全性
老生常談的問題了,首先要說的是單例模式的線程安全意味著:某個類的實例在多線程環境 下只會被創建一次出來。單例模式有很多種的寫法,我總結一下:
(1) 餓漢式單例模式的寫法:線程安全
(2) 懶漢式單例模式的寫法:非線程安全
(3) 雙檢鎖單例模式的寫法:線程安全
44、Semaphore 有什么作用
Semaphore 就是一個信號量,它的作用是限制某段代碼塊的并發數。Semaphore 有一個構造函數,可以傳入一個 int 型整數 n,表示某段代碼最多只有 n 個線程可以訪問,如果超出了 n,那么請等待,等到某個線程執行完畢這段代碼塊,下一個線程再進入。由此可以看出如果 Semaphore 構造函數中傳入的 int 型整數 n=1,相當于變成了一個 synchronized 了。
45、Executors 類是什么?
Executors 為 Executor,ExecutorService,ScheduledExecutorService,ThreadFactory 和 Callable
類提供了一些工具方法。Executors 可以用于方便的創建線程池
46、線程類的構造方法、靜態塊是被哪個線程調用的
這是一個非常刁鉆和狡猾的問題。請記住:線程類的構造方法、靜態塊是被 new 這個線程類所在的線程所調用的,而 run 方法里面的代碼才是被線程自身所調用的。
如果說上面的說法讓你感到困惑,那么我舉個例子,假設 Thread2 中 new 了 Thread1,main
函數中 new 了 Thread2,那么:
(1) Thread2 的構造方法、靜態塊是 main 線程調用的,Thread2 的 run()方法是 Thread2 自己調用的
(2) Thread1 的構造方法、靜態塊是 Thread2 調用的,Thread1 的 run()方法是 Thread1 自己調用的
47、同步方法和同步塊,哪個是更好的選擇?
同步塊,這意味著同步塊之外的代碼是異步執行的,這比同步整個方法更提升代碼的效率。 請知道一條原則:同步的范圍越小越好。
48、Java 線程數過多會造成什么異常?
(1) 線程的生命周期開銷非常高
(2) 消耗過多的 CPU 資源
如果可運行的線程數量多于可用處理器的數量,那么有線程將會被閑置。大量空閑的線程會 占用許多內存,給垃圾回收器帶來壓力,而且大量的線程在競爭 CPU 資源時還將產生其他性能的開銷。
(3) 降低穩定性
JVM 在可創建線程的數量上存在一個限制,這個限制值將隨著平臺的不同而不同,并且承受著多個因素制約,包括 JVM 的啟動參數、Thread 構造函數中請求棧的大小,以及底層操作系統對線程的限制等。如果破壞了這些限制,那么可能拋出 OutOfMemoryError 異常。
Ps:由于篇幅限制,筆記無法全部為大家展示出來,就以截圖主要內容的形式讓大家參考啦,需要完整版的小伙伴可以 點擊這里即可獲取到文章中的文檔,資料!
一、Java 基礎
- 什么是 Java 程序的主類?應用程序和小程序的主類有何不同?
- 構造器 Constructor 是否可被 override?
- String StringBuffer 和 StringBuilder 的區別是什么?String 為什么是不可變的?
- 對象的相等與指向他們的引用相等,兩者有什么不同?
- 重載和重寫的區別?
- 在一個靜態方法內調用一個非靜態成員為什么是非法的?
- 簡述線程,程序、進程的基本概念。以及他們之間關系是什么
- 什么是方法的返回值?返回值在類的方法里的作用是什么?
- 一個類的構造方法的作用是什么 若一個類沒有聲明構造方法,該程序能正確執行嗎 ?為什么?
- Java 面向對象編程三大特性: 封裝 繼承 多態
- Java 序列化中如果有些字段不想進行序列化 怎么辦?
- 在調用子類構造方法之前會先調用父類沒有參數的構造方法,其目的是?
- 線程有哪些基本狀態?
- 創建一個對象用什么運算符?對象實體與對象引用有何不同?
- 成員變量與局部變量的區別有哪些?
二、Java 中級
- Spring 的 AOP 和 IOC 是什么?使用場景有哪些?Spring 事務,事務的屬性,數據庫隔離級別
- Spring 和 SpringMVC,MyBatis 以及 SpringBoot 的注解分別有哪些?
- SpringCould 組件有哪些,它們的作用是什么?微服務的 CAP 是什么?BASE 是什么?
- HashMap 底層實現原理,紅黑樹,B+樹,B 樹的結構原理,CAS(比較與交換)實現原理
- Redis 支持的數據類型以及使用場景,持久化,哨兵機制,緩存擊穿,緩存穿透
- 線程是什么,有幾種實現方式,它們之間的區別是什么,線程池實現原理,JUC 并發包
- 安全性問題(數據篡改(拿到別人的 URL,篡改數據(金額)發送給系統))
- 索引使用的限制條件,sql 優化有哪些,數據同步問題(緩存,數據庫數據同步)
- 分布式事務
- 堆溢出,棧溢出的出現場景以及解決方案
- 悲觀鎖,樂觀鎖,讀寫鎖,行鎖,表鎖,自旋鎖,死鎖,分布式鎖,線程同步鎖,公平鎖,非公平鎖分別是什么?
- 初始化 Bean 對象有幾個步驟,它的生命周期
- JVM 內存模型,算法,垃圾回收器,調優,類加載機制(雙親委派),創建一個對象,這個對象在內存中是怎么分配的?
- Dubbo 的運行原理,與 SpringCould 相比它為什么效率要高一些,Zookeeper 底層原理
- 說出幾種 MQ 之間的區別,以及為什么使用這種 MQ,消息重復發送(冪等性),消息發送失敗,消息掉包,長時間收不到消息,發送的消息太大造成接收不成功
三、Java 高級
- 為什么使用消息隊列?消息隊列有什么優點和缺點?Kafka、ActiveMQ、RabbitMQ、RocketMQ 都有什么優點和缺點?
- 如何保證消息不被重復消費?或者說,如何保證消息消費的冪等性?
- 如何解決消息隊列的延時以及過期失效問題?消息隊列滿了以后該怎么處理?有幾百萬消息持續積壓幾小時,說說怎么解決?
- redis 集群模式的工作原理能說一下么?在集群模式下,redis 的 key 是如何尋址的?分布式尋址都有哪些算法?了解一致性 hash 算法嗎?
- 了解什么是 redis 的雪崩、穿透和擊穿?redis 崩潰之后會怎么樣?系統該如何應對這種情況?如何處理 redis 的穿透?
- 為什么要分庫分表(設計高并發系統的時候,數據庫層面該如何設計)?用過哪些分庫分表中間件?不同的分庫分表中間件都有什么優點和缺點?你們具體是如何對數據庫如何進行垂直拆分或水平拆分的?
- 有沒有做 MySQL 讀寫分離?如何實現 MySQL 的讀寫分離?MySQL 主從復制原理的是啥?如何解決 MySQL 主從同步的延時問題?
- 說一下的 dubbo 的工作原理?注冊中心掛了可以繼續通信嗎?說說一次 rpc 請求的流程?
- 如何基于 dubbo 進行服務治理、服務降級、失敗重試以及超時重試?
- 集群部署時的分布式 session 如何實現?
- 服務注冊和發現是什么意思?Spring Cloud 如何實現?
- 一般實現分布式鎖都有哪些方式?使用 redis 如何設計分
- 布式鎖?使用 zk 來設計分布式鎖可以嗎?這兩種分布式鎖的實現方式哪種效率比較高?
- dubbo 的 spi 思想是什么?
- 如何設計可以動態擴容縮容的分庫分表方案?
四、分布式
- ActiveMQ 中的消息重發時間間隔和重發次數嗎?
- Kafka 創建 Topic 是如何將分區放置到不同的 Broker 中
- Kafka 判斷一個節點是否還活著有哪兩個條件?
- Kafka 消息是采用 Pull 模式,還是 Push 模式?
- memcached 和服務器的 local cache(比如 PHP 的 APC、mmap 文件等)相比,有什么優缺點?
- 我需要把 memcached 中的 item 批量導出導入,怎么辦?
- memcached 的多線程是什么?如何使用它們?
- MongoDB 在 A:{B,C}上建立索引,查詢 A:{B,C}和 A:{C,B}都會使用索引嗎?
- MongoDB 支持存儲過程嗎?如果支持的話,怎么用?
- 如何理解 MongoDB 中的 GridFS 機制,MongoDB 為何使用 GridFS 來存儲文件?
- 在 Nginx 中,如何使用未定義的服務器名稱來阻止處理請求?
- RabbitMQ 上的一個 queue 中存放的 message 是否有數量限制?
- 若 cluster 中擁有某個 queue 的 owner node 失效了,且該 queue 被聲明具有 durable 屬性,是否能夠成功從其他 node 上重新聲明該 queue ?
- 為什么說保證 message 被可靠持久化的條件是 queue 和 exchange 具有 durable 屬性,同時 message 具有 persistent 屬性才行?
- 為什么用緩存,用過哪些緩存,redis 和 memcache 的區別?
五、Spring 架構
- Spring Boot、Spring MVC 和 Spring 有什么區別?
- BeanFactory 和 ApplicationContext 有什么區別?
- 什么是基于 Java 的 Spring 注解配置? 給一些注解的例子.
- 請解釋 Spring Bean 的生命周期?
- Spring 框架中的單例 Beans 是線程安全的么?
- SpringMvc 的控制器是不是單例模式,如果是,有什么問題,怎么解決?
- SpringMVC 怎么樣設定重定向和轉發的?
- 當一個方法向 AJAX 返回特殊對象,比如 Object,List 等,需要做什么處理?
- SpringMvc 用什么對象從后臺向前臺傳遞數據的?
- 服務注冊和發現是什么意思?Spring Cloud 如何實現?
- 使用 Spring Cloud 有什么優勢?
- 什么是 Hystrix 斷路器?我們需要它嗎?
- 什么是 Spring Cloud Bus?我們需要它嗎?
- 如何實現 Spring Boot 應用程序的安全性?
- Spring Boot 配置的默認 H2 數據庫的名字是上面?為什么默認的數據庫名字是 testdb?
六、線程問題
- stop() 和 suspend() 方法為何不推薦使用?
- 同步和異步有何異同,在什么情況下分別使用它們?
- 線程間通信,wait 和 notify
- 什么是線程餓死,什么是活鎖?
- atomicinteger 和 volatile 等線程安全操作的關鍵字的理解和使用
- volatile 變量是什么?volatile 變量和 atomic 變量有什么不同?
- 當一個線程進入一個對象的一個 synchronized 方法后,其它線程是否可進入此對象的其它方法?
- 簡述 synchronized 和 java.util.concurrent.locks.Lock 的異同?
- 多線程之間通信的同步問題,synchronized 鎖的是對象,衍伸出和 synchronized 相關很多的具體問題,例如同一個類不同方法都有 synchronized 鎖,一個對象是否可以同時訪問。或者一個類的 static 構造方法加上 synchronized 之后的鎖的影響。
- volatile 類型變量提供什么保證?能使得一個非原子操作變成原子操作嗎?
- 了解可重入鎖的含義,以及 ReentrantLock 和 synchronized 的區別
- Java 創建線程之后,直接調用 start()方法和 run()的區別
- 同步的數據結構,例如 concurrentHashMap 的源碼理解以及內部實現原理,為什么它是同步的且效率高
- 常用的線程池模式以及不同線程池的使用場景
- newFixedThreadPool 此種線程池如果線程數達到最大值后會怎么辦,底層原理。
七、網絡方面
- 為什么要三次握手
- 二次握手有什么問題
- 三次握手有哪些缺陷
- TCP 是如何控制流量的
- 發送方發送頻率過高造成丟包,TCP 是如何解決的
- HTTPs 為什么要用對稱加密+非對稱加密,相對于只使用非對稱加密有什么好處
- 講一下 OSI 網絡架構
- HTTP 在哪一層
- HTTP 報文結構
- HTTP 首部字段
- HTTPs 加密在哪一層實現
- http 是無狀態通信,http 的請求方式有哪些,可以自己定義新的請求方式么。
- socket 通信,以及長連接,分包,連接異常斷開的處理。
- socket 通信模型的使用,AIO 和 NIO。
- socket 框架 netty 的使用,以及 NIO 的實現原理,為什么是異步非阻塞
八、MySQL 數據庫
- 務四大特性(ACID)原子性、一致性、隔離性、持久性?
- 查詢語句不同元素(where、jion、limit、group by、having 等等)執行先后順序?
- MySQL 常見的三種存儲引擎(InnoDB、MyISAM、MEMORY)的區別?
- MySQL 的 MyISAM 與 InnoDB 兩種存儲引擎在,事務、鎖級別,各自的適用場景?
- mysql 高并發環境解決方案?
- 事務的并發?事務隔離級別,每個級別會引發什么問題,MySQL 默認是哪個級別?
- MySQL B+Tree 索引和 Hash 索引的區別?
- 有哪些鎖(樂觀鎖悲觀鎖),select 時怎么加排它鎖?
- sql 查詢語句確定創建哪種類型的索引?如何優化查詢?
- 聚集索引和非聚集索引區別?
- mysql 都有什么鎖,死鎖判定原理和具體場景,死鎖怎么解決?
- 非關系型數據庫和關系型數據庫區別,優勢比較?
- MySQL 慢查詢怎么解決?
- 數據庫的讀寫分離、主從復制,主從復制分析的 7 個問題?
- 數據庫崩潰時事務的恢復機制(REDO 日志和 UNDO 日志)?
九、Redis 緩存
- redis 事務相關命令有哪些?
- 為什么要用 redis /為什么要用緩存(高性能、高并發)
- 為什么要用 redis 而不用 map/guava 做緩存?
- redis 和 memcached 的區別
- 請介紹一下 Redis 的數據類型 SortedSet(zset)以及底層實現機制?
- redis 常見數據結構以及使用場景分析(String、Hash、List、Set、Sorted Set)
- redis 設置過期時間
- redis 內存淘汰機制(MySQL 里有 2000w 數據,Redis 中只存 20w 的數據,如何保證 Redis 中的數據都是熱點數據?)
- redis 持久化機制(怎么保證 redis 掛掉之后再重啟數據可以進行恢復)
- redis 事務
- Redis 常見異常及解決方案(緩存穿透、緩存雪崩、緩存預熱、緩存降級)
- 分布式環境下常見的應用場景(分布式鎖、分布式自增 ID)
- Redis 集群模式(主從模式、哨兵模式、Cluster 集群模式)
- 如何解決 Redis 的并發競爭 Key 問題
- 如何保證緩存與數據庫雙寫時的數據一致性?
十、JVM 相關
- 如何判斷一個對象是否存活?(或者 GC 對象的判定方法)
- java 中垃圾收集的方法有哪些?
- 簡述 java 垃圾回收機制?
- GC 的兩種判定方法?
- Minor GC 與 Full GC 分別在什么時候發生?
- JVM 內存分哪幾個區,每個區的作用是什么?
- GC 收集器有哪些?CMS 收集器與 G1 收集器的特點
- GC 的三種收集方法:標記清除、標記整理、復制算法的原理與特點,分別用在什么地方,如果讓你優化收集方法,有什么思路?
- 類加載器雙親委派模型機制?
- java 類加載過程?
- 簡述 java 類加載機制?
- 什么是類加載器,類加載器有哪些?
- 簡述 java 內存分配與回收策略以及 Minor GC 和 Major GC
- HotSpot 虛擬機對象探秘
- HotSpot 垃圾收集器
十一、調優方面
- 垃圾回收器的基本原理是什么?垃圾回收器可以馬上回收內存嗎?有什么辦法主動通知虛擬機進行垃圾回收?
- Java 中會存在內存泄漏嗎,請簡單描述。
- 如果對象的引用被置為 null,垃圾收集器是否會立即釋放對象占用的內存?
- finalize() 方法什么時候被調用?析構函數 (finalization) 的目的是什么?
- 串行(serial)收集器和吞吐量(throughput)收集器的區別是什么?
- 什么是分布式垃圾回收(DGC)?它是如何工作的?
- 你怎樣給 tomcat 去調優?
- Tomcat 的優化經驗
- 在 Java 中,對象什么時候可以被垃圾回收?
- System.gc() 和 Runtime.gc() 會做什么事情?
- Java 中會存在內存泄漏嗎,請簡單描述
- GC 是什么? 為什么要有 GC?
- JVM 的永久代中會發生垃圾回收么?
- tomcat 有哪幾種 Connector 運行模式(優化)?
- 內存調優
十二、設計模式
- 21 種設計模式知識要點
- 請列舉出在 JDK 中幾個常用的設計模式?
- 什么是設計模式?你是否在你的代碼里面使用過任何設計模式?
- 在 Java 中,什么叫觀察者設計模式(observer design pattern)?
- 使用工廠模式最主要的好處是什么?在哪里使用?
- 在 Java 中,什么時候用重載,什么時候用重寫?
- 在 Java 中,為什么不允許從靜態方法中訪問非靜態變量?
- 設計一個 ATM 機,請說出你的設計思路?
- 舉一個用 Java 實現的裝飾模式(decorator design pattern)?它是作用于對象層次還是類層次
- 舉例說明什么情況下會更傾向于使用抽象類而不是接口?
十三、算法 &數據結構
- 如何僅用遞歸函數和棧操作逆序一個棧?
- 將單向鏈表按某值劃分成左邊小、中間相等、右邊大的形式
- 分別用遞歸和非遞歸方式實現二叉樹先序、中序和后序遍歷
- 斐波拉契系列問題的遞歸和動態規劃
- 判斷字符數組中是否有的字符都只出現過一次
- 在有序但含有空的數組中查找字符串
- 只用 2GB 內存在 20 億個整數中找到出現次數最多的數
- 未排序數組中累加和小于或等于給定值的最長子數組長度
- 從 5 隨機到 7 隨機及其擴展
- 最大值減去最小值小于或等于 num 的子數組數量
- 環形單鏈表的約瑟夫問題
- 將單鏈表的每 K 個節點之間逆序
- 在二叉樹中找到累加和為指定值的最長路徑長度
- 判斷一棵二叉樹是否為搜索二叉樹和完全二叉樹
- 最長公共子序列問題
十四、并發
- 什么是可重入性 , 為什么說 Synchronized 是可重入鎖?
- 為什么說 Synchronized 是一個悲觀鎖?樂觀鎖的實現原理又是什么?什么是 CAS,它有 什么特性?
- 樂觀鎖一定就是好的嗎?
- JVM 對 Java 的原生鎖做了哪些優化?
- ReentrantLock 是如何實現可重入性的?
- 跟 Synchronized 相 比 ,可重入鎖 ReentrantLock 其實現原理有什么不同?
- 如何讓 Java 的線程彼此同步?你了解過哪些同步器?請分別介紹下 。
- CyclicBarrier 和 CountDownLatch 看起來很相似,請對比下呢?
- 線程池中的線程是怎么創建的?是一開始就隨著線程池的啟動創建好的嗎?
- 既然提到可以通過配置不同參數創建出不同的線程池,那么 Java 中默認實現好的線程池又 有哪些呢?請比較它們的異同
- 請談談 volatile 有什么特點,為什么它能保證變量對所有線程的可見性?
- 什么是 Java 的內存模型,Java 中各個線程是怎么彼此看到對方的變量的?
- 既然 volatile 能夠保證線程間的變量可見性,是不是就意味著基于 volatile 變量的運算就是并 是安全的 ?
- 很多人都說要慎用 ThreadLocal,談談你的理解,使用 ThreadLocal 需要注意些什么?
- 請談談 AQS 框架是怎么回事兒?
十五、操作系統/Linux
- 死鎖產生的原因
- 進程、線程區別,什么時候用線程
- 如何實現一個線程池,Java 中線程池如何進行配置
- linux 中有哪些常見的指令,進行介紹
- select、poll、epoll 有沒有了解過,講解一下
- 線程切換,引申到 Java 阻塞??運行
- 如何分層復制/home 目錄到另一個目錄?
- 什么是安裝 Linux 所需的最小分區數量,以及如何查看系統啟動信息?
- 如何暫停一個正在運行的進程,把其放在后臺(不運行)?
- 什么是頁面錯誤,它是怎么發生的?
以上是總結出的最全 Java 面試題目,以下是最新總結出的 BAT 面試 java 必考題目和答案。