最多見 200+ 面試題答案全解析-面試必備

本文分爲十九個模塊,分別是: css

Java 基礎、容器、多線程、反射、對象拷貝、Java Web 、異常、網絡、設計模式、Spring/Spring MVC、Spring Boot/Spring Cloud、Hibernate、MyBatis、RabbitMQ、Kafka、Zookeeper、MySQL、Redis、JVM html

以下圖所示:java

模塊圖

Java 基礎

1. JDK 和 JRE 有什麼區別?

  • JDK:Java Development Kit 的簡稱,Java 開發工具包,提供了 Java 的開發環境和運行環境。
  • JRE:Java Runtime Environment 的簡稱,Java 運行環境,爲 Java 的運行提供了所需環境。

具體來講 JDK 其實包含了 JRE,同時還包含了編譯 Java 源碼的編譯器 Javac,還包含了不少 Java 程序調試和分析的工具。簡單來講:若是你須要運行 Java 程序,只需安裝 JRE 就能夠了,若是你須要編寫 Java 程序,須要安裝 JDK。node

2. == 和 equals 的區別是什麼?

== 解讀mysql

對於基本類型和引用類型 == 的做用效果是不一樣的,以下所示:nginx

  • 基本類型:比較的是值是否相同;
  • 引用類型:比較的是引用是否相同;

代碼示例:web

String x = "string"; String y = "string"; String z = new String("string"); System.out.println(x==y); // true System.out.println(x==z); // false System.out.println(x.equals(y)); // true System.out.println(x.equals(z)); // true 

代碼解讀:由於 x 和 y 指向的是同一個引用,因此 == 也是 true,而 new String()方法則重寫開闢了內存空間,因此 == 結果爲 false,而 equals 比較的一直是值,因此結果都爲 true。ajax

equals 解讀正則表達式

equals 本質上就是 ==,只不過 String 和 Integer 等重寫了 equals 方法,把它變成了值比較。看下面的代碼就明白了。redis

首先來看默認狀況下 equals 比較一個有相同值的對象,代碼以下:

class Cat { public Cat(String name) { this.name = name; } private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } Cat c1 = new Cat("王磊"); Cat c2 = new Cat("王磊"); System.out.println(c1.equals(c2)); // false 

輸出結果出乎咱們的意料,居然是 false?這是怎麼回事,看了 equals 源碼就知道了,源碼以下:

public boolean equals(Object obj) { return (this == obj); } 

原來 equals 本質上就是 ==。

那問題來了,兩個相同值的 String 對象,爲何返回的是 true?代碼以下:

String s1 = new String("老王"); String s2 = new String("老王"); System.out.println(s1.equals(s2)); // true 

一樣的,當咱們進入 String 的 equals 方法,找到了答案,代碼以下:

public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; } 

原來是 String 重寫了 Object 的 equals 方法,把引用比較改爲了值比較。

總結 :== 對於基本類型來講是值比較,對於引用類型來講是比較的是引用;而 equals 默認狀況下是引用比較,只是不少類從新了 equals 方法,好比 String、Integer 等把它變成了值比較,因此通常狀況下 equals 比較的是值是否相等。

3. 兩個對象的 hashCode() 相同,則 equals() 也必定爲 true,對嗎?

不對,兩個對象的 hashCode() 相同,equals() 不必定 true。

代碼示例:

String str1 = "通話"; String str2 = "重地"; System. out. println(String. format("str1:%d | str2:%d", str1. hashCode(),str2. hashCode())); System. out. println(str1. equals(str2)); 

執行的結果:

str1:1179395 | str2:1179395

false 

代碼解讀:很顯然「通話」和「重地」的 hashCode() 相同,然而 equals() 則爲 false,由於在散列表中,hashCode() 相等即兩個鍵值對的哈希值相等,然而哈希值相等,並不必定能得出鍵值對相等。

4. final 在 Java 中有什麼做用?

  • final 修飾的類叫最終類,該類不能被繼承。
  • final 修飾的方法不能被重寫。
  • final 修飾的變量叫常量,常量必須初始化,初始化以後值就不能被修改。

5. Java 中的 Math. round(-1. 5) 等於多少?

等於 -1,由於在數軸上取值時,中間值(0.5)向右取整,因此正 0.5 是往上取整,負 0.5 是直接捨棄。

6. String 屬於基礎的數據類型嗎?

String 不屬於基礎類型,基礎類型有 8 種:byte、boolean、char、short、int、float、long、double,而 String 屬於對象。

7. Java 中操做字符串都有哪些類?它們之間有什麼區別?

操做字符串的類有:String、StringBuffer、StringBuilder。

String 和 StringBuffer、StringBuilder 的區別在於 String 聲明的是不可變的對象,每次操做都會生成新的 String 對象,而後將指針指向新的 String 對象,而 StringBuffer、StringBuilder 能夠在原有對象的基礎上進行操做,因此在常常改變字符串內容的狀況下最好不要使用 String。

StringBuffer 和 StringBuilder 最大的區別在於,StringBuffer 是線程安全的,而 StringBuilder 是非線程安全的,但 StringBuilder 的性能卻高於 StringBuffer,因此在單線程環境下推薦使用 StringBuilder,多線程環境下推薦使用 StringBuffer。

8. String str="i"與 String str=new String("i")同樣嗎?

不同,由於內存的分配方式不同。String str="i"的方式,Java 虛擬機會將其分配到常量池中;而 String str=new String("i") 則會被分到堆內存中。

9. 如何將字符串反轉?

使用 StringBuilder 或者 stringBuffer 的 reverse() 方法。

示例代碼:

// StringBuffer reverse StringBuffer stringBuffer = new StringBuffer(); stringBuffer. append("abcdefg"); System. out. println(stringBuffer. reverse()); // gfedcba // StringBuilder reverse StringBuilder stringBuilder = new StringBuilder(); stringBuilder. append("abcdefg"); System. out. println(stringBuilder. reverse()); // gfedcba 

10. String 類的經常使用方法都有那些?

  • indexOf():返回指定字符的索引。
  • charAt():返回指定索引處的字符。
  • replace():字符串替換。
  • trim():去除字符串兩端空白。
  • split():分割字符串,返回一個分割後的字符串數組。
  • getBytes():返回字符串的 byte 類型數組。
  • length():返回字符串長度。
  • toLowerCase():將字符串轉成小寫字母。
  • toUpperCase():將字符串轉成大寫字符。
  • substring():截取字符串。
  • equals():字符串比較。

11. 抽象類必需要有抽象方法嗎?

不須要,抽象類不必定非要有抽象方法。

示例代碼:

abstract class Cat { public static void sayHi() { System. out. println("hi~"); } } 

上面代碼,抽象類並無抽象方法但徹底能夠正常運行。

12. 普通類和抽象類有哪些區別?

  • 普通類不能包含抽象方法,抽象類能夠包含抽象方法。
  • 抽象類不能直接實例化,普通類能夠直接實例化。

13. 抽象類能使用 final 修飾嗎?

不能,定義抽象類就是讓其餘類繼承的,若是定義爲 final 該類就不能被繼承,這樣彼此就會產生矛盾,因此 final 不能修飾抽象類,以下圖所示,編輯器也會提示錯誤信息:

編譯器保存圖

14. 接口和抽象類有什麼區別?

  • 實現:抽象類的子類使用 extends 來繼承;接口必須使用 implements 來實現接口。
  • 構造函數:抽象類能夠有構造函數;接口不能有。
  • 實現數量:類能夠實現不少個接口;可是隻能繼承一個抽象類。
  • 訪問修飾符:接口中的方法默認使用 public 修飾;抽象類中的方法能夠是任意訪問修飾符。

15. Java 中 IO 流分爲幾種?

按功能來分:輸入流(input)、輸出流(output)。

按類型來分:字節流和字符流。

字節流和字符流的區別是:字節流按 8 位傳輸以字節爲單位輸入輸出數據,字符流按 16 位傳輸以字符爲單位輸入輸出數據。

16. BIO、NIO、AIO 有什麼區別?

  • BIO:Block IO 同步阻塞式 IO,就是咱們日常使用的傳統 IO,它的特色是模式簡單使用方便,併發處理能力低。
  • NIO:Non IO 同步非阻塞 IO,是傳統 IO 的升級,客戶端和服務器端經過 Channel(通道)通信,實現了多路複用。
  • AIO:Asynchronous IO 是 NIO 的升級,也叫 NIO2,實現了異步非堵塞 IO ,異步 IO 的操做基於事件和回調機制。

17. Files的經常使用方法都有哪些?

  • Files. exists():檢測文件路徑是否存在。
  • Files. createFile():建立文件。
  • Files. createDirectory():建立文件夾。
  • Files. delete():刪除一個文件或目錄。
  • Files. copy():複製文件。
  • Files. move():移動文件。
  • Files. size():查看文件個數。
  • Files. read():讀取文件。
  • Files. write():寫入文件。

容器

18. Java 容器都有哪些?

Java 容器分爲 Collection 和 Map 兩大類,其下又有不少子類,以下所示:

  • Collection
  • List
    • ArrayList
    • LinkedList
    • Vector
    • Stack
  • Set
    • HashSet
    • LinkedHashSet
    • TreeSet
  • Map
  • HashMap
    • LinkedHashMap
  • TreeMap
  • ConcurrentHashMap
  • Hashtable

19. Collection 和 Collections 有什麼區別?

  • Collection 是一個集合接口,它提供了對集合對象進行基本操做的通用接口方法,全部集合都是它的子類,好比 List、Set 等。
  • Collections 是一個包裝類,包含了不少靜態方法,不能被實例化,就像一個工具類,好比提供的排序方法: Collections. sort(list)。

20. List、Set、Map 之間的區別是什麼?

List、Set、Map 的區別主要體如今兩個方面:元素是否有序、是否容許元素重複。

三者之間的區別,以下表:

區別圖

21. HashMap 和 Hashtable 有什麼區別?

  • 存儲:HashMap 運行 key 和 value 爲 null,而 Hashtable 不容許。
  • 線程安全:Hashtable 是線程安全的,而 HashMap 是非線程安全的。
  • 推薦使用:在 Hashtable 的類註釋能夠看到,Hashtable 是保留類不建議使用,推薦在單線程環境下使用 HashMap 替代,若是須要多線程使用則用 ConcurrentHashMap 替代。

22. 如何決定使用 HashMap 仍是 TreeMap?

對於在 Map 中插入、刪除、定位一個元素這類操做,HashMap 是最好的選擇,由於相對而言 HashMap 的插入會更快,但若是你要對一個 key 集合進行有序的遍歷,那 TreeMap 是更好的選擇。

23. 說一下 HashMap 的實現原理?

HashMap 基於 Hash 算法實現的,咱們經過 put(key,value)存儲,get(key)來獲取。當傳入 key 時,HashMap 會根據 key. hashCode() 計算出 hash 值,根據 hash 值將 value 保存在 bucket 裏。當計算出的 hash 值相同時,咱們稱之爲 hash 衝突,HashMap 的作法是用鏈表和紅黑樹存儲相同 hash 值的 value。當 hash 衝突的個數比較少時,使用鏈表不然使用紅黑樹。

24. 說一下 HashSet 的實現原理?

HashSet 是基於 HashMap 實現的,HashSet 底層使用 HashMap 來保存全部元素,所以 HashSet 的實現比較簡單,相關 HashSet 的操做,基本上都是直接調用底層 HashMap 的相關方法來完成,HashSet 不容許重複的值。

