Java高階面試題及答案【第二部分】

Java知音發表於2018-05-03

談一談對MySQL InnoDB的認識

介紹:

InnoDB引擎是MySQL資料庫的一個重要的儲存引擎,和其他儲存引擎相比,InnoDB引擎的優點是支援相容ACID的事務(類似於PostgreSQL),以及引數完整性(有外來鍵)等。現在Innobase實行雙認證授權.MySQL5.5.5以後預設的儲存引擎都是InnoDB引擎。

特點是:

1、具有較好的事務支援:支援4個事務隔離級別,支援多版本讀

2、行級鎖定:通過索引實現,全表掃描仍然會是表鎖,注意間隙鎖的影響

3、讀寫阻塞與事務隔離級別相關

4、具有非常高效的快取特性:能快取索引,也能快取資料

5、整個表和主鍵以Cluster方式儲存,組成一顆平衡樹

6、所有Secondary Index都會儲存主鍵資訊

適用場景:

1、需要事務支援(具有較好的事務特性)

2、行級鎖定對高併發有很好的適應能力,但需要確保查詢是通過索引完成

3、資料更新較為頻繁的場景

4、資料一致性要求較高

5、硬體裝置記憶體較大,可以利用InnoDB較好的快取能力來提高記憶體利用率,儘可能減少磁碟IO


談一談資料庫事務的隔離級別?

1、Read uncommitted(讀未提交)就是一個事務可以讀取另一個未提交事務的資料。

2、Read committed(讀提交)就是一個事務要等另一個事務提交後才能讀取資料。

3、Repeatable read(重複讀)就是在開始讀取資料(事務開啟)時,不再允許修改操作。

4、Serializable(序列化)在該級別下,事務序列化順序執行,可以避免髒讀、不可重複讀與幻讀。是最高的事務隔離級別,但是這種事務隔離級別效率低下,比較耗資料庫效能,一般不使用。

事務的作用就是保證資料的一致性、完整性。事務隔離級別越高,在併發下會產生的問題就越少,但同時付出的效能消耗也將越大,因此很多時候必須在併發性和效能之間做一個權衡。所以設立了幾種事務隔離級別,以便讓不同的專案可以根據自己專案的併發情況選擇合適的事務隔離級別,對於在事務隔離級別之外會產生的併發問題,在程式碼中做補償。


MySQL主備同步的基本原理

MySQL支援單向、非同步複製,複製過程中一個伺服器充當主伺服器,而一個或多個其它伺服器充當從伺服器。

MySQL複製是基於主伺服器在二進位制日誌中跟蹤所有對資料庫的更改。因此,要進行復制,必須在主伺服器上啟用二進位制日誌。每個從伺服器從主伺服器接收主伺服器已經記錄到日誌的資料。

當一個從伺服器連線主伺服器時,它通知主伺服器從伺服器在日誌中讀取的最後一次成功更新的位置。從伺服器接收從那時起發生的任何更新,並在本機上執行相同的更新。然後封鎖並等待主伺服器通知新的更新。從伺服器執行備份不會干擾主伺服器,在備份過程中主伺服器可以繼續處理更新。


Java語言中一個顯著的特點就是引入了垃圾回收機制,這個大家都清楚,垃圾回收的概念這裡也不做介紹,重點是垃圾回收是在什麼時候開始?對什麼東西,做了什麼事情?

GC何時開始:

所有的回收器型別都是基於分代技術來實現的,那就必須要清楚物件按其生命週期是如何劃分的。

  • 年輕代:劃分為三個區域:原始區(Eden)和兩個小的存活區(Survivor),兩個存活區按功能分為From和To。絕大多數的物件都在原始區分配,超過一個垃圾回收操作仍然存活的物件放到存活區。垃圾回收絕大部分發生在年輕代。

  • 年老代:儲存年輕代中經過多個回收週期仍然存活的物件,對於一些大的記憶體分配,也可能直接分配到永久代。

  • 持久代:儲存類、方法以及它們的描述資訊,這裡基本不產生垃圾回收。

有了以上這些鋪墊之後開始回答GC何時開始:

