《面試填坑系列》大廠常問Java高級面試100題解析(一)

Java高級面試100題及解析

數據庫篇

  1. 事務四大特性(ACID)原子性、一致性、隔離性、持久性?
  2. 事務的併發?事務隔離級別,每一個級別會引起什麼問題,MySQL默認是哪一個級別?
  3. MySQL常見的三種存儲引擎(InnoDB、MyISAM、MEMORY)的區別?
  4. MySQL的MyISAM與InnoDB兩種存儲引擎在,事務、鎖級別,各自的適用場景?
  5. MySQL B+Tree 索引和 Hash 索引的區別?
  6. sql 查詢語句肯定建立哪一種類型的索引,如何優化查詢
  7. 有哪些鎖(樂觀鎖悲觀鎖),select 時怎麼加排它鎖?
  8. 數據庫的讀寫分離、主從複製,主從複製分析的 7 個問題?
  9. MySQL 都有什麼鎖,死鎖斷定原理和具體場景,死鎖怎麼解決?
  10. MySQL 高併發環境解決方案?

Spring篇

  1. Spring IoC、AOP 原理
  2. Spring Bean 生命週期 
  3. Spring Bean 注入是如何解決循環依賴問題的
  4. 怎樣用註解的方式配置 Spring?
  5. Spring 事務爲什麼失效了
  6. SpringMVC 的流程?
  7. Springmvc 的優勢:
  8. Spring 通知類型使用場景分別有哪些?
  9. IoC 控制反轉設計原理?
  10. Spring 如何處理線程併發問題?

JVM篇

  1. Java 類加載過程?
  2. 描述一下 JVM 加載 Class 文件的原理機制?
  3. 簡述 Java 垃圾回收機制。
  4. 什麼是類加載器,類加載器有哪些?
  5. 如何判斷一個對象是否存活?(或者 GC 對象的斷定方法)
  6. 垃圾回收的優勢和原理。並考慮 2 種回收機制。
  7. 垃圾回收器的基本原理是什麼?垃圾回收器能夠立刻回收內存嗎?有什麼辦法主動通知虛擬機進行垃圾回收
  8. Java 中會存在內存泄漏嗎,請簡單描述。
  9. 簡述 Java 內存分配與回收策率以及 Minor GC 和 Major GC。
  10. Java 中垃圾收集的方法有哪些?

Java併發篇

  1. Synchronized 用過嗎,其原理是什麼?
  2. 爲何說 Synchronized 是非公平鎖?
  3. 爲何說 Synchronized 是一個悲觀鎖?樂觀鎖的實現原理又是什麼?什麼是 CAS,它有
  4. 請儘量詳盡地對比下 Synchronized 和 ReentrantLock 的異同。
  5. 談談 ReadWriteLock 和 StampedLock。
  6. 如何讓 Java 的線程彼此同步?你瞭解過哪些同步器?請分別介紹下。
  7. 線程池中的線程是怎麼建立的?是一開始就隨着線程池的啓動建立好的嗎?
  8. 提到能夠經過配置不一樣參數建立出不一樣的線程池,那麼 Java 中默認實現好的線程池又有哪些呢?請比
  9. 如何在 Java 線程池中提交線程?
  10. 請談談 volatile 有什麼特色,爲何它能保證變量對全部線程的可見性?

Redis緩存篇

  1. 什麼是 Redis 事務?原理是什麼?
  2. 請介紹一下 Redis 的數據類型 SortedSet(zset)以及底層實現機制?
  3. Redis 經常使用的命令有哪些?
  4. 什麼是緩存穿透?怎麼解決?
  5. 什麼是緩存雪崩? 怎麼解決?
  6. 請介紹幾個可能致使 Redis 阻塞的緣由
  7. 緩存的更新策略有幾種?分別有什麼注意事項?
  8. Redis 爲何設計成單線程的?
  9. Redis 持久化機制 AOF 和 RDB 有哪些不一樣之處?
  10. Redis 緩存失效策略有哪些?

RabbitMQ篇

  1. RabbitMQ 的使用場景有哪些?
  2. RabbitMQ 有哪些重要的角色?
  3. RabbitMQ 有哪些重要的組件?
  4. RabbitMQ 的消息是怎麼發送的?
  5. RabbitMQ 怎麼保證消息的穩定性?
  6. RabbitMQ 怎麼避免消息丟失?
  7. 要保證消息持久化成功的條件有哪些?
  8. RabbitMQ 有幾種廣播類型?
  9. RabbitMQ 怎麼實現延遲消息隊列?
  10. RabbitMQ 集羣中惟一一個磁盤節點崩潰了會發生什麼狀況?

Java集合篇

  1. ArrayList 和 Vector 的區別
  2. 說說 ArrayList,Vector, LinkedList 的存儲性能和特性
  3. 快速失敗 (fail-fast) 和安全失敗 (fail-safe) 的區別是什麼?
  4. hashmap 的數據結構。
  5. HashMap 的工做原理是什麼?
  6. Hashmap 何時進行擴容呢?
  7. HashSet 和 TreeSet 有什麼區別?
  8. HashSet 的底層實現是什麼?
  9. LinkedHashMap 的實現原理?
  10. Collection 和 Collections 的區別。

微服務篇

  1. 使用Spring Cloud有什麼優點?
  2. 服務註冊和發現是什麼意思?Spring Cloud如何實現?
  3. 負載平衡的意義什麼?
  4. 什麼是Hystrix?它如何實現容錯?
  5. 什麼是Hystrix斷路器?咱們須要它嗎?
  6. 什麼是Netflix Feign?它的優勢是什麼?
  7. Spring Boot 的核心配置文件有哪幾個?它們的區別是什麼?
  8. Spring Boot 的核心註解是哪一個?它主要由哪幾個註解組成的?
  9. Spring Boot中的監視器是什麼?
  10. 什麼是Swagger?你用Spring Boot實現了它嗎?

