JAVA那點破事!併發、IO模型、集合、執行緒池、死鎖、非阻塞、AQS....

語言: CN / TW / HK

大家好,我是Tom哥~

關於Java面試, 面試官一般喜歡問哪些問題?

本文對一些高頻問題做了彙總,為了便於大家查詢問題,瞭解全貌,整理個目錄,我們可以快速全域性瞭解關於 JAVA

接下來,我們逐條來看看每個問題及答案

JDK、JRE、JVM 三者有什麼關係?

答案:

  • JDK(全稱 Java Development Kit),Java開發工具包,能獨立建立、編譯、執行程式。

JDK = JRE + java開發工具(javac.exe/java.exe/jar.exe)

  • JRE(全稱 Java Runtime Environment),能執行已編譯好的程式,但不能建立程式

JRE = JVM + java核心類庫

  • JVM (全稱 Java Virtual Machine),java虛擬機器。

java建立物件有哪些方式?

答案:

  • 1、new 建立物件

  • 2、反射機制建立物件

  • 3、通過clone方法

  • 4、序列化機制

== 和 equals 有什麼區別?

答案:

  • == ,如果是基本資料型別,比較兩個值是否相等;如果是物件,比較兩個物件的引用是否相等,指向同一塊記憶體區域

  • equals,用於物件之間,比較兩個物件的值是否相等。

hashCode()的作用?

答案:生成雜湊碼,int型別,用於確定該物件在雜湊表中的索引位置。每個類中都包含這個方法。

String、StringBuffer、StringBuilder 有什麼區別?

答案

  • 1、String。採用 final 修飾,物件不可變,執行緒安全。如果對一個已經存在的String物件修改,會重新建立一個新物件,並把值放進去。
  • 2、StringBuffer,採用 synchronized 關鍵字修飾,執行緒安全
  • 3、StringBuilder,非執行緒安全,但效率會更高些,適用於單執行緒。

try-catch-finally,如catch中return了,還會執行finally嗎?

答案:當然啦,會在return之前執行。

程序和執行緒的區別?

答案:

  • 程序:是一個程式的執行流程,是系統進行資源分配和排程的基本單位,作用是程式能夠併發執行提高資源利用率。因為程序的建立、銷燬、切換產生大量的時間和空間的開銷,所以程序的數量不能太多

  • 執行緒:是比程序更小的能獨立執行的基本單位,他是程序的一個實體,可以減少程式併發執行時的時間和空間開銷,使得作業系統具有更好的併發性。多個執行緒可以共享程序的系統資源。執行緒基本不擁有系統資源,只有一些執行時必不可少的資源,比如程式計數器、暫存器和棧,程序則佔有堆。

synchronized 的內部原理?

答案:java提供的原子性內建鎖,也被稱為監視器鎖。使用 synchronized 之後,會在編譯之後在同步的程式碼塊前後加上 monitorenter monitorexit 位元組碼指令,依賴作業系統底層互斥鎖實現。實現原子性操作和解決共享變數的記憶體可⻅性問題。

內部處理過程(內部有兩個佇列waitSet和entryList。):

  • 1、當多個執行緒進入同步程式碼塊時,首先進入 entryList
  • 2、有一個執行緒獲取到monitor鎖後,就賦值給當前執行緒,並且計數器+1

  • 3、如果執行緒呼叫wait方法,將釋放鎖,當前執行緒置為null,計數器-1,同時進入 waitSet 等待被喚醒,呼叫notify或者notifyAll之後又會進入entryList競爭鎖
  • 4、如果執行緒執行完畢,同樣釋放鎖,計數器-1,當前執行緒置為null

synchronized 和 ReentrantLock 的區別?

答案:

  • ReentrantLock 實現了Lock介面。synchronized是系統關鍵字

  • ReentrantLock需要手動指定鎖範圍。synchronized 支援同步塊、同步方法

  • 都具有可重入性

  • 預設都是非公平鎖。但 ReentrantLock 還支援公平模式,但效能會急劇下降

  • ReentrantLock 需要顯示的獲取鎖、釋放鎖

  • ReentrantLock 支援多種方式獲取鎖。

    • lock():阻塞模式來獲取鎖

    • lockInterruptibly:阻塞式獲取鎖,支援中斷

    • tryLock():非阻塞模式嘗試獲取鎖

    • tryLock(long timeout, TimeUnit unit):同上,支援時間設定

  • ReentrantLock 可以同時繫結多個Condition條件物件。