Eden記憶體滿了之後,開始Minor GC(從年輕代空間回收記憶體被稱為 Minor GC);升到老年代的物件所需空間大於老年代剩餘空間時開始Full GC(但也可能小於剩餘空間時,被HandlePromotionFailure引數強制Full GC)

對什麼東西操作,即垃圾回收的物件是什麼:

從root開始搜尋沒有可達物件,而且經過第一次標記、清理後,仍然沒有復活的物件。

做了什麼東西:

主要做了清理物件,整理記憶體的工作。具體的引申如下

垃圾回收器的型別:

  • 序列垃圾回收器(Serial Garbage Collector)

  • 並行垃圾回收器(Parallel Garbage Collector)

  • 併發標記掃描垃圾回收器(CMS Garbage Collector)

  • G1垃圾回收器(G1 Garbage Collector)

垃圾回收演算法:

  • 引用計數法

  • 標記清除法

  • 複製演算法

  • 標記壓縮演算法

  • 分代演算法

  • 分割槽演算法

以上這些,可以自己瞭解一下,這裡列舉幾篇相關文章:
JVM的記憶體區域劃分
JVM知識點梳理
JVM記憶體分配與回收
JVM記憶體管理機制
Java虛擬機器學習 - 垃圾收集器


類在虛擬機器中的載入過程

載入Loading:

通過一個類的全限定名來獲取一個二進位制位元組流、將這個位元組流所代表的靜態儲存結構轉化為方法區的執行時資料結構、在記憶體中生成一個代表這個類的java.lang.Class物件,作為方法區這個類的各種資料的訪問入口。

驗證Verification:

確保Class檔案的位元組流中包含的資訊符合當前虛擬機器的要求,並不會危害虛擬機器的自身安全。

準備Preparation:

正式為類變數分配記憶體並設定類變數初始值。

解析Resolution:

虛擬機器將常量池內的符號引用替換為直接引用的過程。

初始化Initialization:

類載入過程的最後一步,到了這個階段才真正開始執行類中定義的Java程式程式碼。

使用Using:

根據你寫的程式程式碼定義的行為執行。

解除安裝Unloading:

GC負責解除安裝,這部分一般不用討論。

以上這些拋磚引玉,歡迎留言更清晰的類載入過程,相關文章可以閱讀:
類載入器詳解
詳解java類的生命週期
談談我對物件導向以及類與物件的理解


強引用、軟引用、弱引用、虛引用與GC的關係

強引用:new出的物件之類的引用,只要強引用還在,永遠不會回收。

軟引用:引用但非必須的物件,記憶體溢位異常之前回收。

弱引用:非必須的物件,物件只能生存到下一次垃圾收集發生之前。

虛引用:對生存時間無影響,在垃圾回收時得到通知。

這個相對好理解了,相關閱讀如下:
Java 如何有效地避免OOM:善於利用軟引用和弱引用


說一下spring中Bean的作用域

singleton:

Spring IoC容器中只會存在一個共享的Bean例項,無論有多少個Bean引用它,始終指向同一物件。Singleton作用域是Spring中的預設作用域。

prototype:

每次通過Spring容器獲取prototype定義的bean時,容器都將建立一個新的Bean例項,每個Bean例項都有自己的屬性和狀態,而singleton全域性只有一個物件。

request:

在一次Http請求中,容器會返回該Bean的同一例項。而對不同的Http請求則會產生新的Bean,而且該bean僅在當前Http Request內有效。

session:

在一次Http Session中,容器會返回該Bean的同一例項。而對不同的Session請求則會建立新的例項,該bean例項僅在當前Session內有效。

global Session:

在一個全域性的Http Session中,容器會返回該Bean的同一個例項,僅在使用portlet context時有效。


