自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

面試八股文之 Java 基礎(chǔ)

開(kāi)發(fā) 后端
Java是一門面向?qū)ο缶幊陶Z(yǔ)言,不僅吸收了C++語(yǔ)言的各種優(yōu)點(diǎn),還摒棄了C++里難以理解的多繼承、指針等概念,因此Java語(yǔ)言具有功能強(qiáng)大和簡(jiǎn)單易用兩個(gè)特征。

一.介紹 Java 

java 是一門「開(kāi)源的跨平臺(tái)的面向?qū)ο蟮摹褂?jì)算機(jī)語(yǔ)言。

 

跨平臺(tái)是因?yàn)?java 的 class 文件是運(yùn)行在虛擬機(jī)上的,其實(shí)跨平臺(tái)的,而「虛擬機(jī)是不同平臺(tái)有不同版本」,所以說(shuō) java 是跨平臺(tái)的.

面向?qū)ο笥袔讉€(gè)特點(diǎn): 

1.「封裝」

  • 兩層含義:一層含義是把對(duì)象的屬性和行為看成一個(gè)密不可分的整體,將這兩者'封裝'在一個(gè)不可分割的「獨(dú)立單元」(即對(duì)象)中
  • 另一層含義指'信息隱藏,把不需要讓外界知道的信息隱藏起來(lái),有些對(duì)象的屬性及行為允許外界用戶知道或使用,但不允許更改,而另一些屬性或行為,則不允許外界知曉,或只允許使用對(duì)象的功能,而盡可能「隱藏對(duì)象的功能實(shí)現(xiàn)細(xì)節(jié)」。

「優(yōu)點(diǎn)」:

  • 良好的封裝能夠「減少耦合」,符合程序設(shè)計(jì)追求'高內(nèi)聚,低耦合'
  • 「類內(nèi)部的結(jié)構(gòu)可以自由修改」
  • 可以對(duì)成員變量進(jìn)行更「精確的控制」
  • 「隱藏信息」實(shí)現(xiàn)細(xì)節(jié)

2.「繼承」

繼承就是子類繼承父類的特征和行為,使得子類對(duì)象(實(shí)例)具有父類的實(shí)例域和方法,或子類從父類繼承方法,使得子類具有父類相同的行為。

「優(yōu)點(diǎn)」:

  • 提高類代碼的「復(fù)用性」
  • 提高了代碼的「維護(hù)性」

3.「多態(tài)」

  • 「方法重載」:在一個(gè)類中,允許多個(gè)方法使用同一個(gè)名字,但方法的參數(shù)不同,完成的功能也不同。
  • 「對(duì)象多態(tài)」:子類對(duì)象可以與父類對(duì)象進(jìn)行轉(zhuǎn)換,而且根據(jù)其使用的子類不同完成的功能也不同(重寫(xiě)父類的方法)。

多態(tài)是同一個(gè)行為具有多個(gè)不同表現(xiàn)形式或形態(tài)的能力。Java語(yǔ)言中含有方法重載與對(duì)象多態(tài)兩種形式的多態(tài):

「優(yōu)點(diǎn)」

「消除類型之間的耦合關(guān)系」

「可替換性」

「可擴(kuò)充性」

「接口性」

「靈活性」

「簡(jiǎn)化性」

二.Java 有哪些數(shù)據(jù)類型?

java 主要有兩種數(shù)據(jù)類型

1.「基本數(shù)據(jù)類型」

  • byte,short,int,long屬于數(shù)值型中的整數(shù)型
  • float,double屬于數(shù)值型中的浮點(diǎn)型
  • char屬于字符型
  • boolean屬于布爾型

基本數(shù)據(jù)有「八個(gè)」,

2.「引用數(shù)據(jù)類型」

引用數(shù)據(jù)類型有「三個(gè)」,分別是類,接口和數(shù)組

三.接口和抽象類有什么區(qū)別?

1.接口是抽象類的變體,「接口中所有的方法都是抽象的」。而抽象類是聲明方法的存在而不去實(shí)現(xiàn)它的類。

2.接口可以多繼承,抽象類不行。

3.接口定義方法,不能實(shí)現(xiàn),默認(rèn)是 「public abstract」,而抽象類可以實(shí)現(xiàn)部分方法。

4.接口中基本數(shù)據(jù)類型為 「public static final」 并且需要給出初始值,而抽類象不是的。

四.重載和重寫(xiě)什么區(qū)別?

重寫(xiě):