Zookeeper篇

  1. zk的命名服務(文件系統)
  2. zk的配置管理(文件系統、通知機制)
  3. Zookeeper集羣管理(文件系統、通知機制)
  4. Zookeeper分佈式鎖(文件系統、通知機制)
  5. 獲取分佈式鎖的流程
  6. Zookeeper隊列管理(文件系統、通知機制)
  7. Zookeeper數據複製
  8. Zookeeper工做原理
  9. zookeeper是如何保證事務的順序一致性的?
  10. Zookeeper 下 Server工做狀態

解決方案篇

本次更新Java 面試題(一)的1~20題答案

數據庫篇

1. 事務四大特性(ACID)原子性、一致性、隔離性、持久性?

1.1. 原子性(Atomicity)前端

原子性是指事務包含的全部操做要麼所有成功,要麼所有失敗回滾,所以事務的操做若是成功就必需要徹底應用到數據庫,若是操做失敗則不能對數據庫有任何影響。

1.2. 一致性(Consistency)java

事務開始前和結束後,數據庫的完整性約束沒有被破壞。好比 A B 轉帳,不可能 A 扣了錢, B 卻沒收到

1.3. 隔離性(Isolation)面試

隔離性是當多個用戶併發訪問數據庫時,好比操做同一張表時,數據庫爲每個用戶開啓的事務, 不能被其餘事務的操做所幹擾,多個併發事務之間要相互隔離

同一時間,只容許一個事務請求同一數據,不一樣的事務之間彼此沒有任何干擾。好比A正在從一張銀行卡中取錢,在A取錢的過程結束前,B不能向這張卡轉帳。

1.4.持久性(Durability)

持久性是指一個事務一旦被提交了,那麼對數據庫中的數據的改變就是永久性的,即使是在數據庫系統遇到故障的狀況下也不會丟失提交事務的操做

2.事務的併發?事務隔離級別,每一個級別會引起什麼問題,MySQL默認是哪一個級別?

從理論上來講,事務應該彼此徹底隔離,以免併發事務所致使的問題,然而,那樣會對性能產生極大的影響,由於事務必須按順序運行, 在實際開發中 , 爲了提高性能 , 事務會以較低的隔離級別運行, 事務的隔離級別能夠經過隔離事務屬性指定

2.1事務的併發問題算法

一、髒讀:事務A讀取了事務B更新的數據,而後B回滾操做,那麼A讀取到的數據是髒數據sql

二、不可重複讀:事務A屢次讀取同一數據,事務B在事務A屢次讀取的過程當中,對數據做了更新並提交,致使事務A屢次讀取同一數據時,結果所以本事務前後兩次讀到的數據結果會不一致。數據庫

三、幻讀:幻讀解決了不重複讀,保證了同一個事務裏,查詢的結果都是事務開始時的狀態(一致性)。編程

例如:事務T1對一個表中全部的行的某個數據項作了從「1」修改成「2」的操做這時事務T2又對這個表中插入了一行數據項,而這個數據項的數值仍是爲「1」而且提交給數據庫。而操做事務T1的用戶若是再查看剛剛修改的數據,會發現還有跟沒有修改同樣,其實這行是從事務T2中添加的,就好像產生幻覺同樣,這就是發生了幻讀。

小結:不可重複讀的和幻讀很容易混淆,不可重複讀側重於修改,幻讀側重於新增或刪除。解決不可重複讀的問題只需鎖住知足條件的行,解決幻讀須要鎖表。

2.2事務的隔離級別後端

事務隔離級別緩存

髒讀安全

不可重複讀

幻讀

讀未提交 read-uncommitted

不可重複讀 read-committed

可重複讀 repeatable-read

串行化 serializable

讀未提交:另外一個事務修改了數據,但還沒有提交,而本事務中的SELECT會讀到這些未被提交的數據 髒讀

不可重複讀:事務A屢次讀取同一數據,事務B在事務A屢次讀取的過程當中,對數據做了更新並提交,致使事務A屢次讀取同一數據時,結果所以本事務前後兩次讀到的數據結果會不一致。

可重複讀:在同一個事務裏,SELECT的結果是事務開始時時間點的狀態,所以,一樣的
SELECT 操做讀到的結果會是一致的。可是,會有 幻讀現象

串行化:最高的隔離級別,在這個隔離級別下,不會產生任何異常。併發的事務,就像事務是在一個個按照順序執行同樣

MySQL默認的事務隔離級別爲repeatable-read 

MySQL支持4中事務隔離級別

事務的隔離級別要獲得底層數據庫引擎的支持,而不是應用程序或者框架的支持. 

Oracle支持的2種事務隔離級別:READ_COMMITED , SERIALIZABLE

2.3補充

1. SQL規範所規定的標準,不一樣的數據庫具體的實現可能會有些差別

2. MySQL中默認事務隔離級別是「可重複讀」時並不會鎖住讀取到的行

  • 事務隔離級別未提交讀時,寫數據只會鎖住相應的行。
  • 事務隔離級別爲可重複讀時,寫數據會鎖住整張表。
  • 事務隔離級別爲串行化時,讀寫數據都會鎖住整張表。