說一下spring中Bean的生命週期

  • 例項化一個Bean,也就是我們通常說的new。

  • 按照Spring上下文對例項化的Bean進行配置,也就是IOC注入。

  • 如果這個Bean實現了BeanNameAware介面,會呼叫它實現的setBeanName(String beanId)方法,此處傳遞的是Spring配置檔案中Bean的ID。

  • 如果這個Bean實現了BeanFactoryAware介面,會呼叫它實現的setBeanFactory(),傳遞的是Spring工廠本身(可以用這個方法獲取到其他Bean)。

  • 如果這個Bean實現了ApplicationContextAware介面,會呼叫setApplicationContext(ApplicationContext)方法,傳入Spring上下文。

  • 如果這個Bean關聯了BeanPostProcessor介面,將會呼叫postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor經常被用作是Bean內容的更改,並且由於這個是在Bean初始化結束時呼叫After方法,也可用於記憶體或快取技術。

  • 如果這個Bean在Spring配置檔案中配置了init-method屬性會自動呼叫其配置的初始化方法。

  • 如果這個Bean關聯了BeanPostProcessor介面,將會呼叫postAfterInitialization(Object obj, String s)方法。

  • 當Bean不再需要時,會經過清理階段,如果Bean實現了DisposableBean介面,會呼叫其實現的destroy方法。

  • 最後,如果這個Bean的Spring配置中配置了destroy-method屬性,會自動呼叫其配置的銷燬方法。


對Spring中依賴注入兩種方式的認識

兩種注入方式為:構造方法注入和設值注入

  1. 設值注入與傳統的JavaBean的寫法更相似,程式設計師更容易理解、接受,通過setter方式設定依賴關係顯得更加直觀、明顯;

  2. 對於複雜的依賴關係,如果採用構造注入,會導致構造器過於臃腫,難以閱讀。Spring在建立Bean例項時,需要同時例項化其依賴的全部例項,因而會產生浪費。而使用設定注入,則避免這下問題;

  3. 在某些屬性可選的情況下,多引數的構造器更加笨拙,官方更鼓勵使用設值注入。

  4. 構造注入可以在構造器中決定依賴關係的注入順序,優先依賴的優先注入。

  5. 對於依賴關係無須變化的Bean,構造注入更有用處,因為沒有setter方法,所有的依賴關係全部在構造器內設定,因此,不用擔心後續程式碼對依賴關係的破壞。

  6. 構造注入使依賴關係只能在構造器中設定,則只有元件的建立者才能改變元件的依賴關係。對元件的呼叫者而言,元件內部的依賴關係完全透明,更符合高內聚的原則。

  7. 設值注入不會重寫構造方法的值。如果我們對同一個變數同時使用了構造方法注入又使用了設定方法注入的話,那麼構造方法將不能覆蓋由設值方法注入的值。

  8. 建議採用以設值注入為主,構造注入為輔的注入策略。對於依賴關係無須變化的注入,儘量採用構造注入;而其他的依賴關係的注入,則考慮採用set注入。


Spring框架中都用到了哪些設計模式?

  • 代理模式:在AOP和remoting中被用的比較多。

  • 單例模式:在spring配置檔案中定義的bean預設為單例模式。

  • 模板方法模式:用來解決程式碼重複的問題。

  • 前端控制器模式:Spring提供了DispatcherServlet來對請求進行分發。

  • 依賴注入模式:貫穿於BeanFactory / ApplicationContext介面的核心理念。

  • 工廠模式:BeanFactory用來建立物件的例項。


BeanFactory 和ApplicationContext的區別

BeanFactory和ApplicationContext都是介面,並且ApplicationContext是BeanFactory的子介面。

BeanFactory是Spring中最底層的介面,提供了最簡單的容器的功能,只提供了例項化物件和拿物件的功能。而ApplicationContext是Spring的一個更高階的容器,提供了更多的有用的功能。

ApplicationContext提供的額外的功能:國際化的功能、訊息傳送、響應機制、統一載入資源的功能、強大的事件機制、對Web應用的支援等等。

載入方式的區別:BeanFactory採用的是延遲載入的形式來注入Bean;ApplicationContext則相反的,它是在Ioc啟動時就一次性建立所有的Bean,好處是可以馬上發現Spring配置檔案中的錯誤,壞處是造成浪費。


這一篇先總結這些,歡迎關注我的公眾號“Java知音”,只推送有價值的文章!

Java高階面試題及答案【第二部分】


相關文章