1.參數(shù)列表必須「完全與被重寫(xiě)的方法」相同,否則不能稱其為重寫(xiě)而是重載.

2.「返回的類型必須一直與被重寫(xiě)的方法的返回類型相同」,否則不能稱其為重寫(xiě)而是重載。

3.訪問(wèn)「修飾符的限制一定要大于被重寫(xiě)方法的訪問(wèn)修飾符」

4.重寫(xiě)方法一定「不能拋出新的檢查異?;蛘弑缺恢貙?xiě)方法申明更加寬泛的檢查型異?!埂?/p>

重載:

1.必須具有「不同的參數(shù)列表」;

2.可以有不同的返回類型,只要參數(shù)列表不同就可以了;

3.可以有「不同的訪問(wèn)修飾符」;

4.可以拋出「不同的異常」;

五.常見(jiàn)的異常有哪些?

  • NullPointerException 空指針異常
  • ArrayIndexOutOfBoundsException 索引越界異常
  • InputFormatException 輸入類型不匹配
  • SQLException SQL異常
  • IllegalArgumentException 非法參數(shù)
  • NumberFormatException 類型轉(zhuǎn)換異常 等等....

六.異常要怎么解決?

Java標(biāo)準(zhǔn)庫(kù)內(nèi)建了一些通用的異常,這些類以Throwable為頂層父類。

Throwable又派生出「Error類和Exception類」。

錯(cuò)誤:Error類以及他的子類的實(shí)例,代表了JVM本身的錯(cuò)誤。錯(cuò)誤不能被程序員通過(guò)代碼處理,Error很少出現(xiàn)。因此,程序員應(yīng)該關(guān)注Exception為父類的分支下的各種異常類。

異常:Exception以及他的子類,代表程序運(yùn)行時(shí)發(fā)送的各種不期望發(fā)生的事件??梢员籎ava異常處理機(jī)制使用,是異常處理的核心。

處理方法:

1.「try()catch(){}」

  1. try{ 
  2. // 程序代碼 
  3. }catch(ExceptionName e1){ 
  4. //Catch 塊 

2.「throw」

throw 關(guān)鍵字作用是拋出一個(gè)異常,拋出的時(shí)候是拋出的是一個(gè)異常類的實(shí)例化對(duì)象,在異常處理中,try 語(yǔ)句要捕獲的是一個(gè)異常對(duì)象,那么此異常對(duì)象也可以自己拋出

3.「throws」

定義一個(gè)方法的時(shí)候可以使用 throws 關(guān)鍵字聲明。使用 throws 關(guān)鍵字聲明的方法表示此方法不處理異常,而交給方法調(diào)用處進(jìn)行處理。

七.arrayList 和 linkedList 的區(qū)別?

1.ArrayList 是實(shí)現(xiàn)了基于「數(shù)組」的,存儲(chǔ)空間是連續(xù)的。LinkedList 基于「鏈表」的,存儲(chǔ)空間是不連續(xù)的。(LinkedList 是雙向鏈表)

2.對(duì)于「隨機(jī)訪問(wèn)」 get 和 set ,ArrayList 覺(jué)得優(yōu)于 LinkedList,因?yàn)?LinkedList 要移動(dòng)指針。

3.對(duì)于「新增和刪除」操作 add 和 remove ,LinedList 比較占優(yōu)勢(shì),因?yàn)?ArrayList 要移動(dòng)數(shù)據(jù)。

4.同樣的數(shù)據(jù)量 LinkedList 所占用空間可能會(huì)更小,因?yàn)?ArrayList 需要「預(yù)留空間」便于后續(xù)數(shù)據(jù)增加,而 LinkedList 增加數(shù)據(jù)只需要「增加一個(gè)節(jié)點(diǎn)」

八.hashMap 1.7 和 hashMap 1.8 的區(qū)別?

只記錄「重點(diǎn)」

 

九.hashMap 線程不安全體現(xiàn)在哪里?

在 「hashMap1.7 中擴(kuò)容」的時(shí)候,因?yàn)椴捎玫氖穷^插法,所以會(huì)可能會(huì)有循環(huán)鏈表產(chǎn)生,導(dǎo)致數(shù)據(jù)有問(wèn)題,在 1.8 版本已修復(fù),改為了尾插法

在任意版本的 hashMap 中,如果在「插入數(shù)據(jù)時(shí)多個(gè)線程命中了同一個(gè)槽」,可能會(huì)有數(shù)據(jù)覆蓋的情況發(fā)生,導(dǎo)致線程不安全。