AQS (AbstractQueuedSynchronizer 抽象佇列同步器 )的原理?

答案:AQS內部維護一個 state狀態位 ,嘗試加鎖的時候通過 CAS(CompareAndSwap) 修改值,如果成功設定為 1,並且把當前執行緒ID賦值,則代表加鎖成功。

一旦獲取到鎖,其他的執行緒將會被阻塞進入阻塞佇列自旋,獲得鎖的執行緒釋放鎖的時候將會喚醒阻塞佇列中的執行緒,釋放鎖的時候則會把 state 重新置為0,同時 當前執行緒ID 置為空。

CAS 有什麼缺點?

答案:在多執行緒場景下,更新變數值被其他執行緒跑了個對衝,CAS會出現ABA問題。解決方式有很多,

  • 可以通過,自增版本號方式,永遠不會回退

  • Java中提供了 AtomicStampedReference ,增加了標誌欄位,更新時不光檢查值,還要檢查當前的標誌是否等於預期標誌,全部滿足條件才會更新
  • 更多內容, CAS原理分析,解決銀行轉賬ABA難題

Java 都用過哪些鎖?

答案:

  • 樂觀鎖、悲觀鎖

  • 分散式鎖

  • 獨佔鎖、共享鎖

  • 互斥鎖

  • 讀寫鎖

  • 公平鎖、非公平鎖

  • 可重入鎖

  • 自旋鎖

  • 分段鎖

  • 鎖升級(無鎖|偏向鎖|輕量級鎖|重量級鎖)

  • 鎖優化技術(鎖粗化、鎖消除)

  • 更多詳細內容, 一文全面梳理各種鎖機制

HashMap原理?

答案:內部由陣列和連結串列組成,非執行緒安全。JDK1.7和1.8的主要區別在於頭插和尾插方式的修改,頭插容易導致HashMap連結串列死迴圈,並且1.8之後加入 紅黑樹 對效能有提升。

  • put插入:key 計算hash值,取模,找到陣列位置,如果陣列中沒有元素直接存入,反之,則判斷key是否相同,key相同就覆蓋,否則就會插入到連結串列的尾部。如果連結串列的⻓度超過8且資料總量超過64,則會轉換成 紅黑樹 。最後判斷元素個數是否超過預設的⻓度(16)*負載因子(0.75),也就是12,超過則進行擴容。
  • get查詢:計算出hash值,然後去陣列查詢,是紅黑樹就去紅黑樹查,連結串列就遍歷連結串列查詢就可以了。

紅黑樹的時間複雜度 O(logn);連結串列的時間複雜度 O(n),當連結串列過長時,紅黑樹能大大提高查詢效能。

ConcurrentHashMap 如何能保證執行緒安全的?

答案:ConcurrentHashmap在JDK1.7和1.8的版本改動比較大。

  • 1.7 使用Segment + HashEntry 分段鎖的方式實現, Segment 繼承於 ReentrantLock HashEntry 儲存鍵值對資料。
  • 1.8 採用陣列+ 連結串列 + 紅黑樹。鎖設計上拋棄了Segment分段鎖,採用 CAS + synchronized 實現。

ArrayList 和 LinkedList 有什麼區別?

答案:

1、Arraylist

  • 非執行緒安全

  • 底層採用陣列儲存

  • 插入、刪除元素,時間複雜度受位置影響。預設是新增在列表的末尾,如果在位置 k 插入或刪除一個元素,需要將k後面的元素後移或前移一位。

  • 支援隨機訪問,根據索引下標序號,可以快速定位元素

  • 需要連續的記憶體空間,中間不能有碎片

2、LinkedList

  • 非執行緒安全

  • 底層採用雙向迴圈連結串列儲存

  • 插入、刪除元素,時間複雜度不受位置影響,只需要更改位置 k的前後指標地址,時間複雜度為 O(1)

  • 不支援高效的隨機訪問

  • 不需要連續的記憶體空間

volatile 原理?

答案:volatile宣告的變數,值被更新後對其他執行緒立即可⻅。

