這份面試題包含了 19 個模塊:Java 基礎、容器、多線程、反射、對象拷貝、Java Web、異常、網絡、設計模式、Spring/Spring MVC、Spring Boot/Spring Cloud、Hibernate、Mybatis、RabbitMQ、Kafka、Zookeeper、MySql、Redis、JVM 等。
一、Java 基礎
1.JDK 和 JRE 有什么區別?
這個問題其實只要弄清楚JDK和JRE是什么就知道答案了
JRE是java運行時環境,包含了java虛擬機,java基礎類庫。是使用java語言編寫的程序運行所需要的軟件環境,是提供給想運行java程序的用戶使用的,還有所有的Java類庫的class文件,都在lib目錄下,並且都打包成了jar.
JDK是java開發工具包,是程序員使用java語言編寫java程序所需的開發工具包,是提供給程序員使用的。JDK包含了JRE,同時還包含了編譯java源碼的編譯器javac,還包含了很多java程序調試和分析的工具:jconsole,jvisualvm等工具軟件,還包含了java程序編寫所需的文檔和demo例子程序。
總結:簡單來說,JRE可以支撐Java程序的運行,包括JVM虛擬機(java.exe等)和基本的類庫(rt.jar等),JDK可以支持Java程序的開發,包括編譯器(javac.exe)、開發工具(javadoc.exe、jar.exe、keytool.exe、jconsole.exe)和更多的類庫(如tools.jar)等。
2.== 和 equals 的區別是什么?
這個題大多數時候出現在筆試中,當然,有的面試官也會問到。
簡單來講,他們的區別有以下三方面:
- ==是判斷兩個變量或實例是不是指向同一個內存空間,equals是判斷兩個變量或實例所指向的內存空間的值是不是相同
- ==是指對內存地址進行比較 , equals()是對字符串的內容進行比較
- ==指引用是否相同, equals()指的是值是否相同
用一張圖來說明他們的關系(圖片轉載自https://blog.csdn.net/qq_36522306/article/details/80550210)
3.兩個對象的 hashCode()相同,則 equals()也一定為 true,對嗎?
這個題明顯是不對的,反過來說就對了(前提是你重寫了hashcode方法,如果沒重寫,也是不一定相等的)。但是一般情況下,如果是筆試時候遇到,答錯誤就行了,但如果是面試的時候問到,面試官肯定能會深究繼續問為什么不對,這個時候你就要了解下他們的原理了。hashCode()返回該對象的哈希碼值;equals()返回兩個對象是否相等。
關於hashCode和equal是方法,有如下幾點需要注意的:
1、兩個對象用equals()比較返回true,那么兩個對象的hashCode()方法必須返回相同的結果。
2、兩個對象用equals()比較返回false,不要求hashCode()方法也一定返回不同的值,但是最好返回不同值,億提搞哈希表性能。
3、重寫equals()方法,必須重寫hashCode()方法,以保證equals方法相等時兩個對象hashcode返回相同的值。
4.final 在 java 中有什么作用?
final作為Java中的關鍵字可以用於三個地方。用於修飾類、類屬性和類方法。
特征:凡是引用final關鍵字的地方皆不可修改!
(1)修飾類:表示該類不能被繼承;
(2)修飾方法:表示方法不能被重寫;
(3)修飾變量:表示變量只能一次賦值以后值不能被修改(常量)。
5.java 中的 Math.round(-1.5) 等於多少?
這種題一般也只會出現在筆試題中,但如果答錯,也是相當掉分的,因為這是基礎中的基礎。
Math.round(1.5)的返回值是2,Math.round(-1.5)的返回值是-1。四舍五入的原理是在參數上加0.5然后做向下取整。
6.String 屬於基礎的數據類型嗎?
答案肯定是不屬於,而且這里你要知道java的8中基礎數據類型,並且知道他們的位數,取值范圍。速記方法:知道了位數,他們的范圍就知道了,就是2的-(位數-1)次冪~(位數-1)次冪-1
7.java 中操作字符串都有哪些類?它們之間有什么區別?
這個題,博主每次面試幾乎都會被問到,有的面試官會問的比較深,所以要知道其原理,即為什么可變,為什么不可變,為什么線程安全,為什么線程不安全。
String、StringBuffer、StringBuilder
String因為底層是final修飾的,所以長度不可變
StringBuffer、StringBuilder長度可變,但是他們兩者也有差別,StringBuffer線程安全(底層方法都是synchronized關鍵字修飾的,所以線程安全),StringBuilder線程不安全
8.String str="i"與 String str=new String("i")一樣嗎?
答案肯定是不一樣的,但是為什么呢,給大家舉個栗子,大家看看就立馬就明白了。
String x = "張三"; String y = "張三"; String z = new String("張三"); System.out.println(x == y); // true System.out.println(x == z); // false
為什么會輸出上邊的結果呢,String x = "張三" 的方式,Java 虛擬機會將其分配到常量池中,而常量池中沒有重復的元素,比如當執行“張三”時,java虛擬機會先在常量池中檢索是否已經有“張三”,如果有那么就將“張三”的地址賦給變量,如果沒有就創建一個,然后在賦給變量;而 String z = new String(“張三”) 則會被分到堆內存中,即使內容一樣還是會創建新的對象。
9.如何將字符串反轉?
最便捷的方式當然是使用StringBuffer或者StringBuilder的reverse 方法,其本質都調用了它們的父類 AbstractStringBuilder 的 reverse 方法實現。
/** * 使用 StringBuilder * @param str * @return */ public static String reverseStringByStringBuilderApi(String str) { if (str != null && str.length() > 0) { return new StringBuilder(str).reverse().toString(); } return str; }
當然,大佬也可以自己寫邏輯反轉
/** * 自己實現 * @param str * @return */ public static String reverseString(String str) { if (str != null && str.length() > 0) { int len = str.length(); char[] chars = new char[len]; for (int i = len - 1; i >= 0; i--) { chars[len - 1 - i] = str.charAt(i); } return new String(chars); } return str; }
10.String 類的常用方法都有那些?
- indexOf():返回指定字符的索引。
- charAt():返回指定索引處的字符。
- replace():字符串替換。
- trim():去除字符串兩端空白。
- split():分割字符串,返回一個分割后的字符串數組。
- getBytes():返回字符串的 byte 類型數組。
- length():返回字符串長度。
- toLowerCase():將字符串轉成小寫字母。
- toUpperCase():將字符串轉成大寫字符。
- substring():截取字符串。
- equals():字符串比較。
11.抽象類必須要有抽象方法嗎?
當然是不必須。
- 抽象類必須有關鍵字abstract來修飾。
- 抽象類可以不含有抽象方法
- 如果一個類包含抽象方法,則該類必須是抽象類
12.普通類和抽象類有哪些區別?
關鍵點:abstract修飾符(抽象方法)、具體實現過程、實例化、子類實現父類的抽象方法
- 普通類中不可含有抽象方法,可以被實例化;
- 抽象類,則抽象類中所有的方法自動被認為是抽象方法,沒有實現過程(這一點在java8已經改了,抽象類可以有實現,具體可以去了解java8的新特性,也是經常被問的噢),不可被實例化;抽象類的子類,除非也是抽象類,否則必須實現該抽象類聲明的方法
13.抽象類能使用 final 修飾嗎?
這里就要參考第4題了,如果這題不會答,說明第4題沒搞明白。
答案是明顯不行的,抽象類是要被繼承的,如果被final修飾了,就沒法繼承了。
14.接口和抽象類有什么區別?
這個被問到的頻率也很高
15.java 中 IO 流分為幾種?
數據流是 Java 進行 I/O 操作的對象,它按照不同的標准可以分為不同的類別。
- 按照流的方向主要分為輸入流和輸出流兩大類。
- 數據流按照數據單位的不同分為字節流和字符流。
- 按照功能可以划分為節點流和處理流。
所有輸入流類都是 InputStream 抽象類(字節輸入流)和 Reader 抽象類(字符輸入流)的子類。
所有輸出流類都是 OutputStream 抽象類(字節輸出流)和 Writer 抽象類(字符輸出流)的子類。
16.BIO、NIO、AIO 有什么區別?
這題自己去查吧,博主現在不想弄這個題的答案,哈哈哈哈
17.Files的常用方法都有哪些?
Files.exists() //檢測文件路徑是否存在 Files.createFile()//創建文件 Files.createDirectory()//創建文件夾 Files.delete() //刪除文件或者目錄 Files.copy() //復制文件 Files.move() //移動文件 Files.size()//查看文件個數 Files.read() //讀取文件 Files.write()//寫入文件
二、容器(集合)
圖片轉載自https://blog.csdn.net/qq_35771266/article/details/97156939
18.java 容器都有哪些?
此題答案從上圖中找
19.Collection 和 Collections 有什么區別?
- Collcetion是一個集合接口,它提供了對集合對象進行基本操作的通用接口方法。實現該接口的類主要有List和Set,該接口的設計目標是為各種具體的集合提供最大化的統一操作方式。
- Collections是針對集合類的一個包裝類(工具類),它提供了一系列的靜態方法以實現對各種集合的搜索、排序、線程安全化等操作,其中大多數方法都是用來處理線性表。 Collections類不能實例化,如同一個工具類,服務於Collection。若是在使用Collections類的方法時候,對應的collection的對象為null,則這些方法都會拋出 NullPointerException 。之前我們見到的包裝類還有Arrays,它是為數組提供服務的。
20.List、Set、Map 之間的區別是什么?
這個題比較復雜,要說的東西非常的多這里就簡單的羅列下他們的主要區別,后續有空了再詳細介紹。
首先list與set都繼承於Collection,list序列的形式存儲元素。所以取出來的順序可能和放入順序不同。set的特點是無法存放重復的元素。map一個映射不能包含重復的鍵;每個鍵最多只能映射一個值。以鍵值對存放數據以上三個都是接口且不能被實例化。
List:
1.可以允許重復的對象。
2.可以插入多個null元素。
3.是一個有序容器,保持了每個元素的插入順序,輸出的順序就是插入的順序。
4.常用的實現類有 ArrayList、LinkedList 和 Vector。ArrayList 最為流行,它提供了使用索引的隨意訪問,而 LinkedList 則對於經常需要從 List 中添加或刪除元素的場合更為合適。
Set:
1.不允許重復對象
2. 無序容器,你無法保證每個元素的存儲順序,TreeSet通過 Comparator 或者 Comparable 維護了一個排序順序。
3. 只允許一個 null 元素
4.Set 接口最流行的幾個實現類是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基於 HashMap 實現的 HashSet;TreeSet 還實現了 SortedSet 接口,因此 TreeSet 是一個根據其 compare() 和 compareTo() 的定義進行排序的有序容器。
map:
1.Map不是collection的子接口或者實現類。Map是一個接口。
2.Map 的 每個 Entry 都持有兩個對象,也就是一個鍵一個值,Map 可能會持有相同的值對象但鍵對象必須是唯一的。
3. TreeMap 也通過 Comparator 或者 Comparable 維護了一個排序順序。
4. Map 里你可以擁有隨意個 null 值但最多只能有一個 null 鍵。
5.Map 接口最流行的幾個實現類是 HashMap、LinkedHashMap、Hashtable 和 TreeMap。(HashMap、TreeMap最常用)
21.HashMap 和 Hashtable 有什么區別?
HashMap和Hashtable是一組相似的鍵值對集合,它們的區別也是面試常被問的問題之一,我這里簡單總結一下HashMap和Hashtable主要的2個區別:
1、Hashtable是線程安全的,Hashtable所有對外提供的方法都使用了synchronized,也就是同步(所以性能上會比HashMap稍微慢一點),而HashMap則是線程非安全的
2、Hashtable不允許空的key和value,空的value將導致空指針異常,而HashMap則無所謂,沒有這方面的限制,可以允許有一個空的key,value可以允許有多個。
22.如何決定使用 HashMap 還是 TreeMap?
TreeMap<K,V>的Key值是要求實現java.lang.Comparable,所以迭代的時候TreeMap默認是按照Key值升序排列的;TreeMap的實現也是基於紅黑樹結構。
而HashMap<K,V>的Key值實現散列hashCode(),分布是散列的均勻的,不支持排序,數據結構主要是桶(數組),鏈表或紅黑樹。
所以,查詢的時候使用HashMap,增加、快速創建的時候使用TreeMap。
23.說一下 HashMap 的實現原理?
這題直接參閱博主的另一篇文章吧,弄懂那個,hashmap的面試基本能夠應對,此處不再贅述。https://www.cnblogs.com/hwtnet/p/12083440.html
24.說一下 HashSet 的實現原理?
25.ArrayList 和 LinkedList 的區別是什么?
1.ArrayList是實現了基於動態數組的數據結構,LinkedList基於鏈表的數據結構。
2.對於隨機訪問get和set,ArrayList覺得優於LinkedList,因為LinkedList要移動指針。
3.對於新增和刪除操作add和remove,LinedList比較占優勢,因為ArrayList要移動數據。
有可能還會被問到,當在ArrayList 和 LinkedList最后面插入一個元素的時候,誰的效率更高。回答ArrayList就可以了 。原因是ArrayList大概率不需要擴容(如果遇到需要擴容,那就不好說了),直接增加就行了,但是 LinkedList需要New一個Node對象來存放新元素,所以會比較慢。還有一種問法,同樣是在尾部添加元素,就是當數據量在千萬級別以下的時候,而且誰的效率高。大部分時候是LinkedList高,但當數據量超過千萬以后,ArrayList 效率明顯高於LinkedList,原因是當數據量大的時候,new一個對象的時間明顯大於擴容的時間,那么就會出現ArrayList的效率比LinkedList高了。
26.如何實現數組和 List 之間的轉換?
直接上代碼吧,列出幾種最簡單以及最常見的方式,應該都看的懂
數組轉list
public class ArrayToList { public static void main(String[] args) { //數組轉list String[] str=new String[] {"hello","world"}; //方式一:使用for循環把數組元素加進list,最原始的方法 List<String> list=new ArrayList<String>(); for (String string : str) { list.add(string); } System.out.println(list); //方式二: 最簡單以及博主最推薦的方法 List<String> list2=new ArrayList<String>(Arrays.asList(str)); System.out.println(list2); //方式三:使用Collections.addAll() List<String> list3=new ArrayList<String>(str.length); Collections.addAll(list3, str); System.out.println(list3); } }
List轉數組
public class ListToArray { public static void main(String[] args) { //list轉數組 List<String> list=new ArrayList<String>(); list.add("hello"); list.add("world"); //方式一:使用for循環 String[] str1=new String[list.size()]; for(int i=0;i<list.size();i++) { str1[i]=list.get(i); } for (String string : str1) { System.out.println(string); } //方式二:使用toArray()方法 //list.toArray(T[] a); 將list轉化為你所需要類型的數組 String[] str2=list.toArray(new String[list.size()]); for (String string : str2) { System.out.println(string); } } }
27.ArrayList 和 Vector 的區別是什么?
- Vector 是線程安全的,也就是說是它的方法之間是線程同步的,而 ArrayList 是線程不安全的,它的方法之間是線程不同步的
- ArrayList與Vector都有一個初始的容量大小,當需要擴容時,Vector 默認增長為原來兩倍,而 ArrayList 的增長為原來的 1.5 倍。
28.Array 和 ArrayList 有何區別?
Array 長度固定,但是效率非常的高,且只能存放同類型的對象,ArrayList長度動態不固定,但是效率相對較低,可以存放任何類型的對象,每個元素的類型不同都可以。
29.在 Queue 中 poll()和 remove()有什么區別?
30.哪些集合類是線程安全的?
Vector、Hashtable、ConcurrentHashMap(java.util.concurrent包下所有的集合類)、Stack
31.迭代器 Iterator 是什么?
迭代器是一種設計模式,它是一個對象,它可以遍歷並選擇序列中的對象,而開發人員不需要了解該序列的底層結構。迭代器通常被稱為“輕量級”對象,因為創建它的代價小。
32.Iterator 怎么使用?有什么特點?
Java中的Iterator功能比較簡單,並且只能單向移動:
(1) 使用方法iterator()要求容器返回一個Iterator。第一次調用Iterator的next()方法時,它返回序列的第一個元素。注意:iterator()方法是java.lang.Iterable接口,被Collection繼承。
(2) 使用next()獲得序列中的下一個元素。
(3) 使用hasNext()檢查序列中是否還有元素。
(4) 使用remove()將迭代器新返回的元素刪除。
Iterator是Java迭代器最簡單的實現,為List設計的ListIterator具有更多的功能,它可以從兩個方向遍歷List,也可以從List中插入和刪除元素。
33.Iterator 和 ListIterator 有什么區別?
答案見32題
34.怎么確保一個集合不能被修改?
可以使用 Collections. unmodifiableCollection(Collection c) 方法來創建一個只讀集合,這樣改變集合的任何操作都會拋出 Java. lang. UnsupportedOperationException 異常。
List<String> list = new ArrayList<>(); list. add("A"); Collection<String> unmlist = Collections. unmodifiableCollection(list); unmlist. add("B"); // 運行時此行報錯 System. out. println(list.size());
三、多線程
35.並行和並發有什么區別?
(1) 並行是指兩個或者多個事件在同一時刻發生;而並發是指兩個或多個事件在同一時間間隔發生。
(2) 並行是在不同實體上的多個事件,並發是在同一實體上的多個事件。
(3) 在一台處理器上“同時”(這個同時實際上市交替“”)處理多個任務,在多台處理器上同時處理多個任務。如hadoop分布式集群
舉個栗子:
順序執行:你吃飯吃到一半,電話來了,你一直到吃完了以后才去接,這就說明你不支持並發也不支持並行。
並發:你吃飯吃到一半,電話來了,你停了下來接了電話,接完后繼續吃飯,這說明你支持並發。
並行:你吃飯吃到一半,電話來了,你一邊打電話一邊吃飯,這說明你支持並行。此處注意理解:是同時吃,同時說,要真嚴格的說的話,需要2張嘴才是並行。
36.線程和進程的區別?
進程:是執行中一段程序,即一旦程序被載入到內存中並准備執行,它就是一個進程。進程是表示資源分配的的基本概念,又是調度運行的基本單位,是系統中的並發執行的單位。
線程:單個進程中執行中每個任務就是一個線程。線程是進程中執行運算的最小單位。
一個線程只能屬於一個進程,但是一個進程可以擁有多個線程。多線程處理就是允許一個進程中在同一時刻執行多個任務。
37.守護線程是什么?
守護線程,專門用於服務其他的線程的線程。如果其他的線程(即用戶自定義線程)都執行完畢,連main線程也執行完畢,那么jvm就會退出(即停止運行)——此時,連jvm都停止運行了,守護線程當然也就停止執行了
38.創建線程有哪幾種方式?
繼承 Thread 類、實現 Runnable 接口、實現Callable接口,重寫call()方法,通過Runnable實現類使用Thread。
39.說一下 runnable 和 callable 有什么區別?
主要區別
- Runnable 接口 run 方法無返回值;Callable 接口 call 方法有返回值,支持泛型
- Runnable 接口 run 方法只能拋出運行時異常,且無法捕獲處理;Callable 接口 call 方法允許拋出異常,可以獲取異常信息
40.線程有哪些狀態?
41.sleep() 和 wait() 有什么區別?
sleep() 和 wait() 的區別就是 調用sleep方法的線程不會釋放對象鎖,而調用wait() 方法會釋放對象鎖
42.notify()和 notifyAll()有什么區別?
notify(): 喚醒一個正在等待該對象的線程。(隨機喚醒一個)
notifyAll(): 喚醒所有正在等待該對象的線程。
43.線程的 run()和 start()有什么區別?
當你啟動線程,使用start(),系統會把run()方法當成線程執行體來處理,這是正常的,也是正確的情況。但是,當你啟動線程時,調用run()方法,系統run()方法會立即執行,但是這時候系統會把run()方法當成普通的方法,線程對象也當成一個普通對象。我的理解就是,他們都可以讓run方法執行,但是,使用start()方法的話,run()就會被當做線程來使用,直接用run()方法的話,就是個普通方法而已。
44.創建線程池有哪幾種方式?
Executors目前提供了5種不同的線程池創建配置:
- newCachedThreadPool(),它是用來處理大量短時間工作任務的線程池,具有幾個鮮明特點:它會試圖緩存線程並重用,當無緩存線程可用時,就會創建新的工作線程;如果線程閑置時間超過60秒,則被終止並移除緩存;長時間閑置時,這種線程池,不會消耗什么資源。其內部使用SynchronousQueue作為工作隊列。
- newFixedThreadPool(int nThreads),重用指定數目(nThreads)的線程,其背后使用的是無界的工作隊列,任何時候最多有nThreads個工作線程是活動的。這意味着,如果任務數量超過了活動線程數目,將在工作隊列中等待空閑線程出現;如果工作線程退出,將會有新的工作線程被創建,以補足指定數目nThreads。
- newSingleThreadExecutor(),它的特點在於工作線程數目限制為1,操作一個無界的工作隊列,所以它保證了所有的任務都是被順序執行,最多會有一個任務處於活動狀態,並且不予許使用者改動線程池實例,因此可以避免改變線程數目。
- newSingleThreadScheduledExecutor()和newScheduledThreadPool(int corePoolSize),創建的是個ScheduledExecutorService,可以進行定時或周期性的工作調度,區別在於單一工作線程還是多個工作線程。
- newWorkStealingPool(int parallelism),這是一個經常被人忽略的線程池,Java 8 才加入這個創建方法,其內部會構建ForkJoinPool,利用Work-Stealing算法,並行地處理任務,不保證處理順序。
原文鏈接:https://blog.csdn.net/ITzhanghao/article/details/100151997
45.線程池都有哪些狀態?
- RUNNING:這是最正常的狀態,接受新的任務,處理等待隊列中的任務。線程池的初始化狀態是RUNNING。線程池被一旦被創建,就處於RUNNING狀態,並且線程池中的任務數為0。
- SHUTDOWN:不接受新的任務提交,但是會繼續處理等待隊列中的任務。調用線程池的shutdown()方法時,線程池由RUNNING -> SHUTDOWN。
- STOP:不接受新的任務提交,不再處理等待隊列中的任務,中斷正在執行任務的線程。調用線程池的shutdownNow()方法時,線程池由(RUNNING or SHUTDOWN ) -> STOP。
- TIDYING:所有的任務都銷毀了,workCount 為 0,線程池的狀態在轉換為 TIDYING 狀態時,會執行鈎子方法 terminated()。因為terminated()在ThreadPoolExecutor類中是空的,所以用戶想在線程池變為 TIDYING時進行相應的處理;可以通過重載terminated()函數來實現。當線程池在SHUTDOWN狀態下,阻塞隊列為空並且線程池中執行的任務也為空時,就會由 SHUTDOWN -> TIDYING。當線程池在STOP狀態下,線程池中執行的任務為空時,就會由STOP -> TIDYING。
- TERMINATED:線程池處在TIDYING狀態時,執行完terminated()之后,就會由 TIDYING -> TERMINATED。
46.線程池中 submit()和 execute()方法有什么區別?
- execute() 只能執行 Runnable 類型的任務 ;submit() 可以執行 Runnable 和 Callable 類型的任務
- execute() 沒有返回值;而 submit() 有返回值
- submit() 的返回值 Future 調用get方法時,可以捕獲處理異常
47.在 java 程序中怎么保證多線程的運行安全?
- 修改線程模型。即不在線程之間共享該狀態變量。一般這個改動比較大,需要量力而行。
- 將對象變為不可變對象。有時候實現不了。
- 在訪問狀態變量時使用同步,這是最常用的方式。 synchronized和Lock都可以實現同步。簡單點說,就是在你修改或訪問可變狀態時加鎖,獨占對象,讓其他線程進不來。這也算是一種線程隔離的辦法。(這種方式也有不少缺點,比如說死鎖,性能問題等等)
- 其實有一種更好的辦法,就是設計線程安全類。《代碼大全》就有提過,問題解決得越早,花費的代價就越小。具體怎么實現大家自己去問度娘吧,這里不贅述。
48.多線程鎖的升級原理是什么?
- 在所有的鎖都啟用的情況下線程進入臨界區時會先去獲取偏向鎖,如果已經存在偏向鎖了,則會嘗試獲取輕量級鎖,啟用自旋鎖,如果自旋也沒有獲取到鎖,則使用重量級鎖,沒有獲取到鎖的線程阻塞掛起,直到持有鎖的線程執行完同步塊;
- 偏向鎖是在無鎖爭用的情況下使用的,也就是在當前線程沒有執行完之前,沒有其它線程會執行該同步塊,一旦有了第二個線程的爭用,偏向鎖就會升級為輕量級鎖,如果輕量級鎖自旋到達閾值后,沒有獲取到鎖,就會升級為重量級鎖;如果線程爭用激烈,那么應該禁用偏向鎖。
49.什么是死鎖?
死鎖,簡單來講,就是多個線程相互等待對方的資源而進入循環等待的一種狀態。栗子:線程1已經持有鎖A,要去獲取鎖B,線程2已經持有鎖B,要去獲取鎖A,即兩個線程都在等待獲取對方持有的鎖。
50.怎么防止死鎖?
- 避免多次鎖定。盡量避免同一個線程對多個 Lock 進行鎖定。例如上面的死鎖程序,主線程要對 A、B 兩個對象的 Lock 進行鎖定,副線程也要對 A、B 兩個對象的 Lock 進行鎖定,這就埋下了導致死鎖的隱患。
- 具有相同的加鎖順序。如果多個線程需要對多個 Lock 進行鎖定,則應該保證它們以相同的順序請求加鎖。比如上面的死鎖程序,主線程先對 A 對象的 Lock 加鎖,再對 B 對象的 Lock 加鎖;而副線程則先對 B 對象的 Lock 加鎖,再對 A 對象的 Lock 加鎖。這種加鎖順序很容易形成嵌套鎖定,進而導致死鎖。如果讓主線程、副線程按照相同的順序加鎖,就可以避免這個問題。
- 使用定時鎖。程序在調用 acquire() 方法加鎖時可指定 timeout 參數,該參數指定超過 timeout 秒后會自動釋放對 Lock 的鎖定,這樣就可以解開死鎖了。
- 死鎖檢測。死鎖檢測是一種依靠算法機制來實現的死鎖預防機制,它主要是針對那些不可能實現按序加鎖,也不能使用定時鎖的場景的。
總的來說,知道了產生死鎖的幾大特性,然后去破壞這些特性中的任意一種就可以解決死鎖的問題。
51.ThreadLocal 是什么?有哪些使用場景?
ThreadLocal 是線程本地存儲,在每個線程中都創建了一個 ThreadLocalMap 對象,每個線程可以訪問自己內部 ThreadLocalMap 對象內的 value。
經典的使用場景是為每個線程分配一個 JDBC 連接 Connection。這樣就可以保證每個線程的都在各自的 Connection 上進行數據庫的操作,不會出現 A 線程關了 B線程正在使用的 Connection; 還有 Session 管理 等問題。
52.說一下 synchronized 底層實現原理?
從字節碼中可知同步語句塊的實現使用的是monitorenter 和 monitorexit 指令,其中monitorenter指令指向同步代碼塊的開始位置,monitorexit指令則指明同步代碼塊的結束位置,當執行monitorenter指令時,當前線程將試圖獲取 objectref(即對象鎖) 所對應的 monitor 的持有權,當 objectref 的 monitor 的進入計數器為 0,那線程可以成功取得 monitor,並將計數器值設置為 1,取鎖成功。如果當前線程已經擁有 objectref 的 monitor 的持有權,那它可以重入這個 monitor (關於重入性稍后會分析),重入時計數器的值也會加 1。倘若其他線程已經擁有 objectref 的 monitor 的所有權,那當前線程將被阻塞,直到正在執行線程執行完畢,即monitorexit指令被執行,執行線程將釋放 monitor(鎖)並設置計數器值為0 ,其他線程將有機會持有 monitor 。
53.synchronized 和 volatile 的區別是什么?
- volatile本質是在告訴jvm當前變量在寄存器(工作內存)中的值是不確定的,需要從主存中讀取; synchronized則是鎖定當前變量,只有當前線程可以訪問該變量,其他線程被阻塞住。
- volatile僅能使用在變量級別;synchronized則可以使用在變量、方法、和類級別的
- volatile僅能實現變量的修改可見性,不能保證原子性;而synchronized則可以保證變量的修改可見性和原子性
- volatile不會造成線程的阻塞;synchronized可能會造成線程的阻塞。
- volatile標記的變量不會被編譯器優化;synchronized標記的變量可以被編譯器優化
54.synchronized 和 Lock 有什么區別?
- 首先synchronized是java內置關鍵字,在jvm層面,Lock是個java類;
- synchronized無法判斷是否獲取鎖的狀態,Lock可以判斷是否獲取到鎖;
- synchronized會自動釋放鎖(a 線程執行完同步代碼會釋放鎖 ;b 線程執行過程中發生異常會釋放鎖),Lock需在finally中手工釋放鎖(unlock()方法釋放鎖),否則容易造成線程死鎖;
- 用synchronized關鍵字的兩個線程1和線程2,如果當前線程1獲得鎖,線程2線程等待。如果線程1阻塞,線程2則會一直等待下去,而Lock鎖就不一定會等待下去,如果嘗試獲取不到鎖,線程可以不用一直等 待就結束了;
- synchronized的鎖可重入、不可中斷、非公平,而Lock鎖可重入、可判斷、可公平(兩者皆可)
- Lock鎖適合大量同步的代碼的同步問題,synchronized鎖適合代碼少量的同步問題。
55.synchronized 和 ReentrantLock 區別是什么?
- synchronized 競爭鎖時會一直等待;ReentrantLock 可以嘗試獲取鎖,並得到獲取結果
- synchronized 獲取鎖無法設置超時;ReentrantLock 可以設置獲取鎖的超時時間
- synchronized 無法實現公平鎖;ReentrantLock 可以滿足公平鎖,即先等待先獲取到鎖
- synchronized 控制等待和喚醒需要結合加鎖對象的 wait() 和 notify()、notifyAll();ReentrantLock 控制等待和喚醒需要結合 Condition 的 await() 和 signal()、signalAll() 方法
- synchronized 是 JVM 層面實現的;ReentrantLock 是 JDK 代碼層面實現
- synchronized 在加鎖代碼塊執行完或者出現異常,自動釋放鎖;ReentrantLock 不會自動釋放鎖,需要在 finally{} 代碼塊顯示釋放
PS:補充一個相同點,都可以做到同一線程,同一把鎖,可重入代碼塊。
56.說一下 atomic 的原理?
這題沒什么意思,各位自尋答案吧。
四、反射
57.什么是反射?
58.什么是 java 序列化?什么情況下需要序列化?
59.動態代理是什么?有哪些應用?
60.怎么實現動態代理?
五、對象拷貝
61.為什么要使用克隆?
62.如何實現對象克隆?
63.深拷貝和淺拷貝區別是什么?
六、Java Web
64.jsp 和 servlet 有什么區別?
65.jsp 有哪些內置對象?作用分別是什么?
66.說一下 jsp 的 4 種作用域?
67.session 和 cookie 有什么區別?
68.說一下 session 的工作原理?
69.如果客戶端禁止 cookie 能實現 session 還能用嗎?
70.spring mvc 和 struts 的區別是什么?
71.如何避免 sql 注入?
72.什么是 XSS 攻擊,如何避免?
73.什么是 CSRF 攻擊,如何避免?
七、異常
74.throw 和 throws 的區別?
75.final、finally、finalize 有什么區別?
76.try-catch-finally 中哪個部分可以省略?
77.try-catch-finally 中,如果 catch 中 return 了,finally 還會執行嗎?
78.常見的異常類有哪些?
八、網絡
79.http 響應碼 301 和 302 代表的是什么?有什么區別?
80.forward 和 redirect 的區別?
81.簡述 tcp 和 udp的區別?
82.tcp 為什么要三次握手,兩次不行嗎?為什么?
83.說一下 tcp 粘包是怎么產生的?
84.OSI 的七層模型都有哪些?
85.get 和 post 請求有哪些區別?
86.如何實現跨域?
87.說一下 JSONP 實現原理?
九、設計模式
88.說一下你熟悉的設計模式?
89.簡單工廠和抽象工廠有什么區別?
十、Spring/Spring MVC
90.為什么要使用 spring?
91.解釋一下什么是 aop?
92.解釋一下什么是 ioc?
93.spring 有哪些主要模塊?
94.spring 常用的注入方式有哪些?
95.spring 中的 bean 是線程安全的嗎?
96.spring 支持幾種 bean 的作用域?
97.spring 自動裝配 bean 有哪些方式?
98.spring 事務實現方式有哪些?
99.說一下 spring 的事務隔離?
100.說一下 spring mvc 運行流程?
101.spring mvc 有哪些組件?
102.@RequestMapping 的作用是什么?
103.@Autowired 的作用是什么?
十一、Spring Boot/Spring Cloud
104.什么是 spring boot?
105.為什么要用 spring boot?
106.spring boot 核心配置文件是什么?
107.spring boot 配置文件有哪幾種類型?它們有什么區別?
108.spring boot 有哪些方式可以實現熱部署?
109.jpa 和 hibernate 有什么區別?
110.什么是 spring cloud?
111.spring cloud 斷路器的作用是什么?
112.spring cloud 的核心組件有哪些?
十二、Hibernate
113.為什么要使用 hibernate?
114.什么是 ORM 框架?
115.hibernate 中如何在控制台查看打印的 sql 語句?
116.hibernate 有幾種查詢方式?
117.hibernate 實體類可以被定義為 final 嗎?
118.在 hibernate 中使用 Integer 和 int 做映射有什么區別?
119.hibernate 是如何工作的?
120.get()和 load()的區別?
121.說一下 hibernate 的緩存機制?
122.hibernate 對象有哪些狀態?
123.在 hibernate 中 getCurrentSession 和 openSession 的區別是什么?
124.hibernate 實體類必須要有無參構造函數嗎?為什么?
十三、Mybatis
125.mybatis 中 #{}和 ${}的區別是什么?
126.mybatis 有幾種分頁方式?
127.RowBounds 是一次性查詢全部結果嗎?為什么?
128.mybatis 邏輯分頁和物理分頁的區別是什么?
129.mybatis 是否支持延遲加載?延遲加載的原理是什么?
130.說一下 mybatis 的一級緩存和二級緩存?
131.mybatis 和 hibernate 的區別有哪些?
132.mybatis 有哪些執行器(Executor)?
133.mybatis 分頁插件的實現原理是什么?
134.mybatis 如何編寫一個自定義插件?
十四、RabbitMQ
135.rabbitmq 的使用場景有哪些?
136.rabbitmq 有哪些重要的角色?
137.rabbitmq 有哪些重要的組件?
138.rabbitmq 中 vhost 的作用是什么?
139.rabbitmq 的消息是怎么發送的?
140.rabbitmq 怎么保證消息的穩定性?
141.rabbitmq 怎么避免消息丟失?
142.要保證消息持久化成功的條件有哪些?
143.rabbitmq 持久化有什么缺點?
144.rabbitmq 有幾種廣播類型?
145.rabbitmq 怎么實現延遲消息隊列?
146.rabbitmq 集群有什么用?
147.rabbitmq 節點的類型有哪些?
148.rabbitmq 集群搭建需要注意哪些問題?
149.rabbitmq 每個節點是其他節點的完整拷貝嗎?為什么?
150.rabbitmq 集群中唯一一個磁盤節點崩潰了會發生什么情況?
151.rabbitmq 對集群節點停止順序有要求嗎?
十五、Kafka
152.kafka 可以脫離 zookeeper 單獨使用嗎?為什么?
153.kafka 有幾種數據保留的策略?
154.kafka 同時設置了 7 天和 10G 清除數據,到第五天的時候消息達到了 10G,這個時候 kafka 將如何處理?
155.什么情況會導致 kafka 運行變慢?
156.使用 kafka 集群需要注意什么?
十六、Zookeeper
157.zookeeper 是什么?
158.zookeeper 都有哪些功能?
159.zookeeper 有幾種部署模式?
160.zookeeper 怎么保證主從節點的狀態同步?
161.集群中為什么要有主節點?
162.集群中有 3 台服務器,其中一個節點宕機,這個時候 zookeeper 還可以使用嗎?
163.說一下 zookeeper 的通知機制?
十七、MySql
164.數據庫的三范式是什么?
165.一張自增表里面總共有 7 條數據,刪除了最后 2 條數據,重啟 mysql 數據庫,又插入了一條數據,此時 id 是幾?
166.如何獲取當前數據庫版本?
167.說一下 ACID 是什么?
168.char 和 varchar 的區別是什么?
169.float 和 double 的區別是什么?
170.mysql 的內連接、左連接、右連接有什么區別?
171.mysql 索引是怎么實現的?
172.怎么驗證 mysql 的索引是否滿足需求?
173.說一下數據庫的事務隔離?
174.說一下 mysql 常用的引擎?
175.說一下 mysql 的行鎖和表鎖?
176.說一下樂觀鎖和悲觀鎖?
177.mysql 問題排查都有哪些手段?
178.如何做 mysql 的性能優化?
十八、Redis
179.redis 是什么?都有哪些使用場景?
180.redis 有哪些功能?
181.redis 和 memecache 有什么區別?
182.redis 為什么是單線程的?
183.什么是緩存穿透?怎么解決?
184.redis 支持的數據類型有哪些?
185.redis 支持的 java 客戶端都有哪些?
186.jedis 和 redisson 有哪些區別?
187.怎么保證緩存和數據庫數據的一致性?
188.redis 持久化有幾種方式?
189.redis 怎么實現分布式鎖?
190.redis 分布式鎖有什么缺陷?
191.redis 如何做內存優化?
192.redis 淘汰策略有哪些?
193.redis 常見的性能問題有哪些?該如何解決?
十九、JVM
194.說一下 jvm 的主要組成部分?及其作用?
195.說一下 jvm 運行時數據區?
196.說一下堆棧的區別?
197.隊列和棧是什么?有什么區別?
198.什么是雙親委派模型?
199.說一下類加載的執行過程?
200.怎么判斷對象是否可以被回收?
201.java 中都有哪些引用類型?
202.說一下 jvm 有哪些垃圾回收算法?
203.說一下 jvm 有哪些垃圾回收器?
204.詳細介紹一下 CMS 垃圾回收器?
205.新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么區別?
206.簡述分代垃圾回收器是怎么工作的?
207.說一下 jvm 調優的工具?
208.常用的 jvm 調優的參數都有哪些?
本文題目轉載自https://mp.weixin.qq.com/s/fxHN3t8w04mI9QVJQkM8bA,答案為博主自己整理