十. hashMap 線程不安全怎么解決?

  1. 給 hashMap 「直接加鎖」,來(lái)保證線程安全
  2. 使用 「hashTable」,比方法一效率高,其實(shí)就是在其方法上加了 synchronized 鎖
  3. 使用 「concurrentHashMap」 , 不管是其 1.7 還是 1.8 版本,本質(zhì)都是「減小了鎖的粒度,減少線程競(jìng)爭(zhēng)」來(lái)保證高效.

十一.concurrentHashMap 1.7 和 1.8 有什么區(qū)別

只記錄「重點(diǎn)」

十二.介紹 hashset 

上圖是 set 家族整體的結(jié)構(gòu),set 繼承于 Collection 接口,是一個(gè)「不允許出現(xiàn)重復(fù)元素,并且無(wú)序的集合」.

HashSet 是「基于 HashMap 實(shí)現(xiàn)」的,底層「采用 HashMap 來(lái)保存元素」

元素的哈希值是通過(guò)元素的 hashcode 方法 來(lái)獲取的, HashSet 首先判斷兩個(gè)元素的哈希值,如果哈希值一樣,接著會(huì)比較 equals 方法 如果 equls 結(jié)果為 true ,HashSet 就視為同一個(gè)元素。如果 equals 為 false 就不是同一個(gè)元素。

十三.什么是泛型?

泛型:「把類型明確的工作推遲到創(chuàng)建對(duì)象或調(diào)用方法的時(shí)候才去明確的特殊的類型」

十四.泛型擦除是什么?

因?yàn)榉盒推鋵?shí)只是在編譯器中實(shí)現(xiàn)的而虛擬機(jī)并不認(rèn)識(shí)泛型類項(xiàng),所以要在虛擬機(jī)中將泛型類型進(jìn)行擦除。也就是說(shuō),「在編譯階段使用泛型,運(yùn)行階段取消泛型,即擦除」。擦除是將泛型類型以其父類代替,如String 變成了Object等。其實(shí)在使用的時(shí)候還是進(jìn)行帶強(qiáng)制類型的轉(zhuǎn)化,只不過(guò)這是比較安全的轉(zhuǎn)換,因?yàn)樵诰幾g階段已經(jīng)確保了數(shù)據(jù)的一致性。

十五.說(shuō)說(shuō)進(jìn)程和線程的區(qū)別?

「進(jìn)程是系統(tǒng)資源分配和調(diào)度的基本單位」,它能并發(fā)執(zhí)行較高系統(tǒng)資源的利用率.

「線程」是「比進(jìn)程更小」的能獨(dú)立運(yùn)行的基本單位,創(chuàng)建、銷毀、切換成本要小于進(jìn)程,可以減少程序并發(fā)執(zhí)行時(shí)的時(shí)間和空間開(kāi)銷,使得操作系統(tǒng)具有更好的并發(fā)性。

十六.volatile 有什么作用?

「1.保證內(nèi)存可見(jiàn)性」

  • 可見(jiàn)性是指線程之間的可見(jiàn)性,一個(gè)線程修改的狀態(tài)對(duì)另一個(gè)線程是可見(jiàn)的。也就是一個(gè)線程修改的結(jié)果,另一個(gè)線程馬上就能看到。

「2.禁止指令重排序」

  • cpu 是和緩存做交互的,但是由于 cpu 運(yùn)行效率太高,所以會(huì)不等待當(dāng)前命令返回結(jié)果從而繼續(xù)執(zhí)行下一個(gè)命令,就會(huì)有亂序執(zhí)行的情況發(fā)生

十七.什么是包裝類?

為什么需要包裝類?「Java 中有 8 個(gè)基本類型,分別對(duì)應(yīng)的 8 個(gè)包裝類」

  • byte -- Byte
  • boolean -- Boolean
  • short -- Short
  • char -- Character
  • int -- Integer
  • long -- Long
  • float -- Float
  • double -- Double

「為什么需要包裝類」:

  • 基本數(shù)據(jù)類型方便、簡(jiǎn)單、高效,但泛型不支持、集合元素不支持
  • 不符合面向?qū)ο笏季S
  • 包裝類提供很多方法,方便使用,如 Integer 類 toHexString(int i)、parseInt(String s) 方法等等

十八.Integer a = 1000,Integer b = 1000,a==b 的結(jié)果是什么?那如果 a,b 都為1,結(jié)果又是什么?

Integer a = 1000,Integer b = 1000,a==b 結(jié)果為「false」

Integer a = 1,Integer b = 1,a==b 結(jié)果為「true」