CPU會根據快取一致性協議,強制執行緒重新從主記憶體載入最新的值到自己的工作記憶體中,而不是直接用cpu快取中的值。

ThreadLocal 原理?

答案:ThreadLocal有一個靜態內部類 ThreadLocalMap ThreadLocalMap 又包含了一個Entry陣列,Entry本身是一個弱引用,他的key是指向ThreadLocal的弱引用,Entry具備儲存key -- value鍵值對的能力。

在使用完之後呼叫 remove方法 刪除Entry物件,避免出現記憶體洩露。

什麼是工作記憶體、主記憶體?

答案:

  • 工作記憶體:暫存器、CPU快取(L1、L2、L3)

  • 主記憶體:主要是指實體記憶體

JUC併發包用過哪些執行緒安全的類?

答案:

  • ConcurrentHashMap

  • CountDownLatch、CyclicBarrier

  • Semaphore

  • BlockingQueue

  • ThreadPoolExecutor

  • ReentrantLock、ReentrantReadWriteLock

  • CompletableFuture

ThreadPoolExecutor 有哪些構造引數?

答案:核心執行緒數、最大執行緒數、最大空閒時間、時間單位、任務佇列、執行緒工廠、拒絕策略

ThreadPoolExecutor 的拒絕策略有哪些?

答案:

  • 1、AbortPolicy:直接丟棄任務,丟擲異常,這是預設策略

  • 2、CallerRunsPolicy:只用呼叫者所在的執行緒來處理任務

  • 3、DiscardOldestPolicy:丟棄等待佇列中最舊的任務,並執行當前任務

  • 4、DiscardPolicy:直接丟棄任務,也不丟擲異常

  • 5、使用 RejectedExecutionHandler 介面,自定義實現

執行緒有哪些狀態?是如何轉換?

答案:New、Runnable、Running、Blocked、Waiting、Timed Waiting、Terminated

IO 模型有哪五種?

答案:

1、阻塞IO。當 應用B 發起讀取資料申請時,如果核心資料沒有準備好,應用B會一直處於等待資料狀態,直到核心把資料準備好了交給應用B才結束。

2、非阻塞IO。當應用B發起讀取資料申請時,如果核心資料沒有準備好會即刻告訴應用B,不會讓B在這裡等待。

3、IO複用模型。程序通過將一個或多個fd傳遞給select,阻塞在select操作上,select幫我們偵測多個fd是否準備就緒,當有fd準備就緒時,select返回資料可讀狀態,應用程式再呼叫recvfrom讀取資料。

4、訊號IO。訊號驅動IO不是用迴圈請求詢問的方式去監控資料就緒狀態,而是在呼叫sigaction時候建立一個SIGIO的訊號聯絡,當核心資料準備好之後再通過SIGIO訊號通知執行緒資料準備好後的可讀狀態,當執行緒收到可讀狀態的訊號後,此時再向核心發起recvfrom讀取資料的請求,因為訊號驅動IO的模型下應用執行緒在發出訊號監控後即可返回,不會阻塞,所以這樣的方式下,一個應用執行緒也可以同時監控多個fd。

5、非同步IO。解決了應用程式需要先後 檢視資料是否就緒 傳送接收資料請求 兩個階段的模式,在非同步IO的模式下,只需要向核心傳送一次請求就可以完成狀態查詢和資料拷貝的所有操作。

阻塞IO 和 非阻塞IO 的區別?

答案:如果資料沒有就緒,在 檢視資料是否就緒 的這個階段是一直等待?還是直接返回一個標誌資訊。

關於我:前阿里P7技術專家,出過專利,競賽拿過獎,CSDN部落格專家,負責過電商交易、社群生鮮、網際網路金融等業務,多年團隊管理經驗。

關注公眾號「微觀技術」,後臺回覆 “演算法” ,免費領取資料

推薦閱讀

MYSQL 那點破事!索引、SQL調優、事務、B+樹、分表 ....

TCP網路那點破事!三次握手、四次揮手、TIME-WAIT ....

面試官問:如何保證 MQ訊息是有序的?

什麼是布隆過濾器?如何解決高併發快取穿透問題?

學會這10個設計原則,離架構師又進了一步!!!