前言
回首來看2020年,真的是印象中過的最快的一年了,真的是時間過的飛快,還沒反應過來年就誇完了,相信大家也已經開始上班了!俗話說新年新氣象,馬上就要到了一年之中最重要的金三銀四,之前一直有粉絲要求我整理一些java崗的面試題,年前一直沒時間,這次趁著元旦節給大家整理了一些一線網際網路公司java崗面試題主要是Java基礎+多執行緒+集合+JVM,滿滿的乾貨放在下面了!內容有點多,大家可以挑選自己需要的部分看!
Java 語⾔有哪些特點?
- 簡單易學;
- ⾯向物件(封裝,繼承,多型);
- 平臺⽆關性( Java 虛擬機器實現平臺⽆關性);
- 可靠性;
- 安全性;
- ⽀持多執行緒( C++ 語⾔沒有內建的多執行緒機制,因此必須調⽤作業系統的多執行緒功能來進⾏多執行緒程式設計,⽽ Java 語⾔卻提供了多執行緒⽀持);
⾯向物件和⾯向過程的區別
- ⾯向過程 :⾯向過程效能⽐⾯向物件⾼。 因為類調⽤時需要例項化,開銷⽐⼤,⽐消耗資源,所以當效能是最重要的考量因素的時候,⽐如單⽚機、嵌⼊式開發、Linux/Unix 等⼀般採⽤⾯向過程開發。但是,⾯向過程沒有⾯向物件易維護、易復⽤、易擴充套件。
- ⾯向物件 :⾯向物件易維護、易復⽤、易擴充套件。 因為⾯向物件有封裝、繼承、多型性的特性,所以可以設計出低耦合的系統,使系統更加靈活、更加易於維護。但是,⾯向物件效能⽐⾯向過程低。
什麼是java虛擬機器
- Java 虛擬機器(JVM)是運⾏ Java 位元組碼的虛擬機器。JVM 有針對不同系統的特定實現(Windows,Linux,macOS),⽬的是使⽤相同的位元組碼,它們都會給出相同的結果。
什麼是位元組碼?採⽤位元組碼的好處是什麼?
- 在 Java 中,JVM 可以理解的程式碼就叫做 位元組碼 (即副檔名為 .class 的⽂件),它不⾯向任何特定的處理器,只⾯向虛擬機器。Java 語⾔通過位元組碼的⽅式,在⼀定程度上解決了傳統解釋型語⾔執⾏效率低的問題,同時⼜保留了解釋型語⾔可移植的特點。所以 Java 程式運⾏時⾼效,⽽且,由於位元組碼並不針對⼀種特定的機器,因此,Java 程式⽆須重新編譯便可在多種不同作業系統的計算機上運⾏。
關於JVM和位元組碼
- Java 虛擬機器(JVM)是運⾏ Java 位元組碼的虛擬機器。JVM 有針對不同系統的特定實現(Windows,Linux,macOS),⽬的是使⽤相同的位元組碼,它們都會給出相同的結果。位元組碼和不同系統的 JVM 實現是 Java 語⾔“⼀次編譯,隨處可以運⾏”的關鍵所在。
JDK 和 JRE
- JDK 是 Java Development Kit,它是功能⻬全的 Java SDK。它擁有 JRE 所擁有的⼀切,還有編譯器(javac)和⼯具(如 javadoc 和 jdb)。它能夠建立和編譯程式。
- JRE 是 Java 運⾏時環境。它是運⾏已編譯 Java 程式所需的所有內容的集合,包括 Java 虛擬機器(JVM),Java 類庫,java 命令和其他的⼀些基礎構件。但是,它不能⽤於建立新程式。
Oracle JDK 和 OpenJDK 的對⽐
- Oracle JDK ⼤概每 6 個⽉發⼀次主要版本,⽽ OpenJDK 版本⼤概每三個⽉釋出⼀次。但這不是固定的,我覺得了解這個沒啥⽤處。
- OpenJDK 是⼀個參考模型並且是完全開源的,⽽ Oracle JDK 是 OpenJDK 的⼀個實現,並不是完全開源的;
- Oracle JDK ⽐ OpenJDK 更穩定。OpenJDK 和 Oracle JDK 的程式碼⼏乎相同,但 Oracle JDK 有更多的類和⼀些錯誤修復。因此,如果您想開發企業/商業軟體,我建議您選擇 Oracle JDK,因為它經過了徹底的測試和穩定。某些情況下,有些⼈提到在使⽤ OpenJDK 可能會遇到了許多應⽤程式崩潰的問題,但是,只需切換到 Oracle JDK 就可以解決問題;
- 在響應性和 JVM 效能⽅⾯,Oracle JDK 與 OpenJDK 相⽐提供了更好的效能;
- Oracle JDK 不會為即將釋出的版本提供⻓期⽀持,⽤戶每次都必須通過更新到最新版本獲得⽀持來獲取最新版本;
- Oracle JDK 根據⼆進位制程式碼許可協議獲得許可,⽽ OpenJDK 根據 GPL v2 許可獲得許可。
什麼是 Java 程式的主類 應⽤程式和⼩程式的主類有何不同?
- ⼀個程式中可以有多個類,但只能有⼀個類是主類。在 Java 應⽤程式中,這個主類是指包含main()⽅法的類。⽽在 Java ⼩程式中,這個主類是⼀個繼承⾃系統類 JApplet 或 Applet 的⼦類。應⽤程式的主類不⼀定要求是 public 類,但⼩程式的主類要求必須是 public 類。主類是 Java程式執⾏的⼊⼝點。
Java 應⽤程式與⼩程式之間有哪些差別?
- 簡單說應⽤程式是從主執行緒啟動(也就是 main() ⽅法)。applet ⼩程式沒有 main() ⽅法,主要是嵌在瀏覽器⻚⾯上運⾏(調⽤ init() 或者 run() 來啟動),嵌⼊瀏覽器這點跟 flash 的⼩遊戲類似。
字元型常量和字串常量的區別?
- 形式上: 字元常量是單引號引起的⼀個字元; 字串常量是雙引號引起的若⼲個字元
- 含義上: 字元常量相當於⼀個整型值( ASCII 值),可以參加表示式運算; 字串常量代表⼀個地址值(該字串在記憶體中存放位置)
- 佔記憶體⼤⼩ 字元常量只佔 2 個位元組; 字串常量佔若⼲個位元組 (注意: char 在 Java 中佔兩個位元組)
構造器 Constructor 是否可被 override?
- Constructor 不能被 override(重寫),但是可以 overload(過載),所以你可以看到⼀個類中有多個建構函式的情況。
過載和重寫的區別
- 過載就是同樣的⼀個⽅法能夠根據輸⼊資料的不同,做出不同的處理
- 重寫就是當⼦類繼承⾃⽗類的相同⽅法,輸⼊資料⼀樣,但要做出有別於⽗類的響應時,你就要覆蓋⽗類⽅法
說一下Java ⾯向物件程式設計三⼤特性: 封裝 繼承 多型
封裝
- 封裝把⼀個物件的屬性私有化,同時提供⼀些可以被外界訪問的屬性的⽅法,如果屬性不想被外界訪問,我們⼤可不必提供⽅法給外界訪問。但是如果⼀個類沒有提供給外界訪問的⽅法,那麼這個類也沒有什麼意義了。
繼承
- 繼承是使⽤已存在的類的定義作為基礎建⽴新類的技術,新類的定義可以增加新的資料或新的功能,也
可以⽤⽗類的功能,但不能選擇性地繼承⽗類。通過使⽤繼承我們能夠⾮常⽅便地復⽤以前的程式碼。
關於繼承如下 3 點請記住:
- ⼦類擁有⽗類物件所有的屬性和⽅法(包括私有屬性和私有⽅法),但是⽗類中的私有屬性和⽅
法⼦類是⽆法訪問,只是擁有。 - ⼦類可以擁有⾃⼰屬性和⽅法,即⼦類可以對⽗類進⾏擴充套件。
- ⼦類可以⽤⾃⼰的⽅式實現⽗類的⽅法。(以後介紹)。
多型
- 所謂多型就是指程式中定義的引⽤變數所指向的具體型別和通過該引⽤變數發出的⽅法調⽤在程式設計時並不確定,⽽是在程式運⾏期間才確定,即⼀個引⽤變數到底會指向哪個類的例項物件,該引⽤變數發出的⽅法調⽤到底是哪個類中實現的⽅法,必須在由程式運⾏期間才能決定。在 Java 中有兩種形式可以實現多型:繼承(多個⼦類對同⼀⽅法的重寫)和接⼝(實現接⼝並覆蓋接⼝中同⼀⽅法)。
說一下⾃動裝箱與拆箱
- 裝箱:將基本型別⽤它們對應的引⽤型別包裝起來;
- 拆箱:將包裝型別轉換為基本資料型別;
在⼀個靜態⽅法內調⽤⼀個⾮靜態成員為什麼是⾮法的?
由於靜態⽅法可以不通過物件進⾏調⽤,因此在靜態⽅法⾥,不能調⽤其他⾮靜態變數,也不可以訪問⾮靜態變數成員。
在 Java 中定義⼀個不做事且沒有引數的構造⽅法的作⽤
- Java 程式在執⾏⼦類的構造⽅法之前,如果沒有⽤ super() 來調⽤⽗類特定的構造⽅法,則會調⽤⽗類中“沒有引數的構造⽅法”。因此,如果⽗類中只定義了有引數的構造⽅法,⽽在⼦類的構造⽅法中⼜沒有⽤ super() 來調⽤⽗類中特定的構造⽅法,則編譯時將發⽣錯誤,因為 Java 程式在⽗類中找不到沒有引數的構造⽅法可供執⾏。解決辦法是在⽗類⾥加上⼀個不做事且沒有引數的構造⽅法。
import java 和 javax 有什麼區別?
- 剛開始的時候 JavaAPI 所必需的包是 java 開頭的包,javax 當時只是擴充套件 API 包來使⽤。然⽽隨著時間的推移,javax 逐漸地擴充套件成為 Java API 的組成部分。但是,將擴充套件從 javax 包移動到 java包確實太麻煩了,最終會破壞⼀堆現有的程式碼。因此,最終決定 javax 包將成為標準 API 的⼀部分。所以,實際上 java 和 javax 沒有區別。這都是⼀個名字。
接⼝和抽象類的區別是什麼?
- 接⼝的⽅法預設是 public,所有⽅法在接⼝中不能有實現(Java 8 開始接⼝⽅法可以有預設實現),⽽抽象類可以有⾮抽象的⽅法。
- 接⼝中除了 static、final 變數,不能有其他變數,⽽抽象類中則不⼀定。
- ⼀個類可以實現多個接⼝,但只能實現⼀個抽象類。接⼝⾃⼰本身可以通過 extends 關鍵字擴
展多個接⼝。 - 接⼝⽅法預設修飾符是 public,抽象⽅法可以有 public、protected 和 default 這些修飾符(抽象⽅法就是為了被重寫所以不能使⽤ private 關鍵字修飾!)。
- 從設計層⾯來說,抽象是對類的抽象,是⼀種模板設計,⽽接⼝是對⾏為的抽象,是⼀種⾏為的規範。
成員變數與區域性變數的區別有哪些?
- 從語法形式上看:成員變數是屬於類的,⽽區域性變數是在⽅法中定義的變數或是⽅法的引數;成
員變數可以被 public,private,static 等修飾符所修飾,⽽區域性變數不能被訪問控制修飾符及
static 所修飾;但是,成員變數和區域性變數都能被 final 所修飾。 - 從變數在記憶體中的儲存⽅式來看:如果成員變數是使⽤ static 修飾的,那麼這個成員變數是屬
於類的,如果沒有使⽤ static 修飾,這個成員變數是屬於例項的。物件存於堆記憶體,如果區域性
變數型別為基本資料型別,那麼儲存在棧記憶體,如果為引⽤資料型別,那存放的是指向堆記憶體對
象的引⽤或者是指向常量池中的地址。 - 從變數在記憶體中的⽣存時間上看:成員變數是物件的⼀部分,它隨著物件的建立⽽存在,⽽區域性
變數隨著⽅法的調⽤⽽⾃動消失。 - 成員變數如果沒有被賦初值:則會⾃動以型別的預設值⽽賦值(⼀種情況例外:被 final 修飾的
成員變數也必須顯式地賦值),⽽區域性變數則不會⾃動賦值。
建立⼀個物件⽤什麼運算子?物件實體與物件引⽤有何不同?
- new 運算子,new 建立物件例項(物件例項在堆記憶體中),物件引⽤指向物件例項(物件引⽤存放在棧記憶體中)。⼀個物件引⽤可以指向 0 個或 1 個物件(⼀根繩⼦可以不繫⽓球,也可以系⼀個⽓球);⼀個物件可以有 n 個引⽤指向它(可以⽤ n 條繩⼦繫住⼀個⽓球)。
什麼是⽅法的返回值?返回值在類的⽅法⾥的作⽤是什麼?
- ⽅法的返回值是指我們獲取到的某個⽅法體中的程式碼執⾏後產⽣的結果!(前提是該⽅法可能產⽣結果)。返回值的作⽤:接收出結果,使得它可以⽤於其他的操作!
⼀個類的構造⽅法的作⽤是什麼? 若⼀個類沒有宣告構造⽅法,該程式能正確執⾏嗎? 為什麼?
- 主要作⽤是完成對類物件的初始化⼯作。可以執⾏。因為⼀個類即使沒有宣告構造⽅法也會有預設的不
帶引數的構造⽅法。
構造⽅法有哪些特性?
- 名字與類名相同。
- 沒有返回值,但不能⽤ void 宣告建構函式。
- ⽣成類的物件時⾃動執⾏,⽆需調⽤。
靜態⽅法和例項⽅法有何不同
- 在外部調⽤靜態⽅法時,可以使⽤"類名.⽅法名"的⽅式,也可以使⽤"物件名.⽅法名"的⽅式。
⽽例項⽅法只有後⾯這種⽅式。也就是說,調⽤靜態⽅法可以⽆需建立物件。 - 靜態⽅法在訪問本類的成員時,只允許訪問靜態成員(即靜態成員變數和靜態⽅法),⽽不允許
訪問例項成員變數和例項⽅法;例項⽅法則⽆此限制。
物件的相等與指向他們的引⽤相等,兩者有什麼不同?
- 物件的相等,⽐的是記憶體中存放的內容是否相等。⽽引⽤相等,⽐的是他們指向的記憶體地址是否相
等。
在調⽤⼦類構造⽅法之前會先調⽤⽗類沒有引數的構造⽅法,其⽬的是?
- 幫助⼦類做初始化⼯作。
簡述執行緒、程式、程式的基本概念。以及他們之間關係是什麼?
-
執行緒與程式相似,但執行緒是⼀個⽐程式更⼩的執⾏單位。⼀個程式在其執⾏的過程中可以產⽣多個執行緒。與程式不同的是同類的多個執行緒共享同⼀塊記憶體空間和⼀組系統資源,所以系統在產⽣⼀個執行緒,或是在各個執行緒之間作切換⼯作時,負擔要⽐程式⼩得多,也正因為如此,執行緒也被稱為輕量級程式。
-
程式是含有指令和資料的⽂件,被儲存在磁碟或其他的資料儲存裝置中,也就是說程式是靜態的程式碼。
-
程式是程式的⼀次執⾏過程,是系統運⾏程式的基本單位,因此程式是動態的。系統運⾏⼀個程式即是⼀個程式從建立,運⾏到消亡的過程。簡單來說,⼀個程式就是⼀個執⾏中的程式,它在計算機中⼀個指令接著⼀個指令地執⾏著,同時,每個程式還佔有某些系統資源如 CPU 時間,記憶體空間,⽂件,輸⼊輸出裝置的使⽤權等等。換句話說,當程式在執⾏時,將會被作業系統載⼊記憶體中。 執行緒是程式劃分成的更⼩的運⾏單位。執行緒和程式最⼤的不同在於基本上各程式是獨⽴的,⽽各執行緒則不⼀定,因為同⼀程式中的執行緒極有可能會相互影響。從另⼀⻆度來說,程式屬於作業系統的範疇,主要是同⼀段時間內,可以同時執⾏⼀個以上的程式,⽽執行緒則是在同⼀程式內⼏乎同時執⾏⼀個以上的程式段。
關於 final 關鍵字的⼀些總結
- final 關鍵字主要⽤在三個地⽅:變數、⽅法、類。
- 對於⼀個 final 變數,如果是基本資料型別的變數,則其數值⼀旦在初始化之後便不能更改;如果是引⽤型別的變數,則在對其初始化之後便不能再讓其指向另⼀個物件。
- 當⽤ final 修飾⼀個類時,表明這個類不能被繼承。final 類中的所有成員⽅法都會被隱式地指定為 final ⽅法。
- 使⽤ final ⽅法的原因有兩個。第⼀個原因是把⽅法鎖定,以防任何繼承類修改它的含義;第⼆個原因是效率。在早期的 Java 實現版本中,會將 final ⽅法轉為內嵌調⽤。但是如果⽅法過於龐⼤,可能看不到內嵌調⽤帶來的任何效能提升(現在的 Java 版本已經不需要使⽤ final⽅法進⾏這些優化了)。類中所有的 private ⽅法都隱式地指定為 final。
Java 中的異常處理
Java 異常類層次結構圖
- 在 Java 中,所有的異常都有⼀個共同的祖先 java.lang 包中的 Throwable 類。Throwable: 有兩個重要的⼦類:Exception(異常) 和 Error(錯誤) ,⼆者都是 Java 異常處理的重要⼦類,各⾃都包含⼤量⼦類。
- Error(錯誤):是程式⽆法處理的錯誤,表示運⾏應⽤程式中嚴重問題。⼤多數錯誤與程式碼編寫者執⾏的操作⽆關,⽽表示程式碼運⾏時 JVM(Java 虛擬機器)出現的問題。例如,Java 虛擬機器運⾏錯誤(Virtual MachineError),當 JVM 不再有繼續執⾏操作所需的記憶體資源時,將出現
- OutOfMemoryError。這些異常發⽣時,Java 虛擬機器(JVM)⼀般會選擇執行緒終⽌。這些錯誤表示故障發⽣於虛擬機器⾃身、或者發⽣在虛擬機器試圖執⾏應⽤時,如 Java 虛擬機器運⾏錯誤(Virtual MachineError)、類定義錯誤(NoClassDefFoundError)等。這些錯誤是不可查的,因為它們在應⽤程式的控制和處理能⼒之 外,⽽且絕⼤多數是程式運⾏時不允許出現的狀況。對於設計合理的應⽤程式來說,即使確實發⽣了錯誤,本質上也不應該試圖去處理它所引起的異常狀況。在 Java中,錯誤通過 Error 的⼦類描述。
- Exception(異常):是程式本身可以處理的異常。Exception 類有⼀個重要的⼦類RuntimeExceptionRuntimeException 異常由 Java 虛擬機器丟擲。NullPointerException(要訪問的變數沒有引⽤任何物件時,丟擲該異常)、ArithmeticException(算術運算異常,⼀個整數除以 0時,丟擲該異常)和 ArrayIndexOutOfBoundsException (下標越界異常)。
- 注意:異常和錯誤的區別:異常能被程式本身處理,錯誤是⽆法處理。
Throwable 類常⽤⽅法
- public string getMessage():返回異常發⽣時的簡要描述
- public string toString():返回異常發⽣時的詳細資訊
- public string getLocalizedMessage():返回異常物件的本地化資訊。使⽤ Throwable 的⼦類覆蓋這個⽅法,可以⽣成本地化資訊。如果⼦類沒有覆蓋該⽅法,則該⽅法返回的資訊與getMessage()返回的結果相同
- public void printStackTrace():在控制檯上列印 Throwable 物件封裝的異常資訊
異常處理總結
- try 塊: ⽤於捕獲異常。其後可接零個或多個 catch 塊,如果沒有 catch 塊,則必須跟⼀個finally 塊。
- catch 塊: ⽤於處理 try 捕獲到的異常。
- finally 塊: ⽆論是否捕獲或處理異常,finally 塊⾥的語句都會被執⾏。當在 try 塊或catch 塊中遇到 return 語句時,finally 語句塊將在⽅法返回之前被執⾏。
在以下 4 種特殊情況下,finally 塊不會被執⾏:
- 在 finally 語句塊第⼀⾏發⽣了異常。 因為在其他⾏,finally 塊還是會得到執⾏
- 在前⾯的程式碼中⽤了 System.exit(int)已退出程式。 exit 是帶參函式 ;若該語句在異常語句之後,finally 會執⾏
- 程式所在的執行緒死亡。
- 關閉 CPU。
Java 序列化中如果有些欄位不想進⾏序列化,怎麼辦?
- 對於不想進⾏序列化的變數,使⽤ transient 關鍵字修飾。transient 關鍵字的作⽤是:阻⽌例項中那些⽤此關鍵字修飾的的變數序列化;當物件被反序列化時,被 transient 修飾的變數值不會被持久化和恢復。transient 只能修飾變數,不能修飾類和⽅法。
獲取⽤鍵盤輸⼊常⽤的兩種⽅法
⽅法 1:通過 Scanner
⽅法 2:通過 BufferedReader
講一下Java 中 IO 流
Java 中 IO 流分為⼏種?
- 按照流的流向分,可以分為輸⼊流和輸出流;
- 按照操作單元劃分,可以劃分為位元組流和字元流;
- 按照流的⻆⾊劃分為節點流和處理流。
Java Io 流共涉及 40 多個類,這些類看上去很雜亂,但實際上很有規則,⽽且彼此之間存在⾮常緊密的聯絡, Java I0 流的 40 多個類都是從如下 4 個抽象類基類中派⽣出來的。 - InputStream/Reader: 所有的輸⼊流的基類,前者是位元組輸⼊流,後者是字元輸⼊流。
- OutputStream/Writer: 所有輸出流的基類,前者是位元組輸出流,後者是字元輸出流。
按操作⽅式分類結構圖:
按操作物件分類結構圖:
既然有了位元組流,為什麼還要有字元流?
- 字元流是由 Java 虛擬機器將位元組轉換得到的,問題就出在這個過程還算是⾮常耗時,並且,如果我們不知道編碼型別就很容易出現亂碼問題。所以, I/O 流就⼲脆提供了⼀個直接操作字元的接⼝,⽅便我們平時對字元進⾏流操作。如果⾳頻⽂件、圖⽚等媒體⽂件⽤位元組流⽐好,如果涉及到字元的話使⽤字元流⽐好。
講一下深拷⻉ vs 淺拷⻉
- 淺拷⻉:對基本資料型別進⾏值傳遞,對引⽤資料型別進⾏引⽤傳遞般的拷⻉,此為淺拷⻉。
- 深拷⻉:對基本資料型別進⾏值傳遞,對引⽤資料型別,建立⼀個新的物件,並複製其內容,此
為深拷⻉。
說說List,Set,Map三者的區別?
- List(對付順序的好幫⼿): List接⼝儲存⼀組不唯⼀(可以有多個元素引⽤相同的物件),有序的物件
- Set(注重獨⼀⽆⼆的性質): 不允許重複的集合。不會有多個元素引⽤相同的物件。
- Map(⽤Key來搜尋的專家): 使⽤鍵值對儲存。Map會維護與Key有關聯的值。兩個Key可以引⽤相同的物件,但Key不能重複,典型的Key是String型別,但也可以是任何物件。
HashMap 和 Hashtable 的區別
- 執行緒是否安全: HashMap 是⾮執行緒安全的,HashTable 是執行緒安全的;HashTable 內部的⽅法基本都經過 synchronized 修飾。(如果你要保證執行緒安全的話就使⽤ ConcurrentHashMap吧!);
- 效率: 因為執行緒安全的問題,HashMap 要⽐ HashTable 效率⾼⼀點。另外,HashTable 基本被淘汰,不要在程式碼中使⽤它;
- 對Null key 和Null value的⽀持: HashMap 中,null 可以作為鍵,這樣的鍵只有⼀個,可以有⼀個或多個鍵所對應的值為 null。。但是在 HashTable 中 put 進的鍵值只要有⼀個 null,直接丟擲 NullPointerException。
- 初始容量⼤⼩和每次擴充容量⼤⼩的不同 : ①建立時如果不指定容量初始值,Hashtable 預設的初始⼤⼩為11,之後每次擴充,容量變為原來的2n+1。HashMap 預設的初始化⼤⼩為16。之後每次擴充,容量變為原來的2倍。②建立時如果給定了容量初始值,那麼 Hashtable 會直接使⽤你給定的⼤⼩,⽽ HashMap 會將其擴充為2的冪次⽅⼤⼩(HashMap 中的 tableSizeFor() ⽅法保證,下⾯給出了原始碼)。也就是說 HashMap 總是使⽤2的冪作為雜湊表的⼤⼩,後⾯會介紹到為什麼是2的冪次⽅。
- 底層資料結構: JDK1.8 以後的 HashMap 在解決雜湊衝突時有了⼤的變化,當連結串列⻓度⼤於閾值(預設為8)時,將連結串列轉化為紅⿊樹,以減少搜尋時間。Hashtable 沒有這樣的機制。
什麼是執行緒和程式?
何為程式?
- 程式是程式的⼀次執⾏過程,是系統運⾏程式的基本單位,因此程式是動態的。系統運⾏⼀個程式即是⼀個程式從建立,運⾏到消亡的過程。
- 在 Java 中,當我們啟動 main 函式時其實就是啟動了⼀個 JVM 的程式,⽽ main 函式所在的執行緒就是這個程式中的⼀個執行緒,也稱主執行緒。
何為執行緒?
- 執行緒與程式相似,但執行緒是⼀個⽐程式更⼩的執⾏單位。⼀個程式在其執⾏的過程中可以產⽣多個執行緒。與程式不同的是同類的多個執行緒共享程式的堆和⽅法區資源,但每個執行緒有⾃⼰的程式計數器、虛擬機器棧和本地⽅法棧,所以系統在產⽣⼀個執行緒,或是在各個執行緒之間作切換⼯作時,負擔要⽐程式⼩得多,也正因為如此,執行緒也被稱為輕量級程式。
為什麼要使⽤多執行緒呢?
- 從計算機底層來說: 執行緒可以⽐作是輕量級的程式,是程式執⾏的最⼩單位,執行緒間的切換和排程的成本遠遠⼩於程式。另外,多核 CPU 時代意味著多個執行緒可以同時運⾏,這減少了執行緒上下⽂切換的開銷。
- 從當代互聯⽹發展趨勢來說: 現在的系統動不動就要求百萬級甚⾄千萬級的併發量,⽽多執行緒併發程式設計正是開發⾼併發系統的基礎,利⽤好多執行緒機制可以⼤⼤提⾼系統整體的併發能⼒以及效能
併發程式設計的三個重要特性
- 原⼦性 : ⼀個的操作或者多次操作,要麼所有的操作全部都得到執⾏並且不會收到任何因素的⼲擾⽽中斷,要麼所有的操作都執⾏,要麼都不執⾏。 synchronized 可以保證程式碼⽚段的原⼦性。
- 可⻅性 :當⼀個變數對共享變數進⾏了修改,那麼另外的執行緒都是⽴即可以看到修改後的最新值。 volatile 關鍵字可以保證共享變數的可⻅性。
- 有序性 :程式碼在執⾏的過程中的先後順序,Java 在編譯器以及運⾏期間的優化,程式碼的執⾏順序未必就是編寫程式碼時候的順序。 volatile 關鍵字可以禁⽌指令進⾏重排序優化。
簡單的介紹⼀下強引⽤,軟引⽤,弱引⽤,虛引⽤
強引⽤(StrongReference)
- 以前我們使⽤的⼤部分引⽤實際上都是強引⽤,這是使⽤最普遍的引⽤。如果⼀個物件具有強引⽤,那就類似於必不可少的⽣活⽤品,垃圾回收器絕不會回收它。當記憶體空 間不⾜,Java虛擬機器寧願丟擲OutOfMemoryError錯誤,使程式異常終⽌,也不會靠隨意回收具有強引⽤的物件來解決記憶體不⾜問題。
軟引⽤(SoftReference)
- 如果⼀個物件只具有軟引⽤,那就類似於可有可⽆的⽣活⽤品。如果記憶體空間⾜夠,垃圾回收器就不會回收它,如果記憶體空間不⾜了,就會回收這些物件的記憶體。只要垃圾回收器沒有回收它,該物件就可以被程式使⽤。軟引⽤可⽤來實現記憶體敏感的⾼速快取。軟引⽤可以和⼀個引⽤佇列(ReferenceQueue)聯合使⽤,如果軟引⽤所引⽤的物件被垃圾回收,JAVA虛擬機器就會把這個軟引⽤加⼊到與之關聯的引⽤佇列中。
弱引⽤(WeakReference)
- 如果⼀個物件只具有弱引⽤,那就類似於可有可⽆的⽣活⽤品。弱引⽤與軟引⽤的區別在於:只具有弱引⽤的物件擁有更短暫的⽣命週期。在垃圾回收器執行緒掃描它 所管轄的記憶體區域的過程中,⼀旦發現了只具有弱引⽤的物件,不管當前記憶體空間⾜夠與否,都會回收它的記憶體。不過,由於垃圾回收器是⼀個優先順序很低的執行緒, 因此不⼀定會很快發現那些只具有弱引⽤的物件。弱引⽤可以和⼀個引⽤佇列(ReferenceQueue)聯合使⽤,如果弱引⽤所引⽤的物件被垃圾回收,Java虛擬機器就會把這個弱引⽤加⼊到與之關聯的引⽤佇列中。
虛引⽤(PhantomReference)
- "虛引⽤"顧名思義,就是形同虛設,與其他⼏種引⽤都不同,虛引⽤並不會決定物件的⽣命週期。如果
⼀個物件僅持有虛引⽤,那麼它就和沒有任何引⽤⼀樣,在任何時候都可能被垃圾回收。
總結
感謝你看到這裡,文章有什麼不足還請指正!由於時間關係暫時先整理了這麼多,有什麼不足的可以私信我,我都會跟進補上,希望這些能在馬上到來的金三銀四里面對你有幫助!
另外我還為大家準備了ava核心知識點+全套架構師學習資料和視訊+一線大廠面試寶典+面試簡歷模板+阿里美團網易騰訊小米愛奇藝快手嗶哩嗶哩面試題+Spring原始碼合集+Java架構實戰電子書一起免費分享給大家!
有需要的可以關注我的公眾號:前程有光回覆資料即可領取!覺得文章對你有幫助的話記得給我點個贊,每天都會分享java相關技術文章或行業資訊,歡迎大家關注和轉發文章!