這道題主要考察 Integer 包裝類緩存的范圍,「在-128~127之間會(huì)緩存起來(lái)」,比較的是直接緩存的數(shù)據(jù),在此之外比較的是對(duì)象

十九.JMM 是什么?

JMM 就是 「Java內(nèi)存模型」(java memory model)。因?yàn)樵诓煌挠布a(chǎn)商和不同的操作系統(tǒng)下,內(nèi)存的訪問(wèn)有一定的差異,所以會(huì)造成相同的代碼運(yùn)行在不同的系統(tǒng)上會(huì)出現(xiàn)各種問(wèn)題。所以java內(nèi)存模型(JMM)「屏蔽掉各種硬件和操作系統(tǒng)的內(nèi)存訪問(wèn)差異,以實(shí)現(xiàn)讓java程序在各種平臺(tái)下都能達(dá)到一致的并發(fā)效果」。

Java內(nèi)存模型規(guī)定所有的變量都存儲(chǔ)在主內(nèi)存中,包括實(shí)例變量,靜態(tài)變量,但是不包括局部變量和方法參數(shù)。每個(gè)線程都有自己的工作內(nèi)存,線程的工作內(nèi)存保存了該線程用到的變量和主內(nèi)存的副本拷貝,線程對(duì)變量的操作都在工作內(nèi)存中進(jìn)行。「線程不能直接讀寫(xiě)主內(nèi)存中的變量」。

每個(gè)線程的工作內(nèi)存都是獨(dú)立的,「線程操作數(shù)據(jù)只能在工作內(nèi)存中進(jìn)行,然后刷回到主存」。這是 Java 內(nèi)存模型定義的線程基本工作方式。

二十.創(chuàng)建對(duì)象有哪些方式

有「五種創(chuàng)建對(duì)象的方式」

1.new關(guān)鍵字

  1. Person p1 = new Person(); 

2.Class.newInstance

  1. Person p1 = Person.class.newInstance(); 

3.Constructor.newInstance

  1. Constructor<Person> constructor = Person.class.getConstructor(); 
  2. Person p1 = constructor.newInstance(); 

4.clone

  1. Person p1 = new Person(); 
  2. Person p2 = p1.clone(); 

5.反序列化

  1. Person p1 = new Person(); 
  2. byte[] bytes = SerializationUtils.serialize(p1); 
  3. Person p2 = (Person)SerializationUtils.deserialize(bytes); 

二十一.講講單例模式懶漢式吧