25. ArrayList 和 LinkedList 的區別是什麼?

  • 數據結構實現:ArrayList 是動態數組的數據結構實現,而 LinkedList 是雙向鏈表的數據結構實現。
  • 隨機訪問效率:ArrayList 比 LinkedList 在隨機訪問的時候效率要高,由於 LinkedList 是線性的數據存儲方式,因此須要移動指針從前日後依次查找。
  • 增長和刪除效率:在非首尾的增長和刪除操做,LinkedList 要比 ArrayList 效率要高,由於 ArrayList 增刪操做要影響數組內的其餘數據的下標。

綜合來講,在須要頻繁讀取集合中的元素時,更推薦使用 ArrayList,而在插入和刪除操做較多時,更推薦使用 LinkedList。

26. 如何實現數組和 List 之間的轉換?

  • 數組轉 List:使用 Arrays. asList(array) 進行轉換。
  • List 轉數組:使用 List 自帶的 toArray() 方法。

代碼示例:

// list to array List<String> list = new ArrayList<String>(); list. add("王磊"); list. add("的博客"); list. toArray(); // array to list String[] array = new String[]{"王磊","的博客"}; Arrays. asList(array); 

27. ArrayList 和 Vector 的區別是什麼?

  • 線程安全:Vector 使用了 Synchronized 來實現線程同步,是線程安全的,而 ArrayList 是非線程安全的。
  • 性能:ArrayList 在性能方面要優於 Vector。
  • 擴容:ArrayList 和 Vector 都會根據實際的須要動態的調整容量,只不過在 Vector 擴容每次會增長 1 倍,而 ArrayList 只會增長 50%。

28. Array 和 ArrayList 有何區別?

  • Array 能夠存儲基本數據類型和對象,ArrayList 只能存儲對象。
  • Array 是指定固定大小的,而 ArrayList 大小是自動擴展的。
  • Array 內置方法沒有 ArrayList 多,好比 addAll、removeAll、iteration 等方法只有 ArrayList 有。

29. 在 Queue 中 poll()和 remove()有什麼區別?

  • 相同點:都是返回第一個元素,並在隊列中刪除返回的對象。
  • 不一樣點:若是沒有元素 poll()會返回 null,而 remove()會直接拋出 NoSuchElementException 異常。

代碼示例:

Queue<String> queue = new LinkedList<String>(); queue. offer("string"); // add System. out. println(queue. poll()); System. out. println(queue. remove()); System. out. println(queue. size()); 

30. 哪些集合類是線程安全的?

Vector、Hashtable、Stack 都是線程安全的,而像 HashMap 則是非線程安全的,不過在 JDK 1.5 以後隨着 Java. util. concurrent 併發包的出現,它們也有了本身對應的線程安全類,好比 HashMap 對應的線程安全類就是 ConcurrentHashMap。

31. 迭代器 Iterator 是什麼?

Iterator 接口提供遍歷任何 Collection 的接口。咱們能夠從一個 Collection 中使用迭代器方法來獲取迭代器實例。迭代器取代了 Java 集合框架中的 Enumeration,迭代器容許調用者在迭代過程當中移除元素。

32. Iterator 怎麼使用?有什麼特色?

Iterator 使用代碼以下:

List<String> list = new ArrayList<>(); Iterator<String> it = list. iterator(); while(it. hasNext()){ String obj = it. next(); System. out. println(obj); } 

Iterator 的特色是更加安全,由於它能夠確保,在當前遍歷的集合元素被更改的時候,就會拋出 ConcurrentModificationException 異常。

33. Iterator 和 ListIterator 有什麼區別?

  • Iterator 能夠遍歷 Set 和 List 集合,而 ListIterator 只能遍歷 List。
  • Iterator 只能單向遍歷,而 ListIterator 能夠雙向遍歷(向前/後遍歷)。
  • ListIterator 從 Iterator 接口繼承,而後添加了一些額外的功能,好比添加一個元素、替換一個元素、獲取前面或後面元素的索引位置。

34. 怎麼確保一個集合不能被修改?

可使用 Collections. unmodifiableCollection(Collection c) 方法來建立一個只讀集合,這樣改變集合的任何操做都會拋出 Java. lang. UnsupportedOperationException 異常。

示例代碼以下:

List<String> list = new ArrayList<>(); list. add("x"); Collection<String> clist = Collections. unmodifiableCollection(list); clist. add("y"); // 運行時此行報錯 System. out. println(list. size()); 

多線程

35. 並行和併發有什麼區別?

  • 並行:多個處理器或多核處理器同時處理多個任務。
  • 併發:多個任務在同一個 CPU 核上,按細分的時間片輪流(交替)執行,從邏輯上來看那些任務是同時執行。

以下圖:

併發和並行

併發 = 兩個隊列和一臺咖啡機。

並行 = 兩個隊列和兩臺咖啡機。

36. 線程和進程的區別?

一個程序下至少有一個進程,一個進程下至少有一個線程,一個進程下也能夠有多個線程來增長程序的執行速度。

37. 守護線程是什麼?

守護線程是運行在後臺的一種特殊進程。它獨立於控制終端而且週期性地執行某種任務或等待處理某些發生的事件。在 Java 中垃圾回收線程就是特殊的守護線程。

38. 建立線程有哪幾種方式?

建立線程有三種方式:

  • 繼承 Thread 重寫 run 方法;
  • 實現 Runnable 接口;
  • 實現 Callable 接口。

39. 說一下 runnable 和 callable 有什麼區別?

runnable 沒有返回值,callable 能夠拿到有返回值,callable 能夠看做是 runnable 的補充。

40. 線程有哪些狀態?

線程的狀態:

  • NEW 還沒有啓動
  • RUNNABLE 正在執行中
  • BLOCKED 阻塞的(被同步鎖或者IO鎖阻塞)
  • WAITING 永久等待狀態
  • TIMED_WAITING 等待指定的時間從新被喚醒的狀態
  • TERMINATED 執行完成

41. sleep() 和 wait() 有什麼區別?

  • 類的不一樣:sleep() 來自 Thread,wait() 來自 Object。
  • 釋放鎖:sleep() 不釋放鎖;wait() 釋放鎖。
  • 用法不一樣:sleep() 時間到會自動恢復;wait() 可使用 notify()/notifyAll()直接喚醒。

42. notify()和 notifyAll()有什麼區別?

notifyAll()會喚醒全部的線程,notify()以後喚醒一個線程。notifyAll() 調用後,會將所有線程由等待池移到鎖池,而後參與鎖的競爭,競爭成功則繼續執行,若是不成功則留在鎖池等待鎖被釋放後再次參與競爭。而 notify()只會喚醒一個線程,具體喚醒哪個線程由虛擬機控制。

43. 線程的 run() 和 start() 有什麼區別?

start() 方法用於啓動線程,run() 方法用於執行線程的運行時代碼。run() 能夠重複調用,而 start() 只能調用一次。

44. 建立線程池有哪幾種方式?

線程池建立有七種方式,最核心的是最後一種:

  • newSingleThreadExecutor():它的特色在於工做線程數目被限制爲 1,操做一個無界的工做隊列,因此它保證了全部任務的都是被順序執行,最多會有一個任務處於活動狀態,而且不容許使用者改動線程池實例,所以能夠避免其改變線程數目;

  • newCachedThreadPool():它是一種用來處理大量短期工做任務的線程池,具備幾個鮮明特色:它會試圖緩存線程並重用,當無緩存線程可用時,就會建立新的工做線程;若是線程閒置的時間超過 60 秒,則被終止並移出緩存;長時間閒置時,這種線程池,不會消耗什麼資源。其內部使用 SynchronousQueue 做爲工做隊列;

  • newFixedThreadPool(int nThreads):重用指定數目(nThreads)的線程,其背後使用的是無界的工做隊列,任什麼時候候最多有 nThreads 個工做線程是活動的。這意味着,若是任務數量超過了活動隊列數目,將在工做隊列中等待空閒線程出現;若是有工做線程退出,將會有新的工做線程被建立,以補足指定的數目 nThreads;

  • newSingleThreadScheduledExecutor():建立單線程池,返回 ScheduledExecutorService,能夠進行定時或週期性的工做調度;

  • newScheduledThreadPool(int corePoolSize):和newSingleThreadScheduledExecutor()相似,建立的是個 ScheduledExecutorService,能夠進行定時或週期性的工做調度,區別在於單一工做線程仍是多個工做線程;

  • newWorkStealingPool(int parallelism):這是一個常常被人忽略的線程池,Java 8 才加入這個建立方法,其內部會構建ForkJoinPool,利用Work-Stealing算法,並行地處理任務,不保證處理順序;

  • ThreadPoolExecutor():是最原始的線程池建立,上面1-3建立方式都是對ThreadPoolExecutor的封裝。

45. 線程池都有哪些狀態?

  • RUNNING:這是最正常的狀態,接受新的任務,處理等待隊列中的任務。
  • SHUTDOWN:不接受新的任務提交,可是會繼續處理等待隊列中的任務。
  • STOP:不接受新的任務提交,再也不處理等待隊列中的任務,中斷正在執行任務的線程。
  • TIDYING:全部的任務都銷燬了,workCount 爲 0,線程池的狀態在轉換爲 TIDYING 狀態時,會執行鉤子方法 terminated()。
  • TERMINATED:terminated()方法結束後,線程池的狀態就會變成這個。

46. 線程池中 submit() 和 execute() 方法有什麼區別?

  • execute():只能執行 Runnable 類型的任務。
  • submit():能夠執行 Runnable 和 Callable 類型的任務。

Callable 類型的任務能夠獲取執行的返回值,而 Runnable 執行無返回值。

47. 在 Java 程序中怎麼保證多線程的運行安全?

  • 方法一:使用安全類,好比 Java. util. concurrent 下的類。
  • 方法二:使用自動鎖 synchronized。
  • 方法三:使用手動鎖 Lock。

手動鎖 Java 示例代碼以下:

Lock lock = new ReentrantLock(); lock. lock(); try { System. out. println("得到鎖"); } catch (Exception e) { // TODO: handle exception } finally { System. out. println("釋放鎖"); lock. unlock(); } 

48. 多線程中 synchronized 鎖升級的原理是什麼?

synchronized 鎖升級原理:在鎖對象的對象頭裏面有一個 threadid 字段,在第一次訪問的時候 threadid 爲空,jvm 讓其持有偏向鎖,並將 threadid 設置爲其線程 id,再次進入的時候會先判斷 threadid 是否與其線程 id 一致,若是一致則能夠直接使用此對象,若是不一致,則升級偏向鎖爲輕量級鎖,經過自旋循環必定次數來獲取鎖,執行必定次數以後,若是尚未正常獲取到要使用的對象,此時就會把鎖從輕量級升級爲重量級鎖,此過程就構成了 synchronized 鎖的升級。

鎖的升級的目的:鎖升級是爲了減低了鎖帶來的性能消耗。在 Java 6 以後優化 synchronized 的實現方式,使用了偏向鎖升級爲輕量級鎖再升級到重量級鎖的方式,從而減低了鎖帶來的性能消耗。

49. 什麼是死鎖?

當線程 A 持有獨佔鎖a,並嘗試去獲取獨佔鎖 b 的同時,線程 B 持有獨佔鎖 b,並嘗試獲取獨佔鎖 a 的狀況下,就會發生 AB 兩個線程因爲互相持有對方須要的鎖,而發生的阻塞現象,咱們稱爲死鎖。

50. 怎麼防止死鎖?

  • 儘可能使用 tryLock(long timeout, TimeUnit unit)的方法(ReentrantLock、ReentrantReadWriteLock),設置超時時間,超時能夠退出防止死鎖。
  • 儘可能使用 Java. util. concurrent 併發類代替本身手寫鎖。
  • 儘可能下降鎖的使用粒度,儘可能不要幾個功能用同一把鎖。
  • 儘可能減小同步的代碼塊。

51. ThreadLocal 是什麼?有哪些使用場景?

ThreadLocal 爲每一個使用該變量的線程提供獨立的變量副本,因此每個線程均可以獨立地改變本身的副本,而不會影響其它線程所對應的副本。

ThreadLocal 的經典使用場景是數據庫鏈接和 session 管理等。

52. 說一下 synchronized 底層實現原理?

synchronized 是由一對 monitorenter/monitorexit 指令實現的,monitor 對象是同步的基本實現單元。在 Java 6 以前,monitor 的實現徹底是依靠操做系統內部的互斥鎖,由於須要進行用戶態到內核態的切換,因此同步操做是一個無差異的重量級操做,性能也很低。但在 Java 6 的時候,Java 虛擬機 對此進行了大刀闊斧地改進,提供了三種不一樣的 monitor 實現,也就是常說的三種不一樣的鎖:偏向鎖(Biased Locking)、輕量級鎖和重量級鎖,大大改進了其性能。

53. synchronized 和 volatile 的區別是什麼?

  • volatile 是變量修飾符;synchronized 是修飾類、方法、代碼段。
  • volatile 僅能實現變量的修改可見性,不能保證原子性;而 synchronized 則能夠保證變量的修改可見性和原子性。
  • volatile 不會形成線程的阻塞;synchronized 可能會形成線程的阻塞。

54. synchronized 和 Lock 有什麼區別?

  • synchronized 能夠給類、方法、代碼塊加鎖;而 lock 只能給代碼塊加鎖。
  • synchronized 不須要手動獲取鎖和釋放鎖,使用簡單,發生異常會自動釋放鎖,不會形成死鎖;而 lock 須要本身加鎖和釋放鎖,若是使用不當沒有 unLock()去釋放鎖就會形成死鎖。
  • 經過 Lock 能夠知道有沒有成功獲取鎖,而 synchronized 卻沒法辦到。

55. synchronized 和 ReentrantLock 區別是什麼?

synchronized 早期的實現比較低效,對比 ReentrantLock,大多數場景性能都相差較大,可是在 Java 6 中對 synchronized 進行了很是多的改進。

主要區別以下:

  • ReentrantLock 使用起來比較靈活,可是必須有釋放鎖的配合動做;
  • ReentrantLock 必須手動獲取與釋放鎖,而 synchronized 不須要手動釋放和開啓鎖;
  • ReentrantLock 只適用於代碼塊鎖,而 synchronized 可用於修飾方法、代碼塊等。
  • volatile 標記的變量不會被編譯器優化;synchronized 標記的變量能夠被編譯器優化。

56. 說一下 atomic 的原理?

atomic 主要利用 CAS (Compare And Wwap) 和 volatile 和 native 方法來保證原子操做,從而避免 synchronized 的高開銷,執行效率大爲提高。

反射

57. 什麼是反射?

反射是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲 Java 語言的反射機制。

58. 什麼是 Java 序列化?什麼狀況下須要序列化?

Java 序列化是爲了保存各類對象在內存中的狀態,而且能夠把保存的對象狀態再讀出來。

如下狀況須要使用 Java 序列化:

  • 想把的內存中的對象狀態保存到一個文件中或者數據庫中時候;
  • 想用套接字在網絡上傳送對象的時候;
  • 想經過RMI(遠程方法調用)傳輸對象的時候。

59. 動態代理是什麼?有哪些應用?

動態代理是運行時動態生成代理類。

動態代理的應用有 spring aop、hibernate 數據查詢、測試框架的後端 mock、rpc,Java註解對象獲取等。

60. 怎麼實現動態代理?

JDK 原生動態代理和 cglib 動態代理。JDK 原生動態代理是基於接口實現的,而 cglib 是基於繼承當前類的子類實現的。

對象拷貝

61. 爲何要使用克隆?

克隆的對象可能包含一些已經修改過的屬性,而 new 出來的對象的屬性都仍是初始化時候的值,因此當須要一個新的對象來保存當前對象的「狀態」就靠克隆方法了。

62. 如何實現對象克隆?

  • 實現 Cloneable 接口並重寫 Object 類中的 clone() 方法。
  • 實現 Serializable 接口,經過對象的序列化和反序列化實現克隆,能夠實現真正的深度克隆。

63. 深拷貝和淺拷貝區別是什麼?

  • 淺克隆:當對象被複制時只複製它自己和其中包含的值類型的成員變量,而引用類型的成員對象並無複製。
  • 深克隆:除了對象自己被複制外,對象所包含的全部成員變量也將複製。

Java Web

64. JSP 和 servlet 有什麼區別?

JSP 是 servlet 技術的擴展,本質上就是 servlet 的簡易方式。servlet 和 JSP 最主要的不一樣點在於,servlet 的應用邏輯是在 Java 文件中,而且徹底從表示層中的 html 裏分離開來,而 JSP 的狀況是 Java 和 html 能夠組合成一個擴展名爲 JSP 的文件。JSP 側重於視圖,servlet 主要用於控制邏輯。

65. JSP 有哪些內置對象?做用分別是什麼?

JSP 有 9 大內置對象:

  • request:封裝客戶端的請求,其中包含來自 get 或 post 請求的參數;
  • response:封裝服務器對客戶端的響應;
  • pageContext:經過該對象能夠獲取其餘對象;
  • session:封裝用戶會話的對象;
  • application:封裝服務器運行環境的對象;
  • out:輸出服務器響應的輸出流對象;
  • config:Web 應用的配置對象;
  • page:JSP 頁面自己(至關於 Java 程序中的 this);
  • exception:封裝頁面拋出異常的對象。

66. 說一下 JSP 的 4 種做用域?

  • page:表明與一個頁面相關的對象和屬性。
  • request:表明與客戶端發出的一個請求相關的對象和屬性。一個請求可能跨越多個頁面,涉及多個 Web 組件;須要在頁面顯示的臨時數據能夠置於此做用域。
  • session:表明與某個用戶與服務器創建的一次會話相關的對象和屬性。跟某個用戶相關的數據應該放在用戶本身的 session 中。
  • application:表明與整個 Web 應用程序相關的對象和屬性,它實質上是跨越整個 Web 應用程序,包括多個頁面、請求和會話的一個全局做用域。

67. session 和 cookie 有什麼區別?

  • 存儲位置不一樣:session 存儲在服務器端;cookie 存儲在瀏覽器端。
  • 安全性不一樣:cookie 安全性通常,在瀏覽器存儲,能夠被僞造和修改。
  • 容量和個數限制:cookie 有容量限制,每一個站點下的 cookie 也有個數限制。
  • 存儲的多樣性:session 能夠存儲在 Redis 中、數據庫中、應用程序中;而 cookie 只能存儲在瀏覽器中。

68. 說一下 session 的工做原理?

session 的工做原理是客戶端登陸完成以後,服務器會建立對應的 session,session 建立完以後,會把 session 的 id 發送給客戶端,客戶端再存儲到瀏覽器中。這樣客戶端每次訪問服務器時,都會帶着 sessionid,服務器拿到 sessionid 以後,在內存找到與之對應的 session 這樣就能夠正常工做了。

69. 若是客戶端禁止 cookie 能實現 session 還能用嗎?

能夠用,session 只是依賴 cookie 存儲 sessionid,若是 cookie 被禁用了,可使用 url 中添加 sessionid 的方式保證 session 能正常使用。

70. spring mvc 和 struts 的區別是什麼?

  • 攔截級別:struts2 是類級別的攔截;spring mvc 是方法級別的攔截。
  • 數據獨立性:spring mvc 的方法之間基本上獨立的,獨享 request 和 response 數據,請求數據經過參數獲取,處理結果經過 ModelMap 交回給框架,方法之間不共享變量;而 struts2 雖然方法之間也是獨立的,但其全部 action 變量是共享的,這不會影響程序運行,卻給咱們編碼和讀程序時帶來了必定的麻煩。
  • 攔截機制:struts2 有以本身的 interceptor 機制,spring mvc 用的是獨立的 aop 方式,這樣致使struts2 的配置文件量比 spring mvc 大。
  • 對 ajax 的支持:spring mvc 集成了ajax,全部 ajax 使用很方便,只須要一個註解 @ResponseBody 就能夠實現了;而 struts2 通常須要安裝插件或者本身寫代碼才行。

71. 如何避免 SQL 注入?

  • 使用預處理 PreparedStatement。
  • 使用正則表達式過濾掉字符中的特殊字符。

72. 什麼是 XSS 攻擊,如何避免?

XSS 攻擊:即跨站腳本攻擊,它是 Web 程序中常見的漏洞。原理是攻擊者往 Web 頁面裏插入惡意的腳本代碼(css 代碼、Javascript 代碼等),當用戶瀏覽該頁面時,嵌入其中的腳本代碼會被執行,從而達到惡意攻擊用戶的目的,如盜取用戶 cookie、破壞頁面結構、重定向到其餘網站等。

預防 XSS 的核心是必須對輸入的數據作過濾處理。

73. 什麼是 CSRF 攻擊,如何避免?

CSRF:Cross-Site Request Forgery(中文:跨站請求僞造),能夠理解爲攻擊者盜用了你的身份,以你的名義發送惡意請求,好比:以你名義發送郵件、發消息、購買商品,虛擬貨幣轉帳等。

防護手段:

  • 驗證請求來源地址;
  • 關鍵操做添加驗證碼;
  • 在請求地址添加 token 並驗證。

異常

74. throw 和 throws 的區別?

  • throw:是真實拋出一個異常。
  • throws:是聲明可能會拋出一個異常。

75. final、finally、finalize 有什麼區別?

  • final:是修飾符,若是修飾類,此類不能被繼承;若是修飾方法和變量,則表示此方法和此變量不能在被改變,只能使用。
  • finally:是 try{} catch{} finally{} 最後一部分,表示不論發生任何狀況都會執行,finally 部分能夠省略,但若是 finally 部分存在,則必定會執行 finally 裏面的代碼。
  • finalize: 是 Object 類的一個方法,在垃圾收集器執行的時候會調用被回收對象的此方法。

76. try-catch-finally 中哪一個部分能夠省略?

try-catch-finally 其中 catch 和 finally 均可以被省略,可是不能同時省略,也就是說有 try 的時候,必須後面跟一個 catch 或者 finally。

77. try-catch-finally 中,若是 catch 中 return 了,finally 還會執行嗎?

finally 必定會執行,即便是 catch 中 return 了,catch 中的 return 會等 finally 中的代碼執行完以後,纔會執行。

78. 常見的異常類有哪些?

  • NullPointerException 空指針異常
  • ClassNotFoundException 指定類不存在
  • NumberFormatException 字符串轉換爲數字異常
  • IndexOutOfBoundsException 數組下標越界異常
  • ClassCastException 數據類型轉換異常
  • FileNotFoundException 文件未找到異常
  • NoSuchMethodException 方法不存在異常
  • IOException IO 異常
  • SocketException Socket 異常

網絡

79. http 響應碼 301 和 302 表明的是什麼?有什麼區別?

301:永久重定向。

302:暫時重定向。

它們的區別是,301 對搜索引擎優化(SEO)更加有利;302 有被提示爲網絡攔截的風險。

80. forward 和 redirect 的區別?

forward 是轉發 和 redirect 是重定向:

  • 地址欄 url 顯示:foward url 不會發生改變,redirect url 會發生改變;
  • 數據共享:forward 能夠共享 request 裏的數據,redirect 不能共享;
  • 效率:forward 比 redirect 效率高。

81. 簡述 tcp 和 udp的區別?

tcp 和 udp 是 OSI 模型中的運輸層中的協議。tcp 提供可靠的通訊傳輸,而 udp 則常被用於讓廣播和細節控制交給應用的通訊傳輸。

二者的區別大體以下:

  • tcp 面向鏈接,udp 面向非鏈接即發送數據前不須要創建連接;
  • tcp 提供可靠的服務(數據傳輸),udp 沒法保證;
  • tcp 面向字節流,udp 面向報文;
  • tcp 數據傳輸慢,udp 數據傳輸快;

82. tcp 爲何要三次握手,兩次不行嗎?爲何?

若是採用兩次握手,那麼只要服務器發出確認數據包就會創建鏈接,但因爲客戶端此時並未響應服務器端的請求,那此時服務器端就會一直在等待客戶端,這樣服務器端就白白浪費了必定的資源。若採用三次握手,服務器端沒有收到來自客戶端的再此確認,則就會知道客戶端並無要求創建請求,就不會浪費服務器的資源。

83. 說一下 tcp 粘包是怎麼產生的?

tcp 粘包可能發生在發送端或者接收端,分別來看兩端各類產生粘包的緣由:

  • 發送端粘包:發送端須要等緩衝區滿才發送出去,形成粘包;
  • 接收方粘包:接收方不及時接收緩衝區的包,形成多個包接收。

84. OSI 的七層模型都有哪些?

  • 物理層:利用傳輸介質爲數據鏈路層提供物理鏈接,實現比特流的透明傳輸。
  • 數據鏈路層:負責創建和管理節點間的鏈路。
  • 網絡層:經過路由選擇算法,爲報文或分組經過通訊子網選擇最適當的路徑。
  • 傳輸層:向用戶提供可靠的端到端的差錯和流量控制,保證報文的正確傳輸。
  • 會話層:向兩個實體的表示層提供創建和使用鏈接的方法。
  • 表示層:處理用戶信息的表示問題,如編碼、數據格式轉換和加密解密等。
  • 應用層:直接向用戶提供服務,完成用戶但願在網絡上完成的各類工做。

85. get 和 post 請求有哪些區別?

  • get 請求會被瀏覽器主動緩存,而 post 不會。
  • get 傳遞參數有大小限制,而 post 沒有。
  • post 參數傳輸更安全,get 的參數會明文限制在 url 上,post 不會。

86. 如何實現跨域?

實現跨域有如下幾種方案:

  • 服務器端運行跨域 設置 CORS 等於 *;
  • 在單個接口使用註解 @CrossOrigin 運行跨域;
  • 使用 jsonp 跨域;

87. 說一下 JSONP 實現原理?

jsonp:JSON with Padding,它是利用script標籤的 src 鏈接能夠訪問不一樣源的特性,加載遠程返回的「JS 函數」來執行的。

設計模式

88. 說一下你熟悉的設計模式?

  • 單例模式:保證被建立一次,節省系統開銷。
  • 工廠模式(簡單工廠、抽象工廠):解耦代碼。
  • 觀察者模式:定義了對象之間的一對多的依賴,這樣一來,當一個對象改變時,它的全部的依賴者都會收到通知並自動更新。
  • 外觀模式:提供一個統一的接口,用來訪問子系統中的一羣接口,外觀定義了一個高層的接口,讓子系統更容易使用。
  • 模版方法模式:定義了一個算法的骨架,而將一些步驟延遲到子類中,模版方法使得子類能夠在不改變算法結構的狀況下,從新定義算法的步驟。
  • 狀態模式:容許對象在內部狀態改變時改變它的行爲,對象看起來好像修改了它的類。

89. 簡單工廠和抽象工廠有什麼區別?

  • 簡單工廠:用來生產同一等級結構中的任意產品,對於增長新的產品,無能爲力。
  • 工廠方法:用來生產同一等級結構中的固定產品,支持增長任意產品。
  • 抽象工廠:用來生產不一樣產品族的所有產品,對於增長新的產品,無能爲力;支持增長產品族。

Spring/Spring MVC

90. 爲何要使用 spring?

  • spring 提供 ioc 技術,容器會幫你管理依賴的對象,從而不須要本身建立和管理依賴對象了,更輕鬆的實現了程序的解耦。
  • spring 提供了事務支持,使得事務操做變的更加方便。
  • spring 提供了面向切片編程,這樣能夠更方便的處理某一類的問題。
  • 更方便的框架集成,spring 能夠很方便的集成其餘框架,好比 MyBatis、hibernate 等。

91. 解釋一下什麼是 aop?

aop 是面向切面編程,經過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。

簡單來講就是統一處理某一「切面」(類)的問題的編程思想,好比統一處理日誌、異常等。

92. 解釋一下什麼是 ioc?

ioc:Inversionof Control(中文:控制反轉)是 spring 的核心,對於 spring 框架來講,就是由 spring 來負責控制對象的生命週期和對象間的關係。

簡單來講,控制指的是當前對象對內部成員的控制權;控制反轉指的是,這種控制權不禁當前對象管理了,由其餘(類,第三方容器)來管理。

93. spring 有哪些主要模塊?

  • spring core:框架的最基礎部分,提供 ioc 和依賴注入特性。
  • spring context:構建於 core 封裝包基礎上的 context 封裝包,提供了一種框架式的對象訪問方法。
  • spring dao:Data Access Object 提供了JDBC的抽象層。
  • spring aop:提供了面向切面的編程實現,讓你能夠自定義攔截器、切點等。
  • spring Web:提供了針對 Web 開發的集成特性,例如文件上傳,利用 servlet listeners 進行 ioc 容器初始化和針對 Web 的 ApplicationContext。
  • spring Web mvc:spring 中的 mvc 封裝包提供了 Web 應用的 Model-View-Controller(MVC)的實現。

94. spring 經常使用的注入方式有哪些?

  • setter 屬性注入
  • 構造方法注入
  • 註解方式注入

95. spring 中的 bean 是線程安全的嗎?

spring 中的 bean 默認是單例模式,spring 框架並無對單例 bean 進行多線程的封裝處理。

實際上大部分時候 spring bean 無狀態的(好比 dao 類),全部某種程度上來講 bean 也是安全的,但若是 bean 有狀態的話(好比 view model 對象),那就要開發者本身去保證線程安全了,最簡單的就是改變 bean 的做用域,把「singleton」變動爲「prototype」,這樣請求 bean 至關於 new Bean()了,因此就能夠保證線程安全了。

  • 有狀態就是有數據存儲功能。
  • 無狀態就是不會保存數據。

96. spring 支持幾種 bean 的做用域?

spring 支持 5 種做用域,以下:

  • singleton:spring ioc 容器中只存在一個 bean 實例,bean 以單例模式存在,是系統默認值;
  • prototype:每次從容器調用 bean 時都會建立一個新的示例,既每次 getBean()至關於執行 new Bean()操做;
  • Web 環境下的做用域:
  • request:每次 http 請求都會建立一個 bean;
  • session:同一個 http session 共享一個 bean 實例;
  • global-session:用於 portlet 容器,由於每一個 portlet 有單獨的 session,globalsession 提供一個全局性的 http session。

注意: 使用 prototype 做用域須要慎重的思考,由於頻繁建立和銷燬 bean 會帶來很大的性能開銷。

97. spring 自動裝配 bean 有哪些方式?

  • no:默認值,表示沒有自動裝配,應使用顯式 bean 引用進行裝配。
  • byName:它根據 bean 的名稱注入對象依賴項。
  • byType:它根據類型注入對象依賴項。
  • 構造函數:經過構造函數來注入依賴項,須要設置大量的參數。
  • autodetect:容器首先經過構造函數使用 autowire 裝配,若是不能,則經過 byType 自動裝配。

98. spring 事務實現方式有哪些?

  • 聲明式事務:聲明式事務也有兩種實現方式,基於 xml 配置文件的方式和註解方式(在類上添加 @Transaction 註解)。
  • 編碼方式:提供編碼的形式管理和維護事務。

99. 說一下 spring 的事務隔離?

spring 有五大隔離級別,默認值爲 ISOLATION_DEFAULT(使用數據庫的設置),其餘四個隔離級別和數據庫的隔離級別一致:

ISOLATION_DEFAULT:用底層數據庫的設置隔離級別,數據庫設置的是什麼我就用什麼;

ISOLATIONREADUNCOMMITTED:未提交讀,最低隔離級別、事務未提交前,就可被其餘事務讀取(會出現幻讀、髒讀、不可重複讀);

ISOLATIONREADCOMMITTED:提交讀,一個事務提交後才能被其餘事務讀取到(會形成幻讀、不可重複讀),SQL server 的默認級別;

ISOLATIONREPEATABLEREAD:可重複讀,保證屢次讀取同一個數據時,其值都和事務開始時候的內容是一致,禁止讀取到別的事務未提交的數據(會形成幻讀),MySQL 的默認級別;

ISOLATION_SERIALIZABLE:序列化,代價最高最可靠的隔離級別,該隔離級別能防止髒讀、不可重複讀、幻讀。

髒讀 :表示一個事務可以讀取另外一個事務中還未提交的數據。好比,某個事務嘗試插入記錄 A,此時該事務還未提交,而後另外一個事務嘗試讀取到了記錄 A。

不可重複讀 :是指在一個事務內,屢次讀同一數據。

幻讀 :指同一個事務內屢次查詢返回的結果集不同。好比同一個事務 A 第一次查詢時候有 n 條記錄,可是第二次同等條件下查詢卻有 n+1 條記錄,這就好像產生了幻覺。發生幻讀的緣由也是另一個事務新增或者刪除或者修改了第一個事務結果集裏面的數據,同一個記錄的數據內容被修改了,全部數據行的記錄就變多或者變少了。

100. 說一下 spring mvc 運行流程?

  • spring mvc 先將請求發送給 DispatcherServlet。
  • DispatcherServlet 查詢一個或多個 HandlerMapping,找處處理請求的 Controller。
  • DispatcherServlet 再把請求提交到對應的 Controller。
  • Controller 進行業務邏輯處理後,會返回一個ModelAndView。
  • Dispathcher 查詢一個或多個 ViewResolver 視圖解析器,找到 ModelAndView 對象指定的視圖對象。
  • 視圖對象負責渲染返回給客戶端。

101. spring mvc 有哪些組件?

  • 前置控制器 DispatcherServlet。
  • 映射控制器 HandlerMapping。
  • 處理器 Controller。
  • 模型和視圖 ModelAndView。
  • 視圖解析器 ViewResolver。

102. @RequestMapping 的做用是什麼?

將 http 請求映射到相應的類/方法上。

103. @Autowired 的做用是什麼?

@Autowired 它能夠對類成員變量、方法及構造函數進行標註,完成自動裝配的工做,經過@Autowired 的使用來消除 set/get 方法。

Spring Boot/Spring Cloud

104. 什麼是 spring boot?

spring boot 是爲 spring 服務的,是用來簡化新 spring 應用的初始搭建以及開發過程的。

105. 爲何要用 spring boot?

  • 配置簡單
  • 獨立運行
  • 自動裝配
  • 無代碼生成和 xml 配置
  • 提供應用監控
  • 易上手
  • 提高開發效率

106. spring boot 核心配置文件是什麼?

spring boot 核心的兩個配置文件:

  • bootstrap (. yml 或者 . properties):boostrap 由父 ApplicationContext 加載的,比 applicaton 優先加載,且 boostrap 裏面的屬性不能被覆蓋;
  • application (. yml 或者 . properties):用於 spring boot 項目的自動化配置。

107. spring boot 配置文件有哪幾種類型?它們有什麼區別?

配置文件有 . properties 格式和 . yml 格式,它們主要的區別是書法風格不一樣。

. properties 配置以下:

spring. RabbitMQ. port=5672 

. yml 配置以下:

spring: RabbitMQ: port: 5672 

. yml 格式不支持 @PropertySource 註解導入。

108. spring boot 有哪些方式能夠實現熱部署?

  • 使用 devtools 啓動熱部署,添加 devtools 庫,在配置文件中把 spring. devtools. restart. enabled 設置爲 true;
  • 使用 Intellij Idea 編輯器,勾上自動編譯或手動從新編譯。

109. jpa 和 hibernate 有什麼區別?

jpa 全稱 Java Persistence API,是 Java 持久化接口規範,hibernate 屬於 jpa 的具體實現。

110. 什麼是 spring cloud?

spring cloud 是一系列框架的有序集合。它利用 spring boot 的開發便利性巧妙地簡化了分佈式系統基礎設施的開發,如服務發現註冊、配置中心、消息總線、負載均衡、斷路器、數據監控等,均可以用 spring boot 的開發風格作到一鍵啓動和部署。

111. spring cloud 斷路器的做用是什麼?

在分佈式架構中,斷路器模式的做用也是相似的,當某個服務單元發生故障(相似用電器發生短路)以後,經過斷路器的故障監控(相似熔斷保險絲),向調用方返回一個錯誤響應,而不是長時間的等待。這樣就不會使得線程因調用故障服務被長時間佔用不釋放,避免了故障在分佈式系統中的蔓延。

112. spring cloud 的核心組件有哪些?

  • Eureka:服務註冊於發現。
  • Feign:基於動態代理機制,根據註解和選擇的機器,拼接請求 url 地址,發起請求。
  • Ribbon:實現負載均衡,從一個服務的多臺機器中選擇一臺。
  • Hystrix:提供線程池,不一樣的服務走不一樣的線程池,實現了不一樣服務調用的隔離,避免了服務雪崩的問題。
  • Zuul:網關管理,由 Zuul 網關轉發請求給對應的服務。

Hibernate

113. 爲何要使用 hibernate?

  • hibernate 是對 jdbc 的封裝,大大簡化了數據訪問層的繁瑣的重複性代碼。
  • hibernate 是一個優秀的 ORM 實現,不少程度上簡化了 DAO 層的編碼功能。
  • 能夠很方便的進行數據庫的移植工做。
  • 提供了緩存機制,是程序執行更改的高效。

114. 什麼是 ORM 框架?

ORM(Object Relation Mapping)對象關係映射,是把數據庫中的關係數據映射成爲程序中的對象。

使用 ORM 的優勢:提升了開發效率下降了開發成本、開發更簡單更對象化、可移植更強。

115. hibernate 中如何在控制檯查看打印的 SQL 語句?

在 Config 裏面把 hibernate. show_SQL 設置爲 true 就能夠。但不建議開啓,開啓以後會下降程序的運行效率。

116. hibernate 有幾種查詢方式?

三種:hql、原生 SQL、條件查詢 Criteria。

117. hibernate 實體類能夠被定義爲 final 嗎?

實體類能夠定義爲 final 類,但這樣的話就不能使用 hibernate 代理模式下的延遲關聯提供性能了,因此不建議定義實體類爲 final。

118. 在 hibernate 中使用 Integer 和 int 作映射有什麼區別?

Integer 類型爲對象,它的值容許爲 null,而 int 屬於基礎數據類型,值不能爲 null。

119. hibernate 是如何工做的?

  • 讀取並解析配置文件。
  • 讀取並解析映射文件,建立 SessionFactory。
  • 打開 Session。
  • 建立事務。
  • 進行持久化操做。
  • 提交事務。
  • 關閉 Session。
  • 關閉 SessionFactory。

120. get()和 load()的區別?

  • 數據查詢時,沒有 OID 指定的對象,get() 返回 null;load() 返回一個代理對象。
  • load()支持延遲加載;get() 不支持延遲加載。

121. 說一下 hibernate 的緩存機制?

hibernate 經常使用的緩存有一級緩存和二級緩存:

一級緩存:也叫 Session 緩存,只在 Session 做用範圍內有效,不須要用戶干涉,由 hibernate 自身維護,能夠經過:evict(object)清除 object 的緩存;clear()清除一級緩存中的全部緩存;flush()刷出緩存;

二級緩存:應用級別的緩存,在全部 Session 中都有效,支持配置第三方的緩存,如:EhCache。

122. hibernate 對象有哪些狀態?

  • 臨時/瞬時狀態:直接 new 出來的對象,該對象還沒被持久化(沒保存在數據庫中),不受 Session 管理。
  • 持久化狀態:當調用 Session 的 save/saveOrupdate/get/load/list 等方法的時候,對象就是持久化狀態。
  • 遊離狀態:Session 關閉以後對象就是遊離狀態。

123. 在 hibernate 中 getCurrentSession 和 openSession 的區別是什麼?

  • getCurrentSession 會綁定當前線程,而 openSession 則不會。
  • getCurrentSession 事務是 Spring 控制的,而且不須要手動關閉,而 openSession 須要咱們本身手動開啓和提交事務。

124. hibernate 實體類必需要有無參構造函數嗎?爲何?

hibernate 中每一個實體類必須提供一個無參構造函數,由於 hibernate 框架要使用 reflection api,經過調用 ClassnewInstance() 來建立實體類的實例,若是沒有無參的構造函數就會拋出異常。

MyBatis

125. MyBatis 中 #{}和 ${}的區別是什麼?

\#{}是預編譯處理,${}是字符替換。 在使用 #{}時,MyBatis 會將 SQL 中的 #{}替換成「?」,配合 PreparedStatement 的 set 方法賦值,這樣能夠有效的防止 SQL 注入,保證程序的運行安全。

126. MyBatis 有幾種分頁方式?

分頁方式:邏輯分頁和物理分頁。

邏輯分頁: 使用 MyBatis 自帶的 RowBounds 進行分頁,它是一次性查詢不少數據,而後在數據中再進行檢索。

物理分頁: 本身手寫 SQL 分頁或使用分頁插件 PageHelper,去數據庫查詢指定條數的分頁數據的形式。

127. RowBounds 是一次性查詢所有結果嗎?爲何?

RowBounds 表面是在「全部」數據中檢索數據,其實並不是是一次性查詢出全部數據,由於 MyBatis 是對 jdbc 的封裝,在 jdbc 驅動中有一個 Fetch Size 的配置,它規定了每次最多從數據庫查詢多少條數據,假如你要查詢更多數據,它會在你執行 next()的時候,去查詢更多的數據。就比如你去自動取款機取 10000 元,但取款機每次最多能取 2500 元,因此你要取 4 次才能把錢取完。只是對於 jdbc 來講,當你調用 next()的時候會自動幫你完成查詢工做。這樣作的好處能夠有效的防止內存溢出。

Fetch Size 官方相關文檔:http://t. cn/EfSE2g3

128. MyBatis 邏輯分頁和物理分頁的區別是什麼?

  • 邏輯分頁是一次性查詢不少數據,而後再在結果中檢索分頁的數據。這樣作弊端是須要消耗大量的內存、有內存溢出的風險、對數據庫壓力較大。
  • 物理分頁是從數據庫查詢指定條數的數據,彌補了一次性所有查出的全部數據的種種缺點,好比須要大量的內存,對數據庫查詢壓力較大等問題。

129. MyBatis 是否支持延遲加載?延遲加載的原理是什麼?

MyBatis 支持延遲加載,設置 lazyLoadingEnabled=true 便可。

延遲加載的原理的是調用的時候觸發加載,而不是在初始化的時候就加載信息。好比調用 a. getB(). getName(),這個時候發現 a. getB() 的值爲 null,此時會單獨觸發事先保存好的關聯 B 對象的 SQL,先查詢出來 B,而後再調用 a. setB(b),而這時候再調用 a. getB(). getName() 就有值了,這就是延遲加載的基本原理。

130. 說一下 MyBatis 的一級緩存和二級緩存?

  • 一級緩存:基於 PerpetualCache 的 HashMap 本地緩存,它的聲明週期是和 SQLSession 一致的,有多個 SQLSession 或者分佈式的環境中數據庫操做,可能會出現髒數據。當 Session flush 或 close 以後,該 Session 中的全部 Cache 就將清空,默認一級緩存是開啓的。
  • 二級緩存:也是基於 PerpetualCache 的 HashMap 本地緩存,不一樣在於其存儲做用域爲 Mapper 級別的,若是多個SQLSession之間須要共享緩存,則須要使用到二級緩存,而且二級緩存可自定義存儲源,如 Ehcache。默認不打開二級緩存,要開啓二級緩存,使用二級緩存屬性類須要實現 Serializable 序列化接口(可用來保存對象的狀態)。

開啓二級緩存數據查詢流程:二級緩存 -> 一級緩存 -> 數據庫。

緩存更新機制:當某一個做用域(一級緩存 Session/二級緩存 Mapper)進行了C/U/D 操做後,默認該做用域下全部 select 中的緩存將被 clear。

131. MyBatis 和 hibernate 的區別有哪些?

  • 靈活性:MyBatis 更加靈活,本身能夠寫 SQL 語句,使用起來比較方便。
  • 可移植性:MyBatis 有不少本身寫的 SQL,由於每一個數據庫的 SQL 能夠不相同,因此可移植性比較差。
  • 學習和使用門檻:MyBatis 入門比較簡單,使用門檻也更低。
  • 二級緩存:hibernate 擁有更好的二級緩存,它的二級緩存能夠自行更換爲第三方的二級緩存。

132. MyBatis 有哪些執行器(Executor)?

MyBatis 有三種基本的Executor執行器:

  • SimpleExecutor:每執行一次 update 或 select 就開啓一個 Statement 對象,用完馬上關閉 Statement 對象;
  • ReuseExecutor:執行 update 或 select,以 SQL 做爲 key 查找 Statement 對象,存在就使用,不存在就建立,用完後不關閉 Statement 對象,而是放置於 Map 內供下一次使用。簡言之,就是重複使用 Statement 對象;
  • BatchExecutor:執行 update(沒有 select,jdbc 批處理不支持 select),將全部 SQL 都添加到批處理中(addBatch()),等待統一執行(executeBatch()),它緩存了多個 Statement 對象,每一個 Statement 對象都是 addBatch()完畢後,等待逐一執行 executeBatch()批處理,與 jdbc 批處理相同。

133. MyBatis 分頁插件的實現原理是什麼?

分頁插件的基本原理是使用 MyBatis 提供的插件接口,實現自定義插件,在插件的攔截方法內攔截待執行的 SQL,而後重寫 SQL,根據 dialect 方言,添加對應的物理分頁語句和物理分頁參數。

134. MyBatis 如何編寫一個自定義插件?

自定義插件實現原理

MyBatis 自定義插件針對 MyBatis 四大對象(Executor、StatementHandler、ParameterHandler、ResultSetHandler)進行攔截:

  • Executor:攔截內部執行器,它負責調用 StatementHandler 操做數據庫,並把結果集經過 ResultSetHandler 進行自動映射,另外它還處理了二級緩存的操做;
  • StatementHandler:攔截 SQL 語法構建的處理,它是 MyBatis 直接和數據庫執行 SQL 腳本的對象,另外它也實現了 MyBatis 的一級緩存;
  • ParameterHandler:攔截參數的處理;
  • ResultSetHandler:攔截結果集的處理。

自定義插件實現關鍵

MyBatis 插件要實現 Interceptor 接口,接口包含的方法,以下:

public interface Interceptor { Object intercept(Invocation invocation) throws Throwable; Object plugin(Object target); void setProperties(Properties properties); } 
  • setProperties 方法是在 MyBatis 進行配置插件的時候能夠配置自定義相關屬性,即:接口實現對象的參數配置;
  • plugin 方法是插件用於封裝目標對象的,經過該方法咱們能夠返回目標對象自己,也能夠返回一個它的代理,能夠決定是否要進行攔截進而決定要返回一個什麼樣的目標對象,官方提供了示例:return Plugin. wrap(target, this);
  • intercept 方法就是要進行攔截的時候要執行的方法。

自定義插件實現示例

官方插件實現:

@Intercepts({@Signature(type = Executor. class, method = "query", args = {MappedStatement. class, Object. class, RowBounds. class, ResultHandler. class})}) public class TestInterceptor implements Interceptor { public Object intercept(Invocation invocation) throws Throwable { Object target = invocation. getTarget(); //被代理對象 Method method = invocation. getMethod(); //代理方法 Object[] args = invocation. getArgs(); //方法參數 // do something . . . . . . 方法攔截前執行代碼塊 Object result = invocation. proceed(); // do something . . . . . . . 方法攔截後執行代碼塊 return result; } public Object plugin(Object target) { return Plugin. wrap(target, this); } } 

RabbitMQ

135. RabbitMQ 的使用場景有哪些?

  • 搶購活動,削峯填谷,防止系統崩塌。
  • 延遲信息處理,好比 10 分鐘以後給下單未付款的用戶發送郵件提醒。
  • 解耦系統,對於新增的功能能夠單獨寫模塊擴展,好比用戶確認評價以後,新增了給用戶返積分的功能,這個時候不用在業務代碼裏添加新增積分的功能,只須要把新增積分的接口訂閱確認評價的消息隊列便可,後面再添加任何功能只須要訂閱對應的消息隊列便可。

136. RabbitMQ 有哪些重要的角色?

RabbitMQ 中重要的角色有:生產者、消費者和代理:

  • 生產者:消息的建立者,負責建立和推送數據到消息服務器;
  • 消費者:消息的接收方,用於處理數據和確認消息;
  • 代理:就是 RabbitMQ 自己,用於扮演「快遞」的角色,自己不生產消息,只是扮演「快遞」的角色。

137. RabbitMQ 有哪些重要的組件?

  • ConnectionFactory(鏈接管理器):應用程序與Rabbit之間創建鏈接的管理器,程序代碼中使用。
  • Channel(信道):消息推送使用的通道。
  • Exchange(交換器):用於接受、分配消息。
  • Queue(隊列):用於存儲生產者的消息。
  • RoutingKey(路由鍵):用於把生成者的數據分配到交換器上。
  • BindingKey(綁定鍵):用於把交換器的消息綁定到隊列上。

138. RabbitMQ 中 vhost 的做用是什麼?

vhost:每一個 RabbitMQ 都能建立不少 vhost,咱們稱之爲虛擬主機,每一個虛擬主機其實都是 mini 版的RabbitMQ,它擁有本身的隊列,交換器和綁定,擁有本身的權限機制。

139. RabbitMQ 的消息是怎麼發送的?

首先客戶端必須鏈接到 RabbitMQ 服務器才能發佈和消費消息,客戶端和 rabbit server 之間會建立一個 tcp 鏈接,一旦 tcp 打開並經過了認證(認證就是你發送給 rabbit 服務器的用戶名和密碼),你的客戶端和 RabbitMQ 就建立了一條 amqp 信道(channel),信道是建立在「真實」 tcp 上的虛擬鏈接,amqp 命令都是經過信道發送出去的,每一個信道都會有一個惟一的 id,不管是發佈消息,訂閱隊列都是經過這個信道完成的。

140. RabbitMQ 怎麼保證消息的穩定性?

  • 提供了事務的功能。
  • 經過將 channel 設置爲 confirm(確認)模式。

141. RabbitMQ 怎麼避免消息丟失?

  • 把消息持久化磁盤,保證服務器重啓消息不丟失。
  • 每一個集羣中至少有一個物理磁盤,保證消息落入磁盤。

142. 要保證消息持久化成功的條件有哪些?

  • 聲明隊列必須設置持久化 durable 設置爲 true.
  • 消息推送投遞模式必須設置持久化,deliveryMode 設置爲 2(持久)。
  • 消息已經到達持久化交換器。
  • 消息已經到達持久化隊列。

以上四個條件都知足才能保證消息持久化成功。

143. RabbitMQ 持久化有什麼缺點?

持久化的缺地就是下降了服務器的吞吐量,由於使用的是磁盤而非內存存儲,從而下降了吞吐量。可儘可能使用 ssd 硬盤來緩解吞吐量的問題。

144. RabbitMQ 有幾種廣播類型?

  • direct(默認方式):最基礎最簡單的模式,發送方把消息發送給訂閱方,若是有多個訂閱者,默認採起輪詢的方式進行消息發送。
  • headers:與 direct 相似,只是性能不好,此類型幾乎用不到。
  • fanout:分發模式,把消費分發給全部訂閱者。
  • topic:匹配訂閱模式,使用正則匹配到消息隊列,能匹配到的都能接收到。

145. RabbitMQ 怎麼實現延遲消息隊列?

延遲隊列的實現有兩種方式:

  • 經過消息過時後進入死信交換器,再由交換器轉發到延遲消費隊列,實現延遲功能;
  • 使用 RabbitMQ-delayed-message-exchange 插件實現延遲功能。

146. RabbitMQ 集羣有什麼用?

集羣主要有如下兩個用途:

  • 高可用:某個服務器出現問題,整個 RabbitMQ 還能夠繼續使用;
  • 高容量:集羣能夠承載更多的消息量。

147. RabbitMQ 節點的類型有哪些?

  • 磁盤節點:消息會存儲到磁盤。
  • 內存節點:消息都存儲在內存中,重啓服務器消息丟失,性能高於磁盤類型。

148. RabbitMQ 集羣搭建須要注意哪些問題?

  • 各節點之間使用「--link」鏈接,此屬性不能忽略。
  • 各節點使用的 erlang cookie 值必須相同,此值至關於「祕鑰」的功能,用於各節點的認證。
  • 整個集羣中必須包含一個磁盤節點。

149. RabbitMQ 每一個節點是其餘節點的完整拷貝嗎?爲何?

不是,緣由有如下兩個:

  • 存儲空間的考慮:若是每一個節點都擁有全部隊列的徹底拷貝,這樣新增節點不但沒有新增存儲空間,反而增長了更多的冗餘數據;
  • 性能的考慮:若是每條消息都須要完整拷貝到每個集羣節點,那新增節點並無提高處理消息的能力,最可能是保持和單節點相同的性能甚至是更糟。

150. RabbitMQ 集羣中惟一一個磁盤節點崩潰了會發生什麼狀況?

若是惟一磁盤的磁盤節點崩潰了,不能進行如下操做:

  • 不能建立隊列
  • 不能建立交換器
  • 不能建立綁定
  • 不能添加用戶
  • 不能更改權限
  • 不能添加和刪除集羣節點

惟一磁盤節點崩潰了,集羣是能夠保持運行的,但你不能更改任何東西。

151. RabbitMQ 對集羣節點中止順序有要求嗎?

RabbitMQ 對集羣的中止的順序是有要求的,應該先關閉內存節點,最後再關閉磁盤節點。若是順序剛好相反的話,可能會形成消息的丟失。

Kafka

152. kafka 能夠脫離 zookeeper 單獨使用嗎?爲何?

kafka 不能脫離 zookeeper 單獨使用,由於 kafka 使用 zookeeper 管理和協調 kafka 的節點服務器。

153. kafka 有幾種數據保留的策略?

kafka 有兩種數據保存策略:按照過時時間保留和按照存儲的消息大小保留。

154. kafka 同時設置了 7 天和 10G 清除數據,到第五天的時候消息達到了 10G,這個時候 kafka 將如何處理?

這個時候 kafka 會執行數據清除工做,時間和大小不論那個知足條件,都會清空數據。

155. 什麼狀況會致使 kafka 運行變慢?

  • cpu 性能瓶頸
  • 磁盤讀寫瓶頸
  • 網絡瓶頸

156. 使用 kafka 集羣須要注意什麼?

  • 集羣的數量不是越多越好,最好不要超過 7 個,由於節點越多,消息複製須要的時間就越長,整個羣組的吞吐量就越低。
  • 集羣數量最好是單數,由於超過一半故障集羣就不能用了,設置爲單數容錯率更高。

Zookeeper

157. zookeeper 是什麼?

zookeeper 是一個分佈式的,開放源碼的分佈式應用程序協調服務,是 google chubby 的開源實現,是 hadoop 和 hbase 的重要組件。它是一個爲分佈式應用提供一致性服務的軟件,提供的功能包括:配置維護、域名服務、分佈式同步、組服務等。

158. zookeeper 都有哪些功能?

  • 集羣管理:監控節點存活狀態、運行請求等。
  • 主節點選舉:主節點掛掉了以後能夠從備用的節點開始新一輪選主,主節點選舉說的就是這個選舉的過程,使用 zookeeper 能夠協助完成這個過程。
  • 分佈式鎖:zookeeper 提供兩種鎖:獨佔鎖、共享鎖。獨佔鎖即一次只能有一個線程使用資源,共享鎖是讀鎖共享,讀寫互斥,便可以有多線線程同時讀同一個資源,若是要使用寫鎖也只能有一個線程使用。zookeeper能夠對分佈式鎖進行控制。
  • 命名服務:在分佈式系統中,經過使用命名服務,客戶端應用可以根據指定名字來獲取資源或服務的地址,提供者等信息。

159. zookeeper 有幾種部署模式?

zookeeper 有三種部署模式:

  • 單機部署:一臺集羣上運行;
  • 集羣部署:多臺集羣運行;
  • 僞集羣部署:一臺集羣啓動多個 zookeeper 實例運行。

160. zookeeper 怎麼保證主從節點的狀態同步?

zookeeper 的核心是原子廣播,這個機制保證了各個 server 之間的同步。實現這個機制的協議叫作 zab 協議。 zab 協議有兩種模式,分別是恢復模式(選主)和廣播模式(同步)。當服務啓動或者在領導者崩潰後,zab 就進入了恢復模式,當領導者被選舉出來,且大多數 server 完成了和 leader 的狀態同步之後,恢復模式就結束了。狀態同步保證了 leader 和 server 具備相同的系統狀態。

161. 集羣中爲何要有主節點?

在分佈式環境中,有些業務邏輯只須要集羣中的某一臺機器進行執行,其餘的機器能夠共享這個結果,這樣能夠大大減小重複計算,提升性能,因此就須要主節點。

162. 集羣中有 3 臺服務器,其中一個節點宕機,這個時候 zookeeper 還可使用嗎?

能夠繼續使用,單數服務器只要沒超過一半的服務器宕機就能夠繼續使用。

163. 說一下 zookeeper 的通知機制?

客戶端端會對某個 znode 創建一個 watcher 事件,當該 znode 發生變化時,這些客戶端會收到 zookeeper 的通知,而後客戶端能夠根據 znode 變化來作出業務上的改變。

MySQL

164. 數據庫的三範式是什麼?

  • 第一範式:強調的是列的原子性,即數據庫表的每一列都是不可分割的原子數據項。
  • 第二範式:要求實體的屬性徹底依賴於主關鍵字。所謂徹底依賴是指不能存在僅依賴主關鍵字一部分的屬性。
  • 第三範式:任何非主屬性不依賴於其它非主屬性。

165. 一張自增表裏面總共有 7 條數據,刪除了最後 2 條數據,重啓 MySQL 數據庫,又插入了一條數據,此時 id 是幾?

  • 表類型若是是 MyISAM ,那 id 就是 8。
  • 表類型若是是 InnoDB,那 id 就是 6。

InnoDB 表只會把自增主鍵的最大 id 記錄在內存中,因此重啓以後會致使最大 id 丟失。

166. 如何獲取當前數據庫版本?

使用 select version() 獲取當前 MySQL 數據庫版本。

167. 說一下 ACID 是什麼?

  • Atomicity(原子性):一個事務(transaction)中的全部操做,或者所有完成,或者所有不完成,不會結束在中間某個環節。事務在執行過程當中發生錯誤,會被恢復(Rollback)到事務開始前的狀態,就像這個事務歷來沒有執行過同樣。即,事務不可分割、不可約簡。
  • Consistency(一致性):在事務開始以前和事務結束之後,數據庫的完整性沒有被破壞。這表示寫入的資料必須徹底符合全部的預設約束、觸發器、級聯回滾等。
  • Isolation(隔離性):數據庫容許多個併發事務同時對其數據進行讀寫和修改的能力,隔離性能夠防止多個事務併發執行時因爲交叉執行而致使數據的不一致。事務隔離分爲不一樣級別,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重複讀(repeatable read)和串行化(Serializable)。
  • Durability(持久性):事務處理結束後,對數據的修改就是永久的,即使系統故障也不會丟失。

168. char 和 varchar 的區別是什麼?

  • char(n) :固定長度類型,好比訂閱 char(10),當你輸入"abc"三個字符的時候,它們佔的空間仍是 10 個字節,其餘 7 個是空字節。

chat 優勢:效率高;缺點:佔用空間;適用場景:存儲密碼的 md5 值,固定長度的,使用 char 很是合適。

  • varchar(n) :可變長度,存儲的值是每一個值佔用的字節再加上一個用來記錄其長度的字節的長度。

因此,從空間上考慮 varcahr 比較合適;從效率上考慮 char 比較合適,兩者使用須要權衡。

169. float 和 double 的區別是什麼?

  • float 最多能夠存儲 8 位的十進制數,並在內存中佔 4 字節。
  • double 最可能夠存儲 16 位的十進制數,並在內存中佔 8 字節。

170. MySQL 的內鏈接、左鏈接、右鏈接有什麼區別?

內鏈接關鍵字:inner join;左鏈接:left join;右鏈接:right join。

內鏈接是把匹配的關聯數據顯示出來;左鏈接是左邊的表所有顯示出來,右邊的表顯示出符合條件的數據;右鏈接正好相反。

171. MySQL 索引是怎麼實現的?

索引是知足某種特定查找算法的數據結構,而這些數據結構會以某種方式指向數據,從而實現高效查找數據。

具體來講 MySQL 中的索引,不一樣的數據引擎實現有所不一樣,但目前主流的數據庫引擎的索引都是 B+ 樹實現的,B+ 樹的搜索效率,能夠到達二分法的性能,找到數據區域以後就找到了完整的數據結構了,全部索引的性能也是更好的。

172. 怎麼驗證 MySQL 的索引是否知足需求?

使用 explain 查看 SQL 是如何執行查詢語句的,從而分析你的索引是否知足需求。

explain 語法:explain select * from table where type=1。

173. 說一下數據庫的事務隔離?

MySQL 的事務隔離是在 MySQL. ini 配置文件裏添加的,在文件的最後添加:

transaction-isolation = REPEATABLE-READ

可用的配置值:READ-UNCOMMITTED、READ-COMMITTED、REPEATABLE-READ、SERIALIZABLE。

  • READ-UNCOMMITTED:未提交讀,最低隔離級別、事務未提交前,就可被其餘事務讀取(會出現幻讀、髒讀、不可重複讀)。
  • READ-COMMITTED:提交讀,一個事務提交後才能被其餘事務讀取到(會形成幻讀、不可重複讀)。
  • REPEATABLE-READ:可重複讀,默認級別,保證屢次讀取同一個數據時,其值都和事務開始時候的內容是一致,禁止讀取到別的事務未提交的數據(會形成幻讀)。
  • SERIALIZABLE:序列化,代價最高最可靠的隔離級別,該隔離級別能防止髒讀、不可重複讀、幻讀。

髒讀 :表示一個事務可以讀取另外一個事務中還未提交的數據。好比,某個事務嘗試插入記錄 A,此時該事務還未提交,而後另外一個事務嘗試讀取到了記錄 A。

不可重複讀 :是指在一個事務內,屢次讀同一數據。

幻讀 :指同一個事務內屢次查詢返回的結果集不同。好比同一個事務 A 第一次查詢時候有 n 條記錄,可是第二次同等條件下查詢卻有 n+1 條記錄,這就好像產生了幻覺。發生幻讀的緣由也是另一個事務新增或者刪除或者修改了第一個事務結果集裏面的數據,同一個記錄的數據內容被修改了,全部數據行的記錄就變多或者變少了。

174. 說一下 MySQL 經常使用的引擎?

  • InnoDB 引擎:mysql 5.1 後默認的數據庫引擎,提供了對數據庫 acid 事務的支持,而且還提供了行級鎖和外鍵的約束,它的設計的目標就是處理大數據容量的數據庫系統。MySQL 運行的時候,InnoDB 會在內存中創建緩衝池,用於緩衝數據和索引。可是該引擎是不支持全文搜索,同時啓動也比較的慢,它是不會保存表的行數的,因此當進行 select count(*) from table 指令的時候,須要進行掃描全表。因爲鎖的粒度小,寫操做是不會鎖定全表的,因此在併發度較高的場景下使用會提高效率的。

  • MyIASM 引擎:不提供事務的支持,也不支持行級鎖和外鍵。所以當執行插入和更新語句時,即執行寫操做的時候須要鎖定這個表,因此會致使效率會下降。不過和 InnoDB 不一樣的是,MyIASM 引擎是保存了表的行數,因而當進行 select count(*) from table 語句時,能夠直接的讀取已經保存的值而不須要進行掃描全表。因此,若是表的讀操做遠遠多於寫操做時,而且不須要事務的支持的,能夠將 MyIASM 做爲數據庫引擎的首選。

175. 說一下 MySQL 的行鎖和表鎖?

MyISAM 只支持表鎖,InnoDB 支持表鎖和行鎖,默認爲行鎖。

  • 表級鎖:開銷小,加鎖快,不會出現死鎖。鎖定粒度大,發生鎖衝突的機率最高,併發量最低。
  • 行級鎖:開銷大,加鎖慢,會出現死鎖。鎖力度小,發生鎖衝突的機率小,併發度最高。

176. 說一下樂觀鎖和悲觀鎖?

  • 樂觀鎖:每次去拿數據的時候都認爲別人不會修改,因此不會上鎖,可是在提交更新的時候會判斷一下在此期間別人有沒有去更新這個數據。
  • 悲觀鎖:每次去拿數據的時候都認爲別人會修改,因此每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會阻止,直到這個鎖被釋放。

數據庫的樂觀鎖須要本身實現,在表裏面添加一個 version 字段,每次修改爲功值加 1,這樣每次修改的時候先對比一下,本身擁有的 version 和數據庫如今的 version 是否一致,若是不一致就不修改,這樣就實現了樂觀鎖。

177. MySQL 問題排查都有哪些手段?

  • 使用 show processlist 命令查看當前全部鏈接信息。
  • 使用 explain 命令查詢 SQL 語句執行計劃。
  • 開啓慢查詢日誌,查看慢查詢的 SQL。

178. 如何作 MySQL 的性能優化?

  • 爲搜索字段建立索引。
  • 避免使用 select *,列出須要查詢的字段。
  • 垂直分割分表。
  • 選擇正確的存儲引擎。

Redis

179. Redis 是什麼?都有哪些使用場景?

Redis 是一個使用 C 語言開發的高速緩存數據庫。

Redis 使用場景:

  • 記錄帖子點贊數、點擊數、評論數;
  • 緩存近期熱帖;
  • 緩存文章詳情信息;
  • 記錄用戶會話信息。

180. Redis 有哪些功能?

  • 數據緩存功能
  • 分佈式鎖的功能
  • 支持數據持久化
  • 支持事務
  • 支持消息隊列

181. Redis 和 memcache 有什麼區別?

  • 存儲方式不一樣:memcache 把數據所有存在內存之中,斷電後會掛掉,數據不能超過內存大小;Redis 有部份存在硬盤上,這樣能保證數據的持久性。
  • 數據支持類型:memcache 對數據類型支持相對簡單;Redis 有複雜的數據類型。
  • 使用底層模型不一樣:它們之間底層實現方式,以及與客戶端之間通訊的應用協議不同,Redis 本身構建了 vm 機制,由於通常的系統調用系統函數的話,會浪費必定的時間去移動和請求。
  • value 值大小不一樣:Redis 最大能夠達到 512mb;memcache 只有 1mb。

182. Redis 爲何是單線程的?

由於 cpu 不是 Redis 的瓶頸,Redis 的瓶頸最有多是機器內存或者網絡帶寬。既然單線程容易實現,並且 cpu 又不會成爲瓶頸,那就瓜熟蒂落地採用單線程的方案了。

關於 Redis 的性能,官方網站也有,普通筆記本輕鬆處理每秒幾十萬的請求。

並且單線程並不表明就慢 nginx 和 nodejs 也都是高性能單線程的表明。

183. 什麼是緩存穿透?怎麼解決?

緩存穿透:指查詢一個必定不存在的數據,因爲緩存是不命中時須要從數據庫查詢,查不到數據則不寫入緩存,這將致使這個不存在的數據每次請求都要到數據庫去查詢,形成緩存穿透。

解決方案:最簡單粗暴的方法若是一個查詢返回的數據爲空(無論是數據不存在,仍是系統故障),咱們就把這個空結果進行緩存,但它的過時時間會很短,最長不超過五分鐘。

184. Redis 支持的數據類型有哪些?

Redis 支持的數據類型:string(字符串)、list(列表)、hash(字典)、set(集合)、zset(有序集合)。

185. Redis 支持的 Java 客戶端都有哪些?

支持的 Java 客戶端有 Redisson、jedis、lettuce 等。

186. jedis 和 Redisson 有哪些區別?

  • jedis:提供了比較全面的 Redis 命令的支持。
  • Redisson:實現了分佈式和可擴展的 Java 數據結構,與 jedis 相比 Redisson 的功能相對簡單,不支持排序、事務、管道、分區等 Redis 特性。

187. 怎麼保證緩存和數據庫數據的一致性?

  • 合理設置緩存的過時時間。
  • 新增、更改、刪除數據庫操做時同步更新 Redis,可使用事物機制來保證數據的一致性。

188. Redis 持久化有幾種方式?

Redis 的持久化有兩種方式,或者說有兩種策略:

  • RDB(Redis Database):指定的時間間隔能對你的數據進行快照存儲。
  • AOF(Append Only File):每個收到的寫命令都經過write函數追加到文件中。

189. Redis 怎麼實現分佈式鎖?

Redis 分佈式鎖其實就是在系統裏面佔一個「坑」,其餘程序也要佔「坑」的時候,佔用成功了就能夠繼續執行,失敗了就只能放棄或稍後重試。

佔坑通常使用 setnx(set if not exists)指令,只容許被一個程序佔有,使用完調用 del 釋放鎖。

190. Redis 分佈式鎖有什麼缺陷?

Redis 分佈式鎖不能解決超時的問題,分佈式鎖有一個超時時間,程序的執行若是超出了鎖的超時時間就會出現問題。

191. Redis 如何作內存優化?

儘可能使用 Redis 的散列表,把相關的信息放到散列表裏面存儲,而不是把每一個字段單獨存儲,這樣能夠有效的減小內存使用。好比將 Web 系統的用戶對象,應該放到散列表裏面再總體存儲到 Redis,而不是把用戶的姓名、年齡、密碼、郵箱等字段分別設置 key 進行存儲。

192. Redis 淘汰策略有哪些?

  • volatile-lru:從已設置過時時間的數據集(server. db[i]. expires)中挑選最近最少使用的數據淘汰。

  • volatile-ttl:從已設置過時時間的數據集(server. db[i]. expires)中挑選將要過時的數據淘汰。

  • volatile-random:從已設置過時時間的數據集(server. db[i]. expires)中任意選擇數據淘汰。

  • allkeys-lru:從數據集(server. db[i]. dict)中挑選最近最少使用的數據淘汰。

  • allkeys-random:從數據集(server. db[i]. dict)中任意選擇數據淘汰。

  • no-enviction(驅逐):禁止驅逐數據。

193. Redis 常見的性能問題有哪些?該如何解決?

  • 主服務器寫內存快照,會阻塞主線程的工做,當快照比較大時對性能影響是很是大的,會間斷性暫停服務,因此主服務器最好不要寫內存快照。
  • Redis 主從複製的性能問題,爲了主從複製的速度和鏈接的穩定性,主從庫最好在同一個局域網內。

JVM

194. 說一下 JVM 的主要組成部分?及其做用?

  • 類加載器(ClassLoader)
  • 運行時數據區(Runtime Data Area)
  • 執行引擎(Execution Engine)
  • 本地庫接口(Native Interface)

組件的做用: 首先經過類加載器(ClassLoader)會把 Java 代碼轉換成字節碼,運行時數據區(Runtime Data Area)再把字節碼加載到內存中,而字節碼文件只是 JVM 的一套指令集規範,並不能直接交給底層操做系統去執行,所以須要特定的命令解析器執行引擎(Execution Engine),將字節碼翻譯成底層系統指令,再交由 CPU 去執行,而這個過程當中須要調用其餘語言的本地庫接口(Native Interface)來實現整個程序的功能。

195. 說一下 JVM 運行時數據區?

不一樣虛擬機的運行時數據區可能略微有所不一樣,但都會聽從 Java 虛擬機規範, Java 虛擬機規範規定的區域分爲如下 5 個部分:

  • 程序計數器(Program Counter Register):當前線程所執行的字節碼的行號指示器,字節碼解析器的工做是經過改變這個計數器的值,來選取下一條須要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能,都須要依賴這個計數器來完成;

  • Java 虛擬機棧(Java Virtual Machine Stacks):用於存儲局部變量表、操做數棧、動態連接、方法出口等信息;

  • 本地方法棧(Native Method Stack):與虛擬機棧的做用是同樣的,只不過虛擬機棧是服務 Java 方法的,而本地方法棧是爲虛擬機調用 Native 方法服務的;

  • Java 堆(Java Heap):Java 虛擬機中內存最大的一塊,是被全部線程共享的,幾乎全部的對象實例都在這裏分配內存;

  • 方法區(Methed Area):用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯後的代碼等數據。

196. 說一下堆棧的區別?

  • 功能方面:堆是用來存放對象的,棧是用來執行程序的。
  • 共享性:堆是線程共享的,棧是線程私有的。
  • 空間大小:堆大小遠遠大於棧。

197. 隊列和棧是什麼?有什麼區別?

隊列和棧都是被用來預存儲數據的。

隊列容許先進先出檢索元素,但也有例外的狀況,Deque 接口容許從兩端檢索元素。

棧和隊列很類似,但它運行對元素進行後進先出進行檢索。

198. 什麼是雙親委派模型?

在介紹雙親委派模型以前先說下類加載器。對於任意一個類,都須要由加載它的類加載器和這個類自己一同確立在 JVM 中的惟一性,每個類加載器,都有一個獨立的類名稱空間。類加載器就是根據指定全限定名稱將 class 文件加載到 JVM 內存,而後再轉化爲 class 對象。

類加載器分類:

  • 啓動類加載器(Bootstrap ClassLoader),是虛擬機自身的一部分,用來加載Java_HOME/lib/目錄中的,或者被 -Xbootclasspath 參數所指定的路徑中而且被虛擬機識別的類庫;
  • 其餘類加載器:
  • 擴展類加載器(Extension ClassLoader):負責加載<java_home>\lib\ext目錄或Java. ext. dirs系統變量指定的路徑中的全部類庫;
  • 應用程序類加載器(Application ClassLoader)。負責加載用戶類路徑(classpath)上的指定類庫,咱們能夠直接使用這個類加載器。通常狀況,若是咱們沒有自定義類加載器默認就是用這個加載器。

雙親委派模型:若是一個類加載器收到了類加載的請求,它首先不會本身去加載這個類,而是把這個請求委派給父類加載器去完成,每一層的類加載器都是如此,這樣全部的加載請求都會被傳送到頂層的啓動類加載器中,只有當父加載沒法完成加載請求(它的搜索範圍中沒找到所需的類)時,子加載器纔會嘗試去加載類。

199. 說一下類裝載的執行過程?

類裝載分爲如下 5 個步驟:

  • 加載:根據查找路徑找到相應的 class 文件而後導入;
  • 檢查:檢查加載的 class 文件的正確性;
  • 準備:給類中的靜態變量分配內存空間;
  • 解析:虛擬機將常量池中的符號引用替換成直接引用的過程。符號引用就理解爲一個標示,而在直接引用直接指向內存中的地址;
  • 初始化:對靜態變量和靜態代碼塊執行初始化工做。

200. 怎麼判斷對象是否能夠被回收?

通常有兩種方法來判斷:

  • 引用計數器:爲每一個對象建立一個引用計數,有對象引用時計數器 +1,引用被釋放時計數 -1,當計數器爲 0 時就能夠被回收。它有一個缺點不能解決循環引用的問題;
  • 可達性分析:從 GC Roots 開始向下搜索,搜索所走過的路徑稱爲引用鏈。當一個對象到 GC Roots 沒有任何引用鏈相連時,則證實此對象是能夠被回收的。

201. Java 中都有哪些引用類型?

  • 強引用:發生 gc 的時候不會被回收。
  • 軟引用:有用但不是必須的對象,在發生內存溢出以前會被回收。
  • 弱引用:有用但不是必須的對象,在下一次GC時會被回收。
  • 虛引用(幽靈引用/幻影引用):沒法經過虛引用得到對象,用 PhantomReference 實現虛引用,虛引用的用途是在 gc 時返回一個通知。

202. 說一下 JVM 有哪些垃圾回收算法?

  • 標記-清除算法:標記無用對象,而後進行清除回收。缺點:效率不高,沒法清除垃圾碎片。
  • 標記-整理算法:標記無用對象,讓全部存活的對象都向一端移動,而後直接清除掉端邊界之外的內存。
  • 複製算法:按照容量劃分二個大小相等的內存區域,當一塊用完的時候將活着的對象複製到另外一塊上,而後再把已使用的內存空間一次清理掉。缺點:內存使用率不高,只有原來的一半。
  • 分代算法:根據對象存活週期的不一樣將內存劃分爲幾塊,通常是新生代和老年代,新生代基本採用複製算法,老年代採用標記整理算法。

203. 說一下 JVM 有哪些垃圾回收器?

  • Serial:最先的單線程串行垃圾回收器。
  • Serial Old:Serial 垃圾回收器的老年版本,一樣也是單線程的,能夠做爲 CMS 垃圾回收器的備選預案。
  • ParNew:是 Serial 的多線程版本。
  • Parallel 和 ParNew 收集器相似是多線程的,但 Parallel 是吞吐量優先的收集器,能夠犧牲等待時間換取系統的吞吐量。
  • Parallel Old 是 Parallel 老生代版本,Parallel 使用的是複製的內存回收算法,Parallel Old 使用的是標記-整理的內存回收算法。
  • CMS:一種以得到最短停頓時間爲目標的收集器,很是適用 B/S 系統。
  • G1:一種兼顧吞吐量和停頓時間的 GC 實現,是 JDK 9 之後的默認 GC 選項。

204. 詳細介紹一下 CMS 垃圾回收器?

CMS 是英文 Concurrent Mark-Sweep 的簡稱,是以犧牲吞吐量爲代價來得到最短回收停頓時間的垃圾回收器。對於要求服務器響應速度的應用上,這種垃圾回收器很是適合。在啓動 JVM 的參數加上「-XX:+UseConcMarkSweepGC」來指定使用 CMS 垃圾回收器。

CMS 使用的是標記-清除的算法實現的,因此在 gc 的時候回產生大量的內存碎片,當剩餘內存不能知足程序運行要求時,系統將會出現 Concurrent Mode Failure,臨時 CMS 會採用 Serial Old 回收器進行垃圾清除,此時的性能將會被下降。

205. 新生代垃圾回收器和老生代垃圾回收器都有哪些?有什麼區別?

  • 新生代回收器:Serial、ParNew、Parallel Scavenge
  • 老年代回收器:Serial Old、Parallel Old、CMS
  • 整堆回收器:G1

新生代垃圾回收器通常採用的是複製算法,複製算法的優勢是效率高,缺點是內存利用率低;老年代回收器通常採用的是標記-整理的算法進行垃圾回收。

206. 簡述分代垃圾回收器是怎麼工做的?

分代回收器有兩個分區:老生代和新生代,新生代默認的空間佔比總空間的 1/3,老生代的默認佔比是 2/3。

新生代使用的是複製算法,新生代裏有 3 個分區:Eden、To Survivor、From Survivor,它們的默認佔比是 8:1:1,它的執行流程以下:

  • 把 Eden + From Survivor 存活的對象放入 To Survivor 區;
  • 清空 Eden 和 From Survivor 分區;
  • From Survivor 和 To Survivor 分區交換,From Survivor 變 To Survivor,To Survivor 變 From Survivor。

每次在 From Survivor 到 To Survivor 移動時都存活的對象,年齡就 +1,當年齡到達 15(默認配置是 15)時,升級爲老生代。大對象也會直接進入老生代。

老生代當空間佔用到達某個值以後就會觸發全局垃圾收回,通常使用標記整理的執行算法。以上這些循環往復就構成了整個分代垃圾回收的總體執行流程。

207. 說一下 JVM 調優的工具?

JDK 自帶了不少監控工具,都位於 JDK 的 bin 目錄下,其中最經常使用的是 jconsole 和 jvisualvm 這兩款視圖監控工具。

  • jconsole:用於對 JVM 中的內存、線程和類等進行監控;
  • jvisualvm:JDK 自帶的全能分析工具,能夠分析:內存快照、線程快照、程序死鎖、監控內存的變化、gc 變化等。

208. 經常使用的 JVM 調優的參數都有哪些?

  • -Xms2g:初始化推大小爲 2g;
  • -Xmx2g:堆最大內存爲 2g;
  • -XX:NewRatio=4:設置年輕的和老年代的內存比例爲 1:4;
  • -XX:SurvivorRatio=8:設置新生代 Eden 和 Survivor 比例爲 8:2;
  • –XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器組合;
  • -XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器組合;
  • -XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器組合;
  • -XX:+PrintGC:開啓打印 gc 信息;
  • -XX:+PrintGCDetails:打印 gc 詳細信息。