隔離級別越高越能保證數據的完整性和一致性,可是對併發性能的影響也越大,魚和熊掌不可兼得啊。 對於多數應用程序,能夠優先考慮把數據庫系統的隔離級別設爲 Read Committed
,它可以避免髒讀取,並且具備較好的併發性能。儘管它會致使不可重複讀、幻讀這些併發問題,在可能出現這類問題的個別場合,能夠由應用程序採用悲觀鎖或樂觀鎖來控制。

3. MySQL常見的三種存儲引擎(InnoDB、MyISAM、MEMORY)的區別?

MySQL 存儲引擎 MyISAM 與 InnoDB 如何選擇

MySQL 有多種存儲引擎,每種存儲引擎有各自的優缺點,能夠擇優選擇使用:MyISAM、InnoDB、MERGE、MEMORY(HEAP)、BDB(BerkeleyDB)、EXAMPLE、FEDERATED、ARCHIVE、CSV、BLACKHOLE

雖然 MySQL 裏的存儲引擎不僅是 MyISAM 與 InnoDB 這兩個,但經常使用的就是兩個

兩種存儲引擎的大體區別表如今

  • InnoDB 支持事務,MyISAM 不支持,這一點是很是之重要。事務是一種高級的處理方式,如在一些列增刪改中只要哪一個出錯還能夠回滾還原,而 MyISAM 就不能夠了。
  • MyISAM 適合查詢以及插入爲主的應用
  • InnoDB 適合頻繁修改以及涉及到安全性較高的應用
  • InnoDB 支持外鍵,MyISAM 不支持。
  • 從 MySQL5.5.5 之後,InnoDB 是默認引擎
  • InnoDB 不支持 FULLTEXT 類型的索引。
  • InnoDB 中不保存表的行數,如select count(*) from table時,InnoDB 須要掃描一遍整個表來計算有多少行,可是 MyISAM 只要簡單的讀出保存好的行數便可。注意的是,當 count(*)語句包含 where 條件時 MyISAM 也須要掃描整個表。
  • 對於自增加的字段,InnoDB 中必須包含只有該字段的索引,可是在 MyISAM 表中能夠和其餘字段一塊兒創建聯合索引。
  • DELETE FROM table時,InnoDB 不會從新創建表,而是一行一行的 刪除,效率很是慢MyISAM 則會重建表
  • InnoDB 支持行鎖(某些狀況下仍是鎖整表,如 update table set a=1 where user like '%lee%'

關於 MySQL 數據庫提供的兩種存儲引擎,MyISAM 與 InnoDB 選擇使用:

  • INNODB 會支持一些關係數據庫的高級功能如事務功能和行級鎖,MyISAM 不支持
  • MyISAM 的性能更優,佔用的存儲空間少,因此,選擇何種存儲引擎,視具體應用而定。
  • 若是你的應用程序必定要使用事務,毫無疑問你要選擇 INNODB 引擎。但要注意,INNODB 的行級鎖是有條件的。在 where 條件沒有使用主鍵時,照樣會鎖全表。好比 DELETE FROM mytable 這樣的刪除語句。
  • 若是你的應用程序對查詢性能要求較高,就要使用 MyISAM 了MyISAM 索引和數據是分開的,並且其索引是壓縮的,能夠更好地利用內存。因此它的查詢性能明顯優於 INNODB。壓縮後的索引也能節約一些磁盤空間。MyISAM 擁有全文索引的功能,這能夠極大地優化 LIKE 查詢的效率

有人說 MyISAM 只能用於小型應用,其實這只是一種偏見。若是數據量比較大,這是須要經過升級架構來解決,好比分表分庫,而不是單純地依賴存儲引擎。

如今通常都是選用 innodb 了,主要是 MyISAM 的全表鎖,讀寫串行問題,併發效率鎖表,效率低,MyISAM 對於讀寫密集型應用通常是不會去選用的。

4. MySQL的MyISAMInnoDB兩種存儲引擎在,事務、鎖級別,各自的適用場景?

事務處理上方面

  • MyISAM強調的是性能,每次查詢具備原子性,其執行數度比 InnoDB 類型更快,可是不提供事務支持
  • InnoDB提供事務支持事務,外部鍵等高級數據庫功能。 具備事務(commit)、回滾(rollback)和崩潰修復能力(crash recovery capabilities)的事務安全(transaction-safe (ACID compliant))型表。

鎖級別

  • MyISAM只支持表級鎖,用戶在操做 MyISAM 表時,select,update,delete,insert 語句都會給表自動加鎖,若是加鎖之後的表知足 insert 併發的狀況下,能夠在表的尾部插入新的數據。
  • InnoDB:支持事務和行級鎖,是 innodb 的最大特點。行鎖大幅度提升了多用戶併發操做的新能。可是 InnoDB 的行鎖,只是在 WHERE 的主鍵是有效的,非主鍵的 WHERE 都會鎖全表的。

5.MySQL B+Tree 索引和 Hash 索引的區別?

  • Hash 索引結構的特殊性,其檢索效率很是高,索引的檢索能夠一次定位;
  • B+樹索引須要從根節點到枝節點,最後才能訪問到頁節點這樣屢次的 IO 訪問;

那爲何你們不都用 Hash 索引而還要使用 B+樹索引呢?

Hash 索引

  1. Hash 索引僅僅能知足"=","IN"和"<=>"查詢,不能使用範圍查詢,由於通過相應的 Hash 算法處理以後的 Hash 值的大小關係,並不能保證和 Hash 運算前徹底同樣;
  2. Hash 索引沒法被用來避免數據的排序操做,由於 Hash 值的大小關係並不必定和 Hash 運算前的鍵值徹底同樣;
  3. Hash 索引不能利用部分索引鍵查詢,對於組合索引,Hash 索引在計算 Hash 值的時候是組合索引鍵合併後再一塊兒計算 Hash 值,而不是單獨計算 Hash 值,因此經過組合索引的前面一個或幾個索引鍵進行查詢的時候,Hash 索引也沒法被利用;
  4. Hash 索引在任什麼時候候都不能避免表掃描,因爲不一樣索引鍵存在相同 Hash 值,因此即便取知足某個 Hash 鍵值的數據的記錄條數,也沒法從 Hash 索引中直接完成查詢,仍是要回表查詢數據;
  5. Hash 索引遇到大量 Hash 值相等的狀況後性能並不必定就會比 B+樹索引高。

B+Tree 索引

MySQL 中,只有 HEAP/MEMORY 引擎才顯示支持 Hash 索引

經常使用的 InnoDB 引擎中默認使用的是 B+樹索引,它會實時監控表上索引的使用狀況,若是認爲創建哈希索引能夠提升查詢效率,則自動在內存中的「自適應哈希索引緩衝區」創建哈希索引(在 InnoDB 中默認開啓自適應哈希索引),經過觀察搜索模式,MySQL 會利用 index key 的前綴創建哈希索引,若是一個表幾乎大部分都在緩衝池中,那麼創建一個哈希索引可以加快等值查詢。

B+樹索引和哈希索引的明顯區別是:

若是是等值查詢,那麼哈希索引明顯有絕對優點由於只須要通過一次算法便可找到相應的鍵值;固然了,這個前提是,鍵值都是惟一的。若是鍵值不是惟一的,就須要先找到該鍵所在位置,而後再根據鏈表日後掃描,直到找到相應的數據

若是是範圍查詢檢索,這時候哈希索引就毫無用武之地了,由於原先是有序的鍵值,通過哈希算法後,有可能變成不連續的了,就沒辦法再利用索引完成範圍查詢檢索;

同理,哈希索引沒辦法利用索引完成排序,以及 like ‘xxx%’ 這樣的部分模糊查詢(這種部分模糊查詢,其實本質上也是範圍查詢);

哈希索引也不支持多列聯合索引的最左匹配規則

B+樹索引的關鍵字檢索效率比較平均,不像 B 樹那樣波動幅度大,在有大量重複鍵值狀況下,哈希索引的效率也是極低的,由於存在所謂的哈希碰撞問題

在大多數場景下,都會有範圍查詢、排序、分組等查詢特徵,用 B+樹索引就能夠了

6.sql 查詢語句肯定建立哪一種類型的索引,如何優化查詢

  • 性能優化過程當中,選擇在哪一個列上建立索引是最重要的步驟之一,能夠考慮使用索引的主要有兩種類型的列:在 where 子句中出現的列,在 join 子句中出現的列。
  • 考慮列中值的分佈,索引的列的基數越大,索引的效果越好。
  • 使用短索引,若是對字符串列進行索引,應該指定一個前綴長度,可節省大量索引空間,提高查詢速度。
  • 利用最左前綴,顧名思義,就是最左優先,在多列索引,有體現:(ALTER TABLE people ADD INDEX lname
    fname
    age (lame,fname,age);),所謂最左前綴原則就是先要看第一列,在第一列知足的條件下再看左邊第二列,以此類推
  • 不要過分建索引,只保持所需的索引。每一個額外的索引都要佔用額外的磁盤空間,並下降寫操做的性能
  • 在修改表的內容時,索引必須進行更新,有時可能須要重構,所以,索引越多,所花的時間越長
  • MySQL 只對一下操做符才使用索引<,<=,=,>,>=,between,in
  • 以及某些時候的 like(不以通配符%或_開頭的情形)。

7.有哪些鎖(樂觀鎖悲觀鎖),select 時怎麼加排它鎖?

悲觀鎖(Pessimistic Lock)

悲觀鎖的特色是先獲取鎖,再進行業務操做,即「悲觀」的認爲獲取鎖是很是有可能失敗的,所以要先確保獲取鎖成功再進行業務操做。一般所說的「一鎖二查三更新」即指的是使用悲觀鎖。一般來說在數據庫上的悲觀鎖須要數據庫自己提供支持,即經過經常使用的 select … for update 操做來實現悲觀鎖。當數據庫執行 select for update 時會獲取被 select 中的數據行的行鎖,所以其餘併發執行的 select for update 若是試圖選中同一行則會發生排斥(須要等待行鎖被釋放),所以達到鎖的效果。select for update 獲取的行鎖會在當前事務結束時自動釋放,所以必須在事務中使用。

這裏須要注意的一點是不一樣的數據庫對 select for update 的實現和支持都是有所區別的,例如 oracle 支持 select for update no wait,表示若是拿不到鎖馬上報錯,而不是等待,MySQL 就沒有 no wait 這個選項。另外MySQL 還有個問題是 select for update 語句執行中全部掃描過的行都會被鎖上,這一點很容易形成問題。所以若是在 MySQL 中用悲觀鎖務必要肯定走了索引,而不是全表掃描

樂觀鎖(Optimistic Lock)

樂觀鎖,也叫樂觀併發控制,它假設多用戶併發的事務在處理時不會彼此互相影響,各事務可以在不產生鎖的狀況下處理各自影響的那部分數據。在提交數據更新以前,每一個事務會先檢查在該事務讀取數據後,有沒有其餘事務又修改了該數據。若是其餘事務有更新的話,那麼當前正在提交的事務會進行回滾

樂觀鎖的特色先進行業務操做,不到萬不得已不去拿鎖。即「樂觀」的認爲拿鎖多半是會成功的,所以在進行完業務操做須要實際更新數據的最後一步再去拿一下鎖就好。

樂觀鎖在數據庫上的實現徹底是邏輯的,不須要數據庫提供特殊的支持通常的作法是在須要鎖的數據上增長一個版本號,或者時間戳,而後按照以下方式實現:

樂觀鎖(給表加一個版本號字段) 這個並非樂觀鎖的定義,給表加版本號,是數據庫實現樂觀鎖的一種方式

1\. SELECT data AS old_data, version AS old_version FROM …;
2\. 根據獲取的數據進行業務操做,獲得 new_data 和 new_version
3\. UPDATE SET data = new_data, version = new_version WHERE version = old_version
if (updated row > 0) {
    // 樂觀鎖獲取成功,操做完成
} else {
    // 樂觀鎖獲取失敗,回滾並重試
}
複製代碼

樂觀鎖在不發生取鎖失敗的狀況下開銷比悲觀鎖小,可是一旦發生失敗回滾開銷則比較大,所以適合用在取鎖失敗機率比較小的場景,能夠提高系統併發性能

樂觀鎖還適用於一些比較特殊的場景,例如在業務操做過程當中沒法和數據庫保持鏈接等悲觀鎖沒法適用的地方

總結

悲觀鎖和樂觀鎖是數據庫用來保證數據併發安全防止更新丟失的兩種方法,例子在select ... for update前加個事務就能夠防止更新丟失。悲觀鎖和樂觀鎖大部分場景下差別不大,一些獨特場景下有一些差異,通常咱們能夠從以下幾個方面來判斷。

  • 響應速度:若是須要很是高的響應速度,建議採用樂觀鎖方案,成功就執行,不成功就失敗,不須要等待其餘併發去釋放鎖。

  • 衝突頻率:若是衝突頻率很是高,建議採用悲觀鎖,保證成功率,若是衝突頻率大,樂觀鎖會須要屢次重試才能成功,代價比較大。

  • 重試代價:若是重試代價大,建議採用悲觀鎖。

8.數據庫的讀寫分離、主從複製,主從複製分析的 7 個問題?

主從複製的幾種方式

同步複製

  • 所謂的同步複製,意思是 master 的變化,必須等待 slave-1,slave-2,...,slave-n 完成後才能返回。 這樣,顯然不可取,也不是 MySQL 複製的默認設置。好比,在 WEB 前端頁面上,用戶增長了條記錄,須要等待很長時間。

異步複製

  • 如同 AJAX 請求同樣。master 只須要完成本身的數據庫操做便可。至於 slaves 是否收到二進制日誌,是否完成操做,不用關心,MySQL 的默認設置。

半同步複製

  • master 只保證 slaves 中的一個操做成功,就返回,其餘 slave 無論。 這個功能,是由 google 爲 MySQL 引入的。

主從複製分析的 7 個問題

問題 1:master 的寫操做,slaves 被動的進行同樣的操做,保持數據一致性,那麼 slave 是否能夠主動的進行寫操做?

假設 slave 能夠主動的進行寫操做,slave 又沒法通知 master,這樣就致使了 master 和 slave 數據不一致了。所以slave 不該該進行寫操做,至少是 slave 上涉及到複製的數據庫不能夠寫。實際上,這裏已經揭示了讀寫分離的概念

問題 2:主從複製中,能夠有 N 個 slave,但是這些 slave 又不能進行寫操做,要他們幹嗎?

以實現數據備份

相似於高可用的功能,一旦 master 掛了,可讓 slave 頂上去,同時 slave 提高爲 master

異地容災,好比 master 在北京,地震掛了,那麼在上海的 slave 還能夠繼續。

主要用於實現 scale out,分擔負載,能夠將讀的任務分散到 slaves 上

極可能的狀況是,一個系統的讀操做遠遠多於寫操做,所以寫操做發向 master,讀操做發向 slaves 進行操做

問題 3:主從複製中有 master,slave1,slave2,...等等這麼多 MySQL 數據庫,那好比一個 JAVA WEB 應用到底應該鏈接哪一個數據庫?

當 然,咱們在應用程序中能夠這樣,insert/delete/update這些更新數據庫的操做,用connection(for master)進行操做,select 用 connection(for slaves)進行操做。那咱們的應用程序還要完成怎麼從 slaves 選擇一個來執行 select,例如使用簡單的輪循算法

這樣的話,至關於應用程序完成了 SQL 語句的路由,並且與 MySQL 的主從複製架構很是關聯,一旦 master 掛了,某些 slave 掛了,那麼應用程序就要修改了。能不能讓應用程序與 MySQL 的主從複製架構沒有什麼太多關係呢?

找一個組件application program 只須要與它打交道,用它來完成 MySQL 的代理,實現 SQL 語句的路由

MySQL proxy 並不負責,怎麼從衆多的 slaves 挑一個?能夠交給另外一個組件(好比 haproxy)來完成。

這就是所謂的MySQL READ WRITE SPLITE,MySQL的讀寫分離。

問題 4:若是 MySQL proxy , direct , master 他們中的某些掛了怎麼辦?

總統通常都會弄個副總統,以防不測。一樣的,能夠給這些關鍵的節點來個備份。

問題 5:當 master 的二進制日誌每產生一個事件,都須要發往 slave,若是咱們有 N 個 slave,那是發 N 次,仍是隻發一次?

若是隻發一次,發給了 slave-1,那 slave-2,slave-3,...它們怎麼辦?

顯 然,應該發 N 次。實際上,在 MySQL master 內部,維護 N 個線程,每個線程負責將二進制日誌文件發往對應的 slave。master 既要負責寫操做,還的維護 N 個線程,負擔會很重。能夠這樣,slave-1 是 master 的從,slave-1 又是 slave-2,slave-3,...的主,同時 slave-1 再也不負責 select。 slave-1 將 master 的複製線程的負擔,轉移到本身的身上這就是所謂的多級複製的概念

問題 6:當一個 select 發往 MySQL proxy,可能此次由 slave-2 響應,下次由 slave-3 響應,這樣的話,就沒法利用查詢緩存了。

應該找一個共享式的緩存,好比 memcache 來解決。將 slave-2,slave-3,...這些查詢的結果都緩存至 mamcache 中。

問題 7:隨着應用的日益增加,讀操做不少,咱們能夠擴展 slave,可是若是 master 知足不了寫操做了,怎麼辦呢?

scale on ?更好的服務器? 沒有最好的,只有更好的,太貴了。。。

scale out ? 主從複製架構已經知足不了。

能夠分庫【垂直拆分】,分表【水平拆分】。

9.MySQL 都有什麼鎖,死鎖斷定原理和具體場景,死鎖怎麼解決?

MySQL 都有什麼鎖

MySQL 有三種鎖的級別:頁級、表級、行級

  • 表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的機率最高,併發度最低。
  • 行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的機率最低,併發度也最高。
  • 頁面鎖:開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度通常

什麼狀況下會形成死鎖

  • 所謂死鎖: 是指兩個或兩個以上的進程在執行過程當中。
  • 因爭奪資源而形成的一種互相等待的現象,若無外力做用,它們都將沒法推動下去。
  • 此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等竺的進程稱爲死鎖進程。
  • 表級鎖不會產生死鎖.因此解決死鎖主要仍是針對於最經常使用的 InnoDB。

死鎖的關鍵在於:兩個(或以上)的 Session 加鎖的順序不一致。

那麼對應的解決死鎖問題的關鍵就是:讓不一樣的 session加鎖有次序

死鎖的解決辦法

  • 查出的線程殺死 kill
SELECT trx_MySQL_thread_id FROM information_schema.INNODB_TRX;
複製代碼
  • 設置鎖的超時時間

Innodb 行鎖的等待時間,單位秒。可在會話級別設置,RDS 實例該參數的默認值爲 50(秒)。

生產環境不推薦使用過大的 innodb_lock_wait_timeout參數值

該參數支持在會話級別修改,方便應用在會話級別單獨設置某些特殊操做的行鎖等待超時時間,以下:

set innodb_lock_wait_timeout=1000; —設置當前會話 Innodb 行鎖等待超時時間,單位秒。複製代碼

10.MySQL 高併發環境解決方案?

MySQL 高併發環境解決方案 分庫 分表 分佈式 增長二級緩存。。。。。

需求分析:互聯網單位 天天大量數據讀取,寫入,併發性高。

  • 現有解決方式:水平分庫分表,由單點分佈到多點數據庫中,從而下降單點數據庫壓力。
  • 集羣方案:解決 DB 宕機帶來的單點 DB 不能訪問問題。
  • 讀寫分離策略:極大限度提升了應用中 Read 數據的速度和併發量。沒法解決高寫入壓力。

Spring全家桶

1.Spring IoC、AOP 原理

1.1.定義

1.1.1.IoC

Inversion of Control,控制反轉。是面向對象編程中的一種設計原則,能夠用來減低計算機代碼之間的耦合度。其中最多見的方式叫作依賴注入(DependencyInjection,簡稱 DI),這也是 Spring 的實現方式。經過控制反轉,對象在被建立的時候,由一個調控系統內全部對象的外界實體將其所依賴的對象的引用傳遞給它。也能夠說,依賴被注入到對象中。 

1.1.2.AOP

Aspect Oriented Programming,面向切面編程。經過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。AOP 是 OOP 的延續,是軟件開發中的一個熱點,也是 Spring框架中的一個重要內容,是函數式編程的一種衍生範型。利用 AOP 能夠對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度下降,提升程序的可重用性,同時提升了開發的效率。其中,最經常使用的使用場景通常有日誌模塊、權限模塊、事物模塊。

1.2.原理

1.2.1.IoC

IoC 內部核心原理就是反射技術,固然這裏面還涉及到 Bean 對象的初始化構建等步驟,這個在後面的生命週期中講,這裏咱們須要瞭解 Java 中反射是如何作的就好。這裏主要說明下主要的相關類和可能面試問題轉向,具體的 API 實現須要本身去看。 

還有其餘的類不一一列舉出來,都在 java.lang.reflect 包下。說到這個模塊的時候,那麼面試官可能會考察相關的知識,主要是考察你是否真的有去了解過反射的使用。舉兩個例子: 

利用反射獲取實例的私有屬性值怎麼作

這裏其實就是裏面的重要考察點就是反射對私有屬性的處理。

/**
 * 經過反射獲取私有的成員變量.
 */
private Object getPrivateValue(Person person, String fieldName)
{
    try
    {
        Field field = person.getClass().getDeclaredField(fieldName);
        // 主要就是這裏,須要將屬性的 accessible 設置爲 true 
        field.setAccessible(true);
        return field.get(person);
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
    return null;
}複製代碼

如何經過反射構建對象實例?

使用默認構造函數(無參)建立的話: 

Class.newInstance() Constroctor constroctor = clazz.getConstructor(String.class,Integer.class); Object obj = constroctor.newInstance("name", 18);
複製代碼

1.2.2.AOP

AOP 的內部原理其實就是動態代理和反射了。主要涉及到的反射類: 


動態代理相關原理的話,你須要瞭解什麼是代理模式、靜態代理的不足、動態代理的實現原理。 Spring 中實現動態代理有兩種方式可選,這兩種動態代理的實現方式的一個對比也
是面試中常問的。 

JDK 動態代理 

必須實現 InvocationHandler 接口,而後經過 Proxy.newProxyInstance(ClassLoader
loader, Class<?>[] interfaces, InvocationHandler h) 得到動態代理對象。
CGLIB 動態代理

使用 CGLIB 動態代理,被代理類不須要強制實現接口。CGLIB 不能對聲明爲 final的方法進行代理,由於 CGLIB 原理是動態生成被代理類的子類。

OK,AOP 講了。其實講到這裏,可能會有一個延伸的面試問題。咱們知道,Spring事物也是 通 過 AOP 來 實 現的 , 咱們使用的時候 一 般就是在方法上 加@Tranactional 註解,那麼你有沒有遇到過事物不生效的狀況呢?這是爲何?這個問題咱們在後面的面試題中會講。 

2.Spring Bean 生命週期 


這只是個大致流程,內部的具體行爲太多,須要自行去看看代碼。 

3.Spring Bean 注入是如何解決循環依賴問題的 

3.1. 什麼是循環依賴,有啥問題? 

循環依賴就是 N 個類中循環嵌套引用,這樣會致使內存溢出。循環依賴主要分兩種:

  • 構造器循環依賴
  • setter 循環依賴
3.2. Spring 解決循環依賴問題 
  • 構造器循環依賴問題 
無解,直接拋出 BeanCurrentlyInCreatingException 異常。
  • setter 循環依賴問題 
單例模式下,經過「三級緩存」來處理。非單例模式的話,問題無解。 

Spring 初始化單例對象大致是分爲以下三個步驟的:

  • createBeanInstance:調用構造函數建立對象
  • populateBean:調用類的 setter 方法填充對象屬性
  • initializeBean:調用定義的 Bean 初始化 init 方法
能夠看出,循環依賴主要發生在 一、2 步,固然若是發生在第一步的話,Spring 也是沒法解決該問題的。那麼就剩下第二步 populateBean 中出現的循環依賴問題。經過「三級緩存」來處理,三級緩存以下:

  • singletonObjects:Cache of singleton objects: bean name --> bean instance,完成初始化的單例對象的 cache(一級緩存)
  • earlySingletonObjects:Cache of early singleton objects: bean name--> bean instance ,完成實例化可是還沒有初始化的,提早暴光的單例對象的 cache (二級緩存)
  • singletonFactories : Cache of singleton factories: bean name -->ObjectFactory,進入實例化階段的單例對象工廠的 cache (三級緩存) 

咱們看下獲取單例對象的方法:

protected Object getSingleton(String beanName, boolean allowEarlyReference)
{
    Object singletonObject = this.singletonObjects.get(beanName);
    // isSingletonCurrentlyInCreation:判斷當前單例 bean 是否正在建立中 
    if(singletonObject == null && isSingletonCurrentlyInCreation(beanName))
    {
        synchronized(this.singletonObjects)
        {
            singletonObject = this.earlySingletonObjects.get(beanName);
            // allowEarlyReference:是否容許從 singletonFactories 中經過 getObject 拿到 
            對象
            if(singletonObject == null && allowEarlyReference)
            {
                ObjectFactory <? > singletonFactory = this.singletonFactories.get(beanName);
                if(singletonFactory != null)
                {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return(singletonObject != NULL_OBJECT ? singletonObject : null);
}
複製代碼

其中解決循環依賴問題的關鍵點就在 singletonFactory.getObject() 這一步,getObject 這是 ObjectFactory<T> 接口的方法。Spring 經過對該方法的實現,在createBeanInstance 以後,populateBean 以前,經過將建立好但還沒完成屬性設置和初始化的對象提早曝光,而後再獲取 Bean 的時候去看是否有提早曝光的對象實例來判斷是否要走建立流程。

protected void addSingletonFactory(String beanName, ObjectFactory <? > singletonFactory) {
    Assert.notNull(singletonFactory, "Singleton factory must not be null");
    synchronized(this.singletonObjects)
    {
        if(!this.singletonObjects.containsKey(beanName))
        {
            this.singletonFactories.put(beanName, singletonFactory);
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }
    }
}複製代碼

4.Spring 事務爲什麼失效了

可能的緣由:

  1. MySQL 使用的是 MyISAM 引擎,而 MyISAM 是不支持事務的。須要支持使用可使用 InnoDB 引擎
  2. 若是使用了 Spring MVC ,context:component-scan 重複掃描問題可能會引發事務失敗
  3. @Transactional 註解開啓配置放到 DispatcherServlet 的配置裏了。
  4. @Transactional 註解只能應用到 public 可見度的方法上。 在其餘可見類型上聲明,事務會失效。
  5. 在接口上使用 @Transactional 註解,只能當你設置了基於接口的代理時它才生效。因此若是強制使用了 CGLIB,那麼事物會實效。
  6. @Transactional 同一個類中無事務方法 a() 內部調用有事務方法 b(),那麼此時事物不生效。 
按 理 說 , 如 果 按 照 Spring 說 的 事 物 傳 播 級 別 去 配 置 其 事 物 級 別 爲REQUIRES_NEW 的話,那麼應該是在調用 b() 的時候會新生成一個事物。實際上卻沒有。



NOT_SUPPORTED 老是非事務地執行,並掛起任何存在的事務其實,這是因爲 Spring 的事物實現是經過 AOP 來實現的。此時,當這個有註解的方法 b() 被調用的時候,其實是由代理類來調用的,代理類在調用以前就會啓動 transaction。然而,若是這個有註解的方法是被同一個類中的其餘方法 a() 調用的,那麼該方法的調用並無經過代理類,而是直接經過原來的那個 bean,因此就不會啓動 transaction,咱們看到的現象就是 @Transactional 註解無效。 

5.怎樣用註解的方式配置 Spring?

Spring 在 2.5 版本之後開始支持用註解的方式來配置依賴注入。能夠用註解的方式來替代XML 方式的 bean 描述,能夠將 bean 描述轉移到組件類的內部,只須要在相關類上、方法上或者字段聲明上使用註解便可。註解注入將會被容器在 XML 注入以前被處理,因此後者會覆蓋掉前者對於同一個屬性的處理結果。註解裝配在 Spring 中是默認關閉的。因此須要在 Spring 文件中配置一下才能使用基於註解的裝配模式。若是你想要在你的應用程序中使用關於註解的方法的話,請參考以下的配置。 

<beans>
    <context:annotation-config/>
    <!-- bean definitions go here -->
</beans>複製代碼

在標籤配置完成之後,就能夠用註解的方式在 Spring 中向屬性、方法和構造方法中自動裝配變量。

下面是幾種比較重要的註解類型:

  • @Required:該註解應用於設值方法。
  • @Autowired:該註解應用於有值設值方法、非設值方法、構造方法和變量。
  • @Qualifier:該註解和@Autowired 註解搭配使用,用於消除特定 bean 自動裝配的歧義。
  • JSR-250 Annotations:Spring 支持基於 JSR-250 註解的如下註解,@Resource、@PostConstruct 和@PreDestroy。 

六、SpringMVC 的流程? 

  1. 用戶發送請求至前端控制器 DispatcherServlet;
  2. DispatcherServlet 收到請求後,調用 HandlerMapping 處理器映射器,請求獲取Handle
  3. 處理器映射器根據請求 url 找到具體的處理器,生成處理器對象及處理器攔截器(若是有則生成)一併返回給 DispatcherServlet;
  4. DispatcherServlet 調用 HandlerAdapter 處理器適配器;
  5. HandlerAdapter 通過適配調用 具體處理器(Handler,也叫後端控制器);
  6. Handler 執行完成返回 ModelAndView;
  7. HandlerAdapter 將 Handler 執 行 結 果 ModelAndView 返 回 給DispatcherServlet ; 
  8. DispatcherServlet 將 ModelAndView 傳 給ViewResolver 視圖解析器進行解析;
  9. ViewResolver 解析後返回具體View;
  10. DispatcherServlet 對 View 進行渲染視圖(即將模型數據填充至視圖中)
  11. DispatcherServlet 響應用戶。


七、Springmvc 的優勢:

  1. 能夠支持各類視圖技術,而不只僅侷限於 JSP;
  2. 與 Spring 框架集成(如 IoC 容器、AOP 等);
  3. 清 晰 的 角 色 分 配 : 前 端 控 制 器 (dispatcherServlet) , 請 求 處處理器映射(handlerMapping), 處理器適配器(HandlerAdapter), 視圖解析器(ViewResolver)。
  4. 支持各類請求資源的映射策略。 

8. Spring 通知類型使用場景分別有哪些?

  

9.IoC 控制反轉設計原理?

具體設計原理以下圖:


10.Spring 如何處理線程併發問題?

Spring 使用 ThreadLocal 解決線程安全問題。咱們知道在通常狀況下,只有無狀態的 Bean 才能夠在多線程環境下共享,在Spring 中,絕大部分 Bean 均可以聲明爲 singleton 做用域。就是由於Spring 對 一 些 Bean ( 如 RequestContextHolder 、
TransactionSynchronizationManager、LocaleContextHolder 等)中非線程安全狀態採用 ThreadLocal 進行處理,讓它們也成爲線程安全的狀態,由於有狀態的 Bean 就能夠在多線程中共享了。

ThreadLocal 和線程同步機制都是爲了解決多線程中相同變量的訪問衝突問題。在同步機制中,經過對象的鎖機制保證同一時間只有一個線程訪問變量。這時該變量是多個線程共享的,使用同步機制要求程序慎密地分析何時對變量進行讀寫,何時須要鎖定某個對象,何時釋放對象鎖等繁雜的問題,程序設計和編寫難度相對較大。而 ThreadLocal 則從另外一個角度來解決多線程的併發訪問。 ThreadLocal 會爲每個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問衝突。由於每個線程都擁有本身的變量副本,從而也就沒有必要對該變量進行同步了。 ThreadLocal 提供了線程安全的共享對象,在編寫多線程代碼時,能夠把不安全的變量封裝進 ThreadLocal。

因爲 ThreadLocal 中能夠持有任何類型的對象,低版本 JDK 所提供的 get()返回的是 Object 對象,須要強制類型轉換。但 JDK 5.0 經過泛型很好的解決了這個問題,在必定程度地簡化 ThreadLocal 的使用。歸納起來講,對於多線程資源共享的問題,同步機制採用了「以時間換空間」的方式,而 ThreadLocal採用了「以空間換時間」的方式。前者僅提供一份變量,讓不一樣的線程排隊訪問,然後者爲每個線程都提供了一份變量,所以能夠同時訪問而互不影響。 

最後

歡迎你們關注個人公種浩【以Java架構贏天下】,整理了960道2019年多家公司java面試題400多頁pdf文檔,還有一份本身平時學習整理的Java學習筆記,共500多頁,文章都會在裏面更新,整理的資料也會放在裏面。喜歡文章記得關注我點個贊喲,感謝支持!


個人Java學習筆記(知識點+面試整理)

相關文章
相關標籤/搜索