直接貼代碼

  1. // 懶漢式 
  2. public class Singleton { 
  3. // 延遲加載保證多線程安全 
  4.     Private volatile static Singleton singleton; 
  5.     private Singleton(){} 
  6.     public static Singleton getInstance(){ 
  7.         if(singleton == null){ 
  8.             synchronized(Singleton.class){ 
  9.                 if(singleton == null){ 
  10.                     singleton = new Singleton(); 
  11.                 } 
  12.             } 
  13.         } 
  14.         return singleton; 
  15.     } 
  • 使用 volatile 是「防止指令重排序,保證對(duì)象可見(jiàn)」,防止讀到半初始化狀態(tài)的對(duì)象
  • 第一層if(singleton == null) 是為了防止有多個(gè)線程同時(shí)創(chuàng)建
  • synchronized 是加鎖防止多個(gè)線程同時(shí)進(jìn)入該方法創(chuàng)建對(duì)象
  • 第二層if(singleton == null) 是防止有多個(gè)線程同時(shí)等待鎖,一個(gè)執(zhí)行完了后面一個(gè)又繼續(xù)執(zhí)行的情況

二十二.volatile 有什么作用

1.「保證內(nèi)存可見(jiàn)性」

當(dāng)一個(gè)被volatile關(guān)鍵字修飾的變量被一個(gè)線程修改的時(shí)候,其他線程可以立刻得到修改之后的結(jié)果。當(dāng)一個(gè)線程向被volatile關(guān)鍵字修飾的變量「寫(xiě)入數(shù)據(jù)」的時(shí)候,虛擬機(jī)會(huì)「強(qiáng)制它被值刷新到主內(nèi)存中」。當(dāng)一個(gè)線程「讀取」被volatile關(guān)鍵字修飾的值的時(shí)候,虛擬機(jī)會(huì)「強(qiáng)制要求它從主內(nèi)存中讀取」。

2.「禁止指令重排序」

指令重排序是編譯器和處理器為了高效對(duì)程序進(jìn)行優(yōu)化的手段,cpu 是與內(nèi)存交互的,而 cpu 的效率想比內(nèi)存高很多,所以 cpu 會(huì)在不影響最終結(jié)果的情況下,不等待返回結(jié)果直接進(jìn)行后續(xù)的指令操作,而 volatile 就是給相應(yīng)代碼加了「內(nèi)存屏障」,在屏障內(nèi)的代碼禁止指令重排序。

二十三.怎么保證線程安全?

1.synchronized關(guān)鍵字

可以用于代碼塊,方法(靜態(tài)方法,同步鎖是當(dāng)前字節(jié)碼對(duì)象;實(shí)例方法,同步鎖是實(shí)例對(duì)象)

2.lock鎖機(jī)制

  1. Lock lock = new ReentrantLock(); 
  2. lock. lock(); 
  3. try { 
  4.     System. out. println("獲得鎖"); 
  5. } catch (Exception e) { 
  6.     
  7. } finally { 
  8.     System. out. println("釋放鎖"); 
  9.     lock. unlock(); 

二十四.synchronized 鎖升級(jí)的過(guò)程

在 Java1.6 之前的版本中,synchronized 屬于重量級(jí)鎖,效率低下,「鎖是」 cpu 一個(gè)「總量級(jí)的資源」,每次獲取鎖都要和 cpu 申請(qǐng),非常消耗性能。

在 「jdk1.6 之后」 Java 官方對(duì)從 JVM 層面對(duì) synchronized 較大優(yōu)化,所以現(xiàn)在的 synchronized 鎖效率也優(yōu)化得很不錯(cuò)了,Jdk1.6 之后,為了減少獲得鎖和釋放鎖所帶來(lái)的性能消耗,引入了偏向鎖和輕量級(jí)鎖,「增加了鎖升級(jí)的過(guò)程」,由無(wú)鎖->偏向鎖->自旋鎖->重量級(jí)鎖.

增加鎖升級(jí)的過(guò)程主要是「減少用戶態(tài)到核心態(tài)的切換,提高鎖的效率,從 jvm 層面優(yōu)化鎖」

二十五.cas 是什么?

cas 叫做 CompareAndSwap,「比較并交換」,很多地方使用到了它,比如鎖升級(jí)中自旋鎖就有用到,主要是「通過(guò)處理器的指令來(lái)保證操作的原子性」,它主要包含三個(gè)變量:

  • 「1.變量?jī)?nèi)存地址」
  • 「2.舊的預(yù)期值 A」
  • 「3.準(zhǔn)備設(shè)置的新值 B」

當(dāng)一個(gè)線程需要修改一個(gè)共享變量的值,完成這個(gè)操作需要先取出共享變量的值,賦給 A,基于 A 進(jìn)行計(jì)算,得到新值 B,在用預(yù)期原值 A 和內(nèi)存中的共享變量值進(jìn)行比較,「如果相同就認(rèn)為其他線程沒(méi)有進(jìn)行修改」,而將新值寫(xiě)入內(nèi)存。

「CAS的缺點(diǎn)」

  • 「CPU開(kāi)銷比較大」:在并發(fā)量比較高的情況下,如果許多線程反復(fù)嘗試更新某一個(gè)變量,卻又一直更新不成功,又因?yàn)樽孕臅r(shí)候會(huì)一直占用CPU,如果CAS一直更新不成功就會(huì)一直占用,造成CPU的浪費(fèi)。
  • 「ABA 問(wèn)題」:比如線程 A 去修改 1 這個(gè)值,修改成功了,但是中間 線程 B 也修改了這個(gè)值,但是修改后的結(jié)果還是 1,所以不影響 A 的操作,這就會(huì)有問(wèn)題??梢杂谩赴姹咎?hào)」來(lái)解決這個(gè)問(wèn)題。
  • 「只能保證一個(gè)共享變量的原子性」

二十六.聊聊 ReentrantLock 吧

ReentrantLock 意為「可重入鎖」,說(shuō)起 ReentrantLock 就不得不說(shuō) AQS ,因?yàn)槠涞讓泳褪恰甘褂?AQS 去實(shí)現(xiàn)」的。

ReentrantLock有兩種模式,一種是公平鎖,一種是非公平鎖。

  • 公平模式下等待線程入隊(duì)列后會(huì)嚴(yán)格按照隊(duì)列順序去執(zhí)行
  • 非公平模式下等待線程入隊(duì)列后有可能會(huì)出現(xiàn)插隊(duì)情況

「公平鎖」

第一步:「獲取狀態(tài)的 state 的值」

  • 如果 state=0 即代表鎖沒(méi)有被其它線程占用,執(zhí)行第二步。
  • 如果 state!=0 則代表鎖正在被其它線程占用,執(zhí)行第三步。

第二步:「判斷隊(duì)列中是否有線程在排隊(duì)等待」

  • 如果不存在則直接將鎖的所有者設(shè)置成當(dāng)前線程,且更新?tīng)顟B(tài) state 。
  • 如果存在就入隊(duì)。

第三步:「判斷鎖的所有者是不是當(dāng)前線程」

  • 如果是則更新?tīng)顟B(tài) state 的值。
  • 如果不是,線程進(jìn)入隊(duì)列排隊(duì)等待。

「非公平鎖」

獲取狀態(tài)的 state 的值

  • 如果 state=0 即代表鎖沒(méi)有被其它線程占用,則設(shè)置當(dāng)前鎖的持有者為當(dāng)前線程,該操作用 CAS 完成。
  • 如果不為0或者設(shè)置失敗,代表鎖被占用進(jìn)行下一步。

此時(shí)「獲取 state 的值」

  • 如果是,則給state+1,獲取鎖
  • 如果不是,則進(jìn)入隊(duì)列等待
  • 如果是0,代表剛好線程釋放了鎖,此時(shí)將鎖的持有者設(shè)為自己
  • 如果不是0,則查看線程持有者是不是自己

二十七.多線程的創(chuàng)建方式有哪些?

1、「繼承Thread類」,重寫(xiě)run()方法

  1. public class Demo extends Thread{ 
  2.     //重寫(xiě)父類Thread的run() 
  3.     public void run() { 
  4.     } 
  5.     public static void main(String[] args) { 
  6.         Demo d1 = new Demo(); 
  7.         Demo d2 = new Demo(); 
  8.         d1.start(); 
  9.         d2.start(); 
  10.     } 

2.「實(shí)現(xiàn)Runnable接口」,重寫(xiě)run()

  1. public class Demo2 implements Runnable{ 
  2.  
  3.     //重寫(xiě)Runnable接口的run() 
  4.     public void run() { 
  5.     } 
  6.      
  7.     public static void main(String[] args) { 
  8.         Thread t1 = new Thread(new Demo2()); 
  9.         Thread t2 = new Thread(new Demo2()); 
  10.         t1.start(); 
  11.         t2.start(); 
  12.     } 
  13.  

3.「實(shí)現(xiàn) Callable 接口」

  1. public class Demo implements Callable<String>{ 
  2.  
  3.     public String call() throws Exception { 
  4.         System.out.println("正在執(zhí)行新建線程任務(wù)"); 
  5.         Thread.sleep(2000); 
  6.         return "結(jié)果"
  7.     } 
  8.  
  9.     public static void main(String[] args) throws InterruptedException, ExecutionException { 
  10.         Demo d = new Demo(); 
  11.         FutureTask<String> task = new FutureTask<>(d); 
  12.         Thread t = new Thread(task); 
  13.         t.start(); 
  14.         //獲取任務(wù)執(zhí)行后返回的結(jié)果 
  15.         String result = task.get(); 
  16.     } 
  17.      

4.「使用線程池創(chuàng)建」

  1. public class Demo { 
  2.     public static void main(String[] args) { 
  3.         Executor threadPool = Executors.newFixedThreadPool(5); 
  4.         for(int i = 0 ;i < 10 ; i++) { 
  5.             threadPool.execute(new Runnable() { 
  6.                 public void run() { 
  7.                     //todo 
  8.                 } 
  9.             }); 
  10.         } 
  11.          
  12.     } 

二十八.線程池有哪些參數(shù)?

「1.corePoolSize」:「核心線程數(shù)」,線程池中始終存活的線程數(shù)。

「2.maximumPoolSize」: 「最大線程數(shù)」,線程池中允許的最大線程數(shù)。

「3.keepAliveTime」: 「存活時(shí)間」,線程沒(méi)有任務(wù)執(zhí)行時(shí)最多保持多久時(shí)間會(huì)終止。

「4.unit」: 「單位」,參數(shù)keepAliveTime的時(shí)間單位,7種可選。

「5.workQueue」: 一個(gè)「阻塞隊(duì)列」,用來(lái)存儲(chǔ)等待執(zhí)行的任務(wù),均為線程安全,7種可選。

「6.threadFactory」: 「線程工廠」,主要用來(lái)創(chuàng)建線程,默及正常優(yōu)先級(jí)、非守護(hù)線程。

「7.handler」:「拒絕策略」,拒絕處理任務(wù)時(shí)的策略,4種可選,默認(rèn)為AbortPolicy。

二十九.線程池的執(zhí)行流程?

判斷線程池中的線程數(shù)「是否大于設(shè)置的核心線程數(shù)」

  • 如果「沒(méi)有滿」,則「放入隊(duì)列」,等待線程空閑時(shí)執(zhí)行任務(wù)
  • 如果隊(duì)列已經(jīng)「滿了」,則判斷「是否達(dá)到了線程池設(shè)置的最大線程數(shù)」
  • 如果「沒(méi)有達(dá)到」,就「創(chuàng)建新線程」來(lái)執(zhí)行任務(wù)
  • 如果已經(jīng)「達(dá)到了」最大線程數(shù),則「執(zhí)行指定的拒絕策略」
  • 如果「小于」,就「創(chuàng)建」一個(gè)核心線程來(lái)執(zhí)行任務(wù)
  • 如果「大于」,就會(huì)「判斷緩沖隊(duì)列是否滿了」

三十.線程池的拒絕策略有哪些?

  • 「AbortPolicy」:直接丟棄任務(wù),拋出異常,這是默認(rèn)策略
  • 「CallerRunsPolicy」:只用調(diào)用者所在的線程來(lái)處理任務(wù)
  • 「DiscardOldestPolicy」:丟棄等待隊(duì)列中最舊的任務(wù),并執(zhí)行當(dāng)前任務(wù)
  • 「DiscardPolicy」:直接丟棄任務(wù),也不拋出異常

三十一.介紹一下四種引用類型?

「強(qiáng)引用 StrongReference」

  1. Object obj = new Object();  
  2. //只要obj還指向Object對(duì)象,Object對(duì)象就不會(huì)被回收 

垃圾回收器不會(huì)回收被引用的對(duì)象,哪怕內(nèi)存不足時(shí),JVM 也會(huì)直接拋出 OutOfMemoryError,除非賦值為 null。

  • 「軟引用 SoftReference」

軟引用是用來(lái)描述一些非必需但仍有用的對(duì)象。在內(nèi)存足夠的時(shí)候,軟引用對(duì)象不會(huì)被回收,只有在內(nèi)存不足時(shí),系統(tǒng)則會(huì)回收軟引用對(duì)象,如果回收了軟引用對(duì)象之后仍然沒(méi)有足夠的內(nèi)存,才會(huì)拋出內(nèi)存溢出異常。

  • 「弱引用 WeakReference」

弱引用的引用強(qiáng)度比軟引用要更弱一些,無(wú)論內(nèi)存是否足夠,只要 JVM 開(kāi)始進(jìn)行垃圾回收,那些被弱引用關(guān)聯(lián)的對(duì)象都會(huì)被回收。

  • 「虛引用 PhantomReference」

虛引用是最弱的一種引用關(guān)系,如果一個(gè)對(duì)象僅持有虛引用,那么它就和沒(méi)有任何引用一樣,它隨時(shí)可能會(huì)被回收,在 JDK1.2 之后,用 PhantomReference 類來(lái)表示,通過(guò)查看這個(gè)類的源碼,發(fā)現(xiàn)它只有一個(gè)構(gòu)造函數(shù)和一個(gè) get() 方法,而且它的 get() 方法僅僅是返回一個(gè)null,也就是說(shuō)將永遠(yuǎn)無(wú)法通過(guò)虛引用來(lái)獲取對(duì)象,虛引用必須要和 ReferenceQueue 引用隊(duì)列一起使用,NIO 的堆外內(nèi)存就是靠其管理。

三十二.深拷貝、淺拷貝是什么?

淺拷貝并不是真的拷貝,只是「復(fù)制指向某個(gè)對(duì)象的指針」,而不復(fù)制對(duì)象本身,新舊對(duì)象還是共享同一塊內(nèi)存。

深拷貝會(huì)另外「創(chuàng)造一個(gè)一模一樣的對(duì)象」,新對(duì)象跟原對(duì)象不共享內(nèi)存,修改新對(duì)象不會(huì)改到原對(duì)象。

三十三.聊聊 ThreadLocal 吧

ThreadLocal其實(shí)就是「線程本地變量」,他會(huì)在每個(gè)線程都創(chuàng)建一個(gè)副本,那么在線程之間訪問(wèn)內(nèi)部副本變量就行了,做到了線程之間互相隔離。

  • ThreadLocal 有一個(gè)「靜態(tài)內(nèi)部類 ThreadLocalMap」,ThreadLocalMap 又包含了一個(gè) Entry 數(shù)組,「Entry 本身是一個(gè)弱引用」,他的 key 是指向 ThreadLocal 的弱引用,「弱引用的目的是為了防止內(nèi)存泄露」,如果是強(qiáng)引用那么除非線程結(jié)束,否則無(wú)法終止,可能會(huì)有內(nèi)存泄漏的風(fēng)險(xiǎn)。
  • 但是這樣還是會(huì)存在內(nèi)存泄露的問(wèn)題,假如 key 和 ThreadLocal 對(duì)象被回收之后,entry 中就存在 key 為 null ,但是 value 有值的 entry 對(duì)象,但是永遠(yuǎn)沒(méi)辦法被訪問(wèn)到,同樣除非線程結(jié)束運(yùn)行?!附鉀Q方法就是調(diào)用 remove 方法刪除 entry 對(duì)象」。

三十四.一個(gè)對(duì)象的內(nèi)存布局是怎么樣的?

對(duì)象內(nèi)存布局

「1.對(duì)象頭」: 對(duì)象頭又分為 「MarkWord」 和 「Class Pointer」 兩部分。

  • 「MarkWord」:包含一系列的標(biāo)記位,比如輕量級(jí)鎖的標(biāo)記位,偏向鎖標(biāo)記位,gc記錄信息等等。
  • 「ClassPointer」:用來(lái)指向?qū)ο髮?duì)應(yīng)的 Class 對(duì)象(其對(duì)應(yīng)的元數(shù)據(jù)對(duì)象)的內(nèi)存地址。在 32 位系統(tǒng)占 4 字節(jié),在 64 位系統(tǒng)中占 8 字節(jié)。

「2.Length」:只在數(shù)組對(duì)象中存在,用來(lái)記錄數(shù)組的長(zhǎng)度,占用 4 字節(jié)

「3.Instance data」: 對(duì)象實(shí)際數(shù)據(jù),對(duì)象實(shí)際數(shù)據(jù)包括了對(duì)象的所有成員變量,其大小由各個(gè)成員變量的大小決定。(這里不包括靜態(tài)成員變量,因?yàn)槠涫窃诜椒▍^(qū)維護(hù)的)

「4.Padding」:Java 對(duì)象占用空間是 8 字節(jié)對(duì)齊的,即所有 Java 對(duì)象占用 bytes 數(shù)必須是 8 的倍數(shù),是因?yàn)楫?dāng)我們從磁盤(pán)中取一個(gè)數(shù)據(jù)時(shí),不會(huì)說(shuō)我想取一個(gè)字節(jié)就是一個(gè)字節(jié),都是按照一塊兒一塊兒來(lái)取的,這一塊大小是 8 個(gè)字節(jié),所以為了完整,padding 的作用就是補(bǔ)充字節(jié),「保證對(duì)象是 8 字節(jié)的整數(shù)倍」。

 

責(zé)任編輯:姜華 來(lái)源: moon聊技術(shù)
相關(guān)推薦

2021-11-04 14:32:17

Spring 面試作用域

2021-10-26 14:40:03

MySQL SQL 語(yǔ)句數(shù)據(jù)庫(kù)

2021-09-07 14:46:42

面試網(wǎng)絡(luò)HTTP 協(xié)議

2021-07-26 14:59:23

面試Redis內(nèi)存數(shù)據(jù)庫(kù)

2024-02-23 19:17:12

構(gòu)造函數(shù)C++開(kāi)發(fā)

2023-11-28 18:09:49

Java多態(tài)

2021-10-26 17:05:55

Redis字符串復(fù)雜度

2022-09-03 11:36:11

Python文件網(wǎng)絡(luò)

2021-08-12 09:28:24

Java多線程變量

2021-08-01 22:59:43

Object八股文quals

2021-05-06 07:27:57

面試任務(wù)調(diào)度器

2021-04-14 10:02:59

網(wǎng)絡(luò)八股文協(xié)議

2021-05-20 11:43:57

操作系統(tǒng)硬件軟件

2023-11-29 17:28:07

2024-10-12 09:26:32

線程池系統(tǒng)核心線程

2023-01-13 18:04:03

面試題消息中間件

2024-06-05 10:59:51

2022-05-19 08:41:09

JVM虛擬機(jī)架構(gòu)

2022-05-27 14:43:45

JVM字節(jié)碼指令

2023-12-12 13:38:00

Java異步編程
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)