Java 面試必備

 1. Object有哪些方法?
clone,實現對象的淺複製。
getClass,final方法,得到運行時類型。
toString,該方法用得比較多,通常子類都有覆蓋。
finalize,該方法用於釋放資源。由於沒法肯定該方法何時被調用,不多使用。
equals,該方法是很是重要的一個方法。通常equals和==是不同的,可是在Object中二者是同樣的。子類通常都要重寫這個方法。
hashCode,該方法用於哈希查找,重寫了equals方法通常都要重寫hashCode方法。這個方法在一些具備哈希功能的Collection中用到。通常必須知足obj1.equals(obj2)==true。能夠推出obj1.hash- Code()==obj2.hashCode(),可是hashCode相等不必定就知足equals。不過爲了提升效率,應該儘可能使上面兩個條件接近等價。
wait,wait方法就是使當前線程等待該對象的鎖,當前線程必須是該對象的擁有者,也就是具備該對象的鎖。wait()方法一直等待,直到得到鎖或者被中斷。wait(long timeout)設定一個超時間隔,若是在規定時間內沒有得到鎖就返回。
notify,該方法喚醒在該對象上等待的某個線程。
notifyAll,該方法喚醒在該對象上等待的全部線程。前端

 2. 類的初始化順序?
Static Field Initial (靜態變量) 
Static Patch Initial (靜態初始化塊) 
Field Initial (變量)
Field Patch Initial (初始化塊)
Structure Initial (構造器)java

 3. Map有哪些實現類?
HashMap無序的
LinkedHashMap 有序的
TreeMap 默認升序。mysql

 4. HashMap的工做原理
HashMap使用數組和鏈表的形式存儲數據。
HashMap基於hashing原理,咱們經過put()和get()方法儲存和獲取對象。當咱們將鍵值對傳遞給put()方法時,它調用鍵對象的hashCode()方法來計算hashcode,讓後找到bucket位置來儲存值對象。當獲取對象時,經過鍵對象的equals()方法找到正確的鍵值對,而後返回值對象。HashMap使用鏈表來解決碰撞問題,當發生碰撞了,對象將會儲存在鏈表的下一個節點中。 HashMap在每一個鏈表節點中儲存鍵值對對象。web

 5. HashMap、HashTable的區別?
HashMap是HashTable的輕量級實現(非線程安全的實現),他們都完成了Map接口。主要的區別有:線程安全性,同步(synchronization),以及速度。redis

 6. 放入HashMap中的類需重寫哪些方法?
使用HashMap,若是key是自定義的類,就必須重寫hashcode()和equals()。算法

 7. ConcurrentHashMap和HashTable的區別?
HashTable(同一把鎖):使用synchronized來保證線程安全,但效率很是低下。當一個線程訪問同步方法時,其餘線程也訪問同步方法,可能會進入阻塞或輪詢狀態,如使用put添加元素,另外一個線程不能使用put添加元素,也不能使用get,競爭會愈來愈激烈效率越低。
ConcurrentHashMap(分段鎖):(鎖分段技術)每一把鎖只鎖容器其中一部分數據,多線程訪問容器裏不一樣數據段的數據,就不會存在鎖競爭,提升併發訪問率。
首先將數據分爲一段一段的存儲,而後給每一段數據配一把鎖,當一個線程佔用鎖訪問其中一個段數據時,其餘段的數據也能被其餘線程訪問。ConcurrentHashMap是由Segment數組結構和HahEntry數組結構組成。Segment是一種可重入鎖ReentrantLock,扮演鎖的角色。HashEntry用於存儲鍵值對數據。一個ConcurrentHashMap裏包含一個Segment數組。Segment的結構和Hashmap相似,是一種數組和鏈表結構,一個Segment包含一個HashEntry數組,每一個HashEntry是一個鏈表結構的元素,每一個Segment守護着一個HashEntry數組裏的元素,當對HashEntry數組的數據進行修改時,必須首先得到對應的Segment。spring

 8. ConcurrentHashMap的併發度是什麼?
ConcurrentHashMap的併發度就是Segment的大小,默認爲16。sql

 9. HashMap、HashTable、ConcurrentHashMap的區別?
HashMap 和 HashTable的父類不一樣,HashMap是AbstMap,HashTable是Dictionary類。
HashMap的初始容量16,HashTable初始容量11。
HashMap擴容機制必須是2的倍數,HashTable不須要。
線程安全性,HashMap線程不安全,HashTable線程安全。
HashMap容許null ,HashTable不容許null。
遍歷方式也不一樣HashMap使用Iterator,HashTableEnumeration
計算hash值的方法不一樣 ConcurrentHashMap也是線程安全的HashMap實現的一種;使用cas操做來修改以保證數據的原子性。數據庫

 10. TCP、UDP的區別?
TCP是面向鏈接的,UDP是面向報文的(即發送的時候不須要創建鏈接)。
TCP是提供可靠服務的,請求有序,UDP盡最大努力交付,不保證服務可靠。
TCP能有擁塞控制,UDP沒有擁塞控制。
TCP是點對點,UDP能夠1對1,1對多,多對1通訊。
TCP首部開銷20字節,UDP只有8。編程

 11. POST、GET的區別?
GET數據傳輸是,只容許ASCII,參數位於URL上,URL最大長度限制2k,重複提交無害,可爲書籤,能夠被緩存,因此安全性差。
POST容許二進制數據使用多重編碼,參數位於請求體重,沒有最大長度限制,提交有害,不可爲書籤也不能被緩存,安全性較高。
POST兩次TCP請求,GET一次TCP請求。

 12. 如何高效安全地刪除一個List中的一個元素?
循環刪除List中多個元素的,應該使用迭代器Iterator方式。

 13. 字節流和字符流的區別和聯繫?
字節流在操做的時候自己是不會用到緩衝區(內存)的,是與文件自己直接操做的,而字符流在操做的時候是使用到緩衝區的。字節流在操做文件時,即便不關閉資源(close方法),文件也能輸出,可是若是字符流不使用close方法的話,則不會輸出任何內容,說明字符流用的是緩衝區,而且可使用flush方法強制進行刷新緩衝區,這時才能在不close的狀況下輸出內容。

 14. 線程安全的含義? 
就是線程同步的意思,就是當一個程序對一個線程安全的方法或者語句進行訪問的時候,其餘的不能再對他進行操做了,必須等到此次訪問結束之後才能對這個線程安全的方法進行訪問。
synchronized修飾的方法或者代碼塊,全部加上synchronized和塊語句,在多線程訪問的時候,同一時刻只能有一個線程可以用。
volatile修飾的變量,線程在每次使用變量的時候,都會讀取變量修改後的最的值。volatile很容易被誤用,用來進行原子性操做。

 15. Thread和Runnable如何使用寫段小代碼
 Thread

public class Example {
	public static void main(String[] args){
		MyThread myThread=new MyThread();
		myThread.start(); 
		while (true){ 
			System.out.println("Main方法在運行");
		}
	}
 }

public class MyThread extends Thread{
	public void run(){                                                                                
		while(true){
			System.out.println("MyThread類的run()方法在運行");
		}
	}
 }

 Runnable

public class Example {
	public static void main(String[] args){
		MyThread myThread=new MyThread(); 
		Thread thread=new Thread(myThread);
		thread.start();
		while (true){
			System.out.println("Main方法在運行");
		}
	} 
} 

public class MyThread implements Runnable{
	public void run(){                                                                                
		while(true){
			System.out.println("MyThread類的run()方法在運行");
		}
	}
}

16. Synchronized和Lock類的區別?
Synchronized
存在層次:是Java的關鍵字,在jvm層面上。
鎖的釋放:以獲取鎖的線程執行完同步代碼,釋放鎖,線程執行發生異常,jvm會讓線程釋放鎖。
鎖的獲取:假設A線程得到鎖,B線程等待。若是A線程阻塞,B線程會一直等待。
鎖狀態:沒法判斷。
鎖類型:可重入、不可中斷、非公平。
性能:少許同步。
Lock
存在層次:是Java的關鍵字,在jvm層面上;Lock是一個類。
鎖的釋放:在finally中必須釋放鎖,否則容易形成線程死鎖。
鎖的獲取:分狀況而定,Lock有多個鎖獲取的方式,具體下面會說道,大體就是能夠嘗試得到鎖,線程能夠不用一直等待。
鎖狀態:能夠判斷。
鎖類型:可重入、可判斷、可公平(二者皆可)。
性能:大量同步。
 
 17. CountDownLatch和CyclicBarrier的區別?
 CountDownLatch
 減計數方式。
 計算爲0時釋放全部等待的線程。
 計數爲0時,沒法重置。
 調用countDown()方法計數減一,調用await()方法只進行阻塞,對計數沒任何影響。
 不可重複利用。
 CyclicBarrier
 加計數方式。
 計數達到指定值時釋放全部等待線程。
 計數達到指定值時,計數置爲0從新開始。
 調用await()方法計數加1,若加1後的值不等於構造方法的值,則線程阻塞。
 可重複利用。
 
 18. ThreadLocal和Executors的用途、原理、用法?
 ThreadLocal是線程的局部變量,是每個線程所單獨持有的,其餘線程不能對其進行訪問。當使用ThreadLocal維護變量的時候爲每個使用該變量的線程提供一個獨立的變量副本,即每一個線程內部都會有一個該變量,這樣同時多個線程訪問該變量並不會彼此相互影響,所以他們使用的都是本身從內存中拷貝過來的變量的副本,這樣就不存在線程安全問題,也不會影響程序的執行性能。
 Executors提供四種線程池:
 newCachedThreadPool建立一個可緩存線程池,若是線程池長度超過處理須要,可靈活回收空閒線程,若無可回收,則新建線程。
 newFixedThreadPool建立一個定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待。
 newScheduledThreadPool建立一個定長線程池,支持定時及週期性任務執行。
 newSingleThreadExecutor建立一個單線程化的線程池,它只會用惟一的工做線程來執行任務,保證全部任務按照指定順序(FIFO,LIFO,優先級)執行。
 
 19. 類的加載過程?
 首先經過一個類的全限定名來獲取此類的二進制字節流;其次將這個字節流所表明的靜態存儲結構轉化爲方法區的運行時數據結構;最後在java堆中生成一個表明這個類的Class對象,做爲方法區這些數據的訪問入口。
 總的來講就是查找並加載類的二進制數據。
 
 20. GC經常使用算法?
 串行收集器(SerialGC)最古老的垃圾回收算法,是之前運行在單核cpu的服務器下的。新生代、老年代都使用串行算法回收。
 並行垃圾回收器(ParallelGC)採用多線程的機制是執行GC操做,因此執行GC過程阻塞時間較短。新生代採用的是並行算法,而老年代依然採用的是串行算法。
 併發標記掃描垃圾回收器(ConcurrentMarkSweep)是應用程序線程和GC線程交替執行。使用的標記-清除算法,併發階段會下降吞吐量。它常常被用在那些對於響應時間要求十分苛刻的應用之上。
 G1收集器垃圾回收器適用於堆內存很大的狀況,他將堆內存分割成不一樣的區域,而且併發的對其進行垃圾回收。G1也能夠在回收內存以後對剩餘的堆內存空間進行壓縮。併發掃描標記垃圾回收器在STW狀況下壓縮內存。G1垃圾回收會優先選擇第一塊垃圾最多的區域。
 
 21. JVM調優步驟
第1步:分析GC日誌及dump文件,判斷是否須要優化,肯定瓶頸問題點;
第2步:肯定JVM調優量化目標;
第3步:肯定JVM調優參數(根據歷史JVM參數來調整);
第4步:調優一臺服務器,對比觀察調優先後的差別;
第5步:不斷的分析和調整,直到找到合適的JVM參數配置;
第6步:找到最合適的參數,將這些參數應用到全部服務器,並進行後續跟蹤。

 22. OOM
 內存泄露:申請使用完的內存沒有釋放,致使虛擬機不能再次使用該內存,此時這段內存就泄露了,由於申請者不用了,而又不能被虛擬機分配給別人用。
 內存溢出:申請的內存超出了JVM能提供的內存大小,此時稱之爲溢出
 jstack、jmap能夠定位到線程堆棧,根據堆棧信息咱們能夠定位到具體代碼,因此它在JVM性能調優中使用得很是多。
 
 23. SpringMVC執行流程及原理?
 用戶發起請求到前端控制器(DispatcherServlet),該控制器會過濾出哪些請求能夠訪問Servlet、哪些不能訪問。就是url-pattern的做用,而且會加載SpringMVC.xml配置文件。
 前端控制器會找處處理器映射器(HandlerMapping),經過HandlerMapping完成url到controller映射的組件,簡單來講,就是將在SpringMVC.xml中配置的或者註解的url與對應的處理類找到並進行存儲,用Map這樣的方式來存儲。
 HandlerMapping有了映射關係,而且找到url對應的處理器,HandlerMapping就會將其處理器(Handler)返回,在返回前,會加上不少攔截器。
 DispatcherServlet拿到Handler後,找到HandlerAdapter(處理器適配器),經過它來訪問處理器,並執行處理器。
 執行處理器會返回一個ModelAndView對象給HandlerAdapter。
 經過HandlerAdapter將ModelAndView對象返回給前端控制器(DispatcherServlet)。
 前端控制器請求視圖解析器(ViewResolver)去進行視圖解析,根據邏輯視圖名解析成真正的視圖(jsp),其實就是將ModelAndView對象中存放視圖的名稱進行查找,找到對應的頁面造成視圖對象,返回視圖對象到前端控制器。
 視圖渲染,就是將ModelAndView對象中的數據放到request域中,用來讓頁面加載數據的。
 
 24. 依賴注入是什麼?
 依賴注入(DependencyInjection)和控制反轉(InversionofControl)是同一個概念。具體含義是:當某個角色(多是一個Java實例,調用者)須要另外一個角色(另外一個Java實例,被調用者)的協助時,在傳統的程序設計過程當中,一般由調用者來建立被調用者的實例。但在Spring裏,建立被調用者的工做再也不由調用者來完成,所以稱爲控制反轉;建立被調用者實例的工做一般由Spring容器來完成,而後注入調用者,所以也稱爲依賴注入。

 25. 用靜態方法寫測試用例時如何獲取服務的實例
 繼承AbstractJUnit4SpringContextTests。
 引入ApplicationContext。
 
 26. Bean注入後執行初始化代碼的途徑
 能夠在XML配置bean時,指定init-method屬性便可。
 須要在須要執行的方法上添加@PostConstruct註解便可。
 
 27. LeftJoin、RightJoin用法與做用?
LeftJoin(左鏈接)返回包括左表中的全部記錄和右表中聯結字段相等的記錄。
RightJoin(右鏈接)返回包括右表中的全部記錄和左表中聯結字段相等的記錄。
InnerJoin(等值鏈接)只返回兩個表中聯結字段相等的行。

 28. MySQL執行計劃是什麼?
 explain
 
 29. 什麼狀況會致使索引失效?
 條件中有or。
 對於多列索引,不是使用的第一部分,則不會使用索引。
 like查詢是以%開頭。
 若是列類型是字符串,那必定要在條件中將數據使用引號引用起來,不然不使用索引。
 
 30. ACID的概念
 原子性(atomicity),就是說這個事務要麼不執行,要麼所有執行,就是上面2條語句,不容許只執行一條而不執行次日語句的狀況發生。
 一致性(consistency),就是說數據庫從一個一致性狀態轉移到另外一個一致性狀態,怎麼理解呢,原子性是表示不容許只執行一條而不執行第二條的狀況發生,那麼一致性就是說要麼第一條第二條都執行成功(所謂執行成功就是對數據庫持久化數據產生了影響),要麼就第一條第二條都執行失敗(都不對數據庫持久化數據產生影響),不容許一條成功,一條失敗的狀況。
 隔離性(isolation)理解隔離性,就是隔離另外一個線程(事務)的操做,好比線程A正在執行這個事務cars_Beijing–,cars_Shanghai++,線程B則正在查詢cars_Beijing和cars_Shanghai的值,隔離性就要保證線程B只能查詢到事務徹底沒有執行或者徹底成功執行的值,不容許線程B查詢到只執行了cars_Beijing–而沒有執行cars_Shanghai++的值。
 持久性(durability),這個比較好理解,就是事務一旦提交,所修改的數據就被持久化,即便掉電也不會丟失。
 
 31. 事務的隔離級別
 未提交讀(readuncommitted),就是不作隔離控制,能夠讀到「髒數據」,好比上面的cars_Beijing–,cars_Shanghai++,這個隔離級別容許其餘線程讀取到只作了cars_Beijing–而沒有作cars_Shanghai++時候的值。顯然這個隔離級別沒有太大意義,現實中沒有人會用,除非這個應用只有讀取,沒有任何寫入。
 提交讀(readcommitted),提交讀就是不容許讀取事務沒有提交的數據,簡單的說,就是上面的cars_Beijing–,cars_Shanghai++,不容許讀取到只作了cars_Beijing–,而沒有作cars_Shanghai++的記錄。這個隔離級別是大多數數據庫(除了mysql)的默認隔離級別。
 可重複讀(repeatableread),什麼是不可重複讀,就是事務A去作cars_Beijing–,cars_Shanghai++以前,事務B啓動了,先讀取了一次事務A要修改的值,這個時候事務A修改了記錄,可是事務B在事務A修改完後又讀取了同一記錄值,顯然,這致使事務B相同的讀取操做卻讀取了不一樣值,這就是不可重複讀。可重複讀就是禁止這種狀況發生,好比對須要修改的數據加排他鎖,事務B須要讀取這個記錄,那麼整個事務B沒有完成以前,都容許事務A啓動。可重複讀的隔離級別是mysql默認的隔離級別。
 可串行化(serialzable),就是多個線程(事務)徹底不併發,串行執行,固然不會有任何隔離問題,顯而易見效率也最低,通常不採用。
 
 32. 單例有哪些實現方式?最安全簡潔是哪一種?
 餓漢模式(線程安全,調用效率高,可是不能延時加載)
 懶漢模式(線程安全,調用效率不高,可是能延時加載)
 雙重檢測鎖模式(因爲JVM底層模型緣由,偶爾會出問題,不建議使用)
 靜態內部類式(線程安全,調用效率高,能夠延時加載)
 枚舉類(線程安全,調用效率高,不能延時加載,能夠自然的防止反射和反序列化調用)
 
 33. Redis有哪些數據結構?
 字符串String、字典Hash、列表List、集合Set、有序集合SortedSet。
 
 34. 使用過Redis分佈式鎖麼,它是什麼回事?
 先拿setnx來爭搶鎖,搶到以後,再用expire給鎖加一個過時時間防止鎖忘記了釋放。set指令有很是複雜的參數,這個應該是能夠同時把setnx和expire合成一條指令來用的。
 
 35. 假如Redis裏面有1億個key,其中有10w個key是以某個固定的已知的前綴開頭的,若是將它們所有找出來?
 使用keys指令能夠掃出指定模式的key列表。redis的單線程的。keys指令會致使線程阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢復。
 
 36. Redis如何作持久化的?
 bgsave作鏡像全量持久化,aof作增量持久化。由於bgsave會耗費較長時間,不夠實時,在停機的時候會致使大量丟失數據,因此須要aof來配合使用。在redis實例重啓時,會使用bgsave持久化文件從新構建內存,再使用aof重放近期的操做指令來實現完整恢復重啓以前的狀態。
 
 37. bgsave的原理是什麼?
 fork和cow。fork是指redis經過建立子進程來進行bgsave操做,cow指的是copyonwrite,子進程建立後,父子進程共享數據段,父進程繼續提供讀寫服務,寫髒的頁面數據會逐漸和子進程分離開來。
 
 38. 是否使用過Redis集羣,集羣的原理是什麼?
 RedisSentinal着眼於高可用,在master宕機時會自動將slave提高爲master,繼續提供服務。
 RedisCluster着眼於擴展性,在單個redis內存不足時,使用Cluster進行分片存儲。
 
 39. Redis的同步機制?
 Redis可使用主從同步,從從同步。第一次同步時,主節點作一次bgsave,並同時將後續修改操做記錄到內存buffer,待完成後將rdb文件全量同步到複製節點,複製節點接受完成後將rdb鏡像加載到內存。加載完成後,再通知主節點將期間修改的操做記錄同步到複製節點進行重放就完成了同步過程。
 
 40. Dubbo默認使用的是什麼通訊框架?
 Netty
 
 41. Dubbo的序列化?
 dubbo序列化,阿里尚不成熟的java序列化實現。
 hessian2序列化:hessian是一種跨語言的高效二進制的序列化方式,但這裏實際不是原生的hessian2序列化,而是阿里修改過的hessianlite,它是dubboRPC默認啓用的序列化方式。
 json序列化:目前有兩種實現,一種是採用的阿里的fastjson庫,另外一種是採用dubbo中自已實現的簡單json庫,通常狀況下,json這種文本序列化性能不如二進制序列化。
 java序列化:主要是採用JDK自帶的java序列化實現,性能很不理想。
 
 42. Dubbo的調用關係?
 提供者啓動時,向註冊中心註冊本身提供的服務。
 消費者啓動時,向註冊中心訂閱本身所需的服務。
 註冊中心返回提供者地址列表給消費者,若是有變動,註冊中心將基於長鏈接推送變動數據給消費者。
 消費者,從遠程接口列表中,調用遠程接口,dubbo會基於負載均衡算法,選一臺提供者進行調用,若是調用失敗則選擇另外一臺。
 消費者和提供者,在內存中累計調用次數和調用時間,定時每分鐘發送一次統計數據到監控中心。
 
 43. Dubbo中ZooKeeper作註冊中心,若是註冊中心集羣都掛掉,發佈者和訂閱者之間還能通訊麼?
 註冊中心對等集羣,任意一臺宕掉後,會自動切換到另外一臺。
 註冊中心所有宕掉,服務提供者和消費者仍能夠經過本地緩存通信。
 服務提供者無狀態,任一臺宕機後,不影響使用。
 服務提供者所有宕機,服務消費者會沒法使用,並沒有限次重連等待服務者恢復。
 
 44. Dubbo在安全機制方面是如何解決的?
 Dubbo經過Token令牌防止用戶繞過註冊中心直連,而後在註冊中心上管理受權。Dubbo還提供服務黑白名單,來控制服務所容許的調用方。
 
 45. Dubbo超時和重連機制?
 Dubbo啓動時默認有重試機制和超時機制。
 超時機制的規則是若是在必定的時間內,provider沒有返回,則認爲本次調用失敗,重試機制在出現調用失敗時,會再次調用。若是在配置的調用次數內都失敗,則認爲這次請求異常,拋出異常。
 
 46. 幾個經常使用類的區別?
 ArrayList:元素單個,效率高,多用於查詢。
 Vector:元素單個,線程安全,多用於查詢。
 LinkedList:元素單個,多用於插入和刪除。
 HashMap:元素成對,元素可爲空。
 HashTable:元素成對,線程安全,元素不可爲空。
 
 47. IO與NIO的區別?
 NIO即NewIO,這個庫是在JDK1.4中才引入的。NIO和IO有相同的做用和目的,但實現方式不一樣,NIO主要用到的是塊,因此NIO的效率要比IO高不少。在JavaAPI中提供了兩套NIO,一套是針對標準輸入輸出NIO,另外一套就是網絡編程NIO。
 IO:面向流,阻塞IO。
 NIO:面向緩衝,非阻塞IO。
 
 48. TCP/IP協議三次握手?
 第一次握手:創建鏈接時,客戶端發送syn包(syn=j)到服務器,並進入SYN_SEND狀態,等待服務器確認;SYN:同步序列編號(SynchronizeSequenceNumbers)。
 第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時本身也發送一個SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態。
 第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此包發送完畢,客戶端和服務器進入ESTABLISHED狀態,完成三次握手。
 完成三次握手,客戶端與服務器開始傳送數據。
 
 49. SpringBoot是什麼?
 用來簡化Spring應用的初始搭建以及開發過程,使用特定的方式來進行配置(properties或yml文件)
 建立獨立的Spring引用程序main方法運行。
 嵌入的Tomcat無需部署war文件。
 簡化Maven配置。
 自動配置Spring添加對應功能Starter自動化配置。
 
 50. SpringBoot經常使用的Starter有哪些?
 spring-boot-starter-web:tomcat和web開發須要servlet與jsp支持。
 spring-boot-starter-data-jpa:數據庫支持。
 spring-boot-starter-data-redis:redis數據庫支持。
 spring-boot-starter-data-solr:solr支持。
 mybatis-spring-boot-starter:第三方的MyBatis集成Starter。
 
 51. SpringBoot自動配置的原理?
 在Spring程序main方法中添加@SpringBootApplication或者@EnableAutoConfiguration會自動去Maven中讀取每一個Starter中的spring.factories文件該文件裏配置了全部須要被建立Spring容器中的bean。
 
 52. SpringBoot讀取配置文件的方式?
 SpringBoot默認讀取配置文件爲application.properties或者是application.yml。
 
 53. SpringBoot集成MyBatis的過程?
 添加MyBatis的依賴:

<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>`

 54. MySQL數據庫引擎MYISAM和INNODB區別?
 **InnoDB**
 具備事務(commit)、回滾(rollback)。
 支持外鍵。
 InnoDB中不保存表的具體行數,獲取行數全表掃描。
 支持行鎖。
 適用於須要事務支持的場景。
 **MyISAM**
 不具備事務(commit)、回滾(rollback)。
 不支持外鍵。
 直接獲取行數。
 不支持行鎖,插入和更新鎖全表讀多寫少,而且不須要事務支持的場景。
 
 55. 哪些狀況FullGC?
 SystemGC。
 老年代空間不足。
 永久代空間不足。
 MinorGC晉升大小大於老年代剩餘大小。
 堆中分配大對象,老年代裝不下的時候。
 CMS出發FullGC的兩種狀況,年輕代晉升老年代沒有足夠的連續空間,或者在CMS併發收集未完成以前老年代就已經滿了。
 
 56. Tomcat調優方案?
 **工做方式選擇**
 爲了提高性能,首先就要對代碼進行動靜分離,讓Tomcat只負責jsp文件的解析工做。如採用Apache和Tomcat的整合方式,他們之間的鏈接方案有三種選擇,JK、http_proxy和ajp_proxy。相對於JK的鏈接方式,後兩種在配置上比較簡單的,靈活性方面也一點都不遜色。但就穩定性而言不像JK這樣久經考驗,因此建議採用JK的鏈接方式。
 **Connector鏈接器的配置**
 以前文件介紹過的Tomcat鏈接器的三種方式:bio、nio和apr,三種方式性能差異很大,apr的性能最優,bio的性能最差。而Tomcat7使用的Connector默認就啓用的Apr協議,但須要系統安裝Apr庫,不然就會使用bio方式。
 **配置文件優化**
 默認配置下,Tomcat會爲每一個鏈接器建立一個綁定的線程池(最大線程數200),服務啓動時,默認建立了5個空閒線程隨時等待用戶請求。
 **JVM優化**
 Tomcat啓動命令行中的優化參數,就是JVM的優化。Tomcat首先跑在JVM之上的,由於它的啓動其實也只是一個java命令行,首先咱們須要對這個JAVA的啓動命令行進行調優。無論是YGC仍是FullGC,GC過程當中都會對致使程序運行中中斷,正確的選擇不一樣的GC策略,調整JVM、GC的參數,能夠極大的減小因爲GC工做,而致使的程序運行中斷方面的問題,進而適當的提升Java程序的工做效率。可是調整GC是以個極爲複雜的過程,因爲各個程序具有不一樣的特色,如:web和GUI程序就有很大區別(Web能夠適當的停頓,但GUI停頓是客戶沒法接受的),並且因爲跑在各個機器上的配置不一樣(主要cup個數,內存不一樣),因此使用的GC種類也會不一樣。
 
 57. 有三個線程T1 T2 T3,如何保證他們按順序執?
> public class TestJoin {
>    public static void main(String[] args) throws InterruptedException {
>        final Thread t1 = new Thread(new Runnable() {
>            public void run() {
>                System.out.println(Thread.currentThread().getName() + " run 1");
>            }
>        }, "T1");
>        final Thread t2 = new Thread(new Runnable() {
>            public void run() {
>                System.out.println(Thread.currentThread().getName() + " run 2");
>                try {
>                    t1.join(10);
>                } catch (InterruptedException e) {
>                    e.printStackTrace();
>                }
>            }
>        }, "T2");
>        final Thread t3 = new Thread(new Runnable() {
>            public void run() {
>                System.out.println(Thread.currentThread().getName() + " run 3");
>                try {
>                    t2.join(10);
>                } catch (InterruptedException e) {
>                    e.printStackTrace();
>                }
>            }
>        }, "T3");
>        //method1
>        //t1.start();
>        //t2.start();
>        //t3.start();
>        //method 2 使用 單個任務的線程池來實現。保證線程的依次執行
>        ExecutorService executor = Executors.newSingleThreadExecutor();
>        executor.submit(t1);
>        executor.submit(t2);
>        executor.submit(t3);
>        executor.shutdown();
>    }
>}

 58. 緩存優化  緩存雪崩:  多是由於數據未加載到緩存中,或者緩存同一時間大面積的失效,從而致使全部請求都去查數據庫,致使數據庫CPU和內存負載太高,甚至宕機。解決思路:加鎖計數(即限制併發的數量,能夠用semphore)或者起必定數量的隊列來避免緩存失效時大量請求併發到數據庫。但這種方式會下降吞吐量。分析用戶行爲,而後失效時間均勻分佈。或者在失效時間的基礎上再加1~5分鐘的隨機數。若是是某臺緩存服務器宕機,則考慮作主備。  緩存穿透:  指用戶查詢數據,在數據庫沒有,天然在緩存中也不會有。這樣就致使用戶查詢的時候,在緩存中找不到,每次都要去數據庫中查詢。解決思路:若是查詢數據庫也爲空,直接設置一個默認值存放到緩存,這樣第二次到緩衝中獲取就有值了,而不會繼續訪問數據庫。設置一個過時時間或者當有值的時候將緩存中的值替換掉便可。能夠給key設置一些格式規則,而後查詢以前先過濾掉不符合規則的Key。  緩存併發:  若是網站併發訪問高,一個緩存若是失效,可能出現多個進程同時查詢DB,同時設置緩存的狀況,若是併發確實很大,這也可能形成DB壓力過大,還有緩存頻繁更新的問題。解決思路:對緩存查詢加鎖,若是KEY不存在,就加鎖,而後查DB入緩存,而後解鎖;其餘進程若是發現有鎖就等待,而後等解鎖後返回數據或者進入DB查詢。  緩存預熱:  目的就是在系統上線前,將數據加載到緩存中。解決思路:數據量不大的話,在系統啓動的時候直接加載。本身寫個簡單的緩存預熱程序。    59. 緩存算法  FIFO算法:First in First out,先進先出。原則:一個數據最早進入緩存中,則應該最先淘汰掉。也就是說,當緩存滿的時候,應當把最早進入緩存的數據給淘汰掉。  LFU算法:Least Frequently Used,最不常用算法。  LRU算法:Least Recently Used,近期最少使用算法。  LRU和LFU的區別。LFU算法是根據在一段時間裏數據項被使用的次數選擇出最少使用的數據項,即根據使用次數的差別來決定。而LRU是根據使用時間的差別來決定的。    60. 高併發、大流量處理及解決方法?  擴容、動靜分離、緩存、服務降級和限流。  **限流的經常使用算法和實踐思路**  令牌桶算法:  主要限制流量的流入速率,容許出現必定程度的突發流量。 每秒會有r個令牌按照固定速率放入桶中。桶的容量是固定不變的,若是桶滿了再放入令牌,則溢出。若桶中的可用令牌不足,則改請求會被進行限流處理(被拋棄或緩存)。 漏桶算法: 主要限制流量的流出速率,而且流出速率是固定不變的  能夠以任意速率向桶中流入水滴。桶的容量是固定不變的,若是桶滿了則溢出。按照固定的速率從桶中流出水滴。 計數器算法: 生產環境中的商品搶購可使用,具體不一樣的sku限流規則配置在配置中心內,支持動態更改。可搶購次數的扣減操做,既能夠用redis,也能夠用JVM。若是是集羣而且選擇用JVM,則要根據總併發數量除以集羣數量,得出單臺機器的併發數。(好比總併發數5000,集羣機器10臺,則每臺機器的併發爲5000/10=500)。 **高併發讀需求** 對於一件搶購商品的流量來講,由於key是同一個,因此流量必然會都引入到同一個redis緩存節點中,這時就容易出現單點故障。所以有下面兩種解決方式:在每一個master節點都掛slave從節點,當主節點掛了能夠自動頂上。多級Cache方案,多用LocalCache來過濾掉一部分流量。  本地緩存通常只緩存一些熱點商品數據,緩存內容通常是商品詳情和商品庫存。  本地緩存跟分佈式緩存的同步通常有兩種方式:一種是定時主動拉取更新策略。這種會存在必定時間的不一致,要視業務狀況而定,例如庫存,暫時的不一致致使超賣,單到真正下單的時候還會再進行庫存的判斷,因此影響較小,能夠接受。這種方式要注意關掉緩存的定時失效,防止當用戶流量忽然過大,都到分佈式緩存中拉取數據;第二種方式是每次商品更新,都發佈一個消息,訂閱此消息的節點監聽到後再更新本地緩存的內容。 **熱點自動發現方案** 能夠將交易系統產生的相關數據,以及在上游系統中埋點上報的相關數據異步寫入日誌系統中,而後經過實時熱點自動發現平臺對收集到的日誌數據作調用次數統計和熱點分析。數據符合熱點條件後,就當即通知交易系統作好熱點保護。 **Redis使用watch命令實現高併發搶購需求** 通常高併發這裏,不用悲觀鎖,會迅速增長系統資源;而使用隊列,容易形成請求堆積,內存效果過快。因此通常使用樂觀鎖,能夠用redis的watch命令實現。watch命令會監視給定的key,當exec時,若是監視的key從調用watch後發生過變化,則事務會失敗。注意watch的能夠是對整個鏈接有效的,事務也同樣。若是鏈接斷開,監視和事務都會被自動清除。固然exec,discard,unwatch命令都會清除鏈接中的全部監視。 **協程(纖程)Fiber** 協程概念:一種用戶態的輕量級線程,其實就是單線程,指定執行整個函數中到一部分而後就先出去執行別的,等條件知足時,協程下次更新幀到了再繼續往下執行。優勢是無需線程上下文切換的開銷,充分開發了單CPU的能力,資源佔用低,適合高併發I/O。缺點也很明顯,就是沒辦法利用多CPU的優點。 框架:Quasar,調度器使用ForkJoinPool來調度這些fiber。Fiber調度器FiberScheduler是一個高效的、work-stealing、多線程的調度器。 場景:服務A平時須要調用其餘服務,但其餘服務在併發高的時候延遲很嚴重。 一開始能夠用httpClient鏈接池+線程池來處理,但若是調用服務的時候延遲過高或者超時,則會致使服務A的吞吐量會特別差。緣由主要是通常一個連接由一個線程來處理,是阻塞的,因此在線程池數有限的狀況下,吞吐量確定上不去。而且當全部線程都I/O阻塞的時候,會很浪費CPU資源,而且CPU會一直作無用的上下文切換。這時候能夠考慮協程來替換。 **ForkJoinPool線程池** Fork/Join框架是Java7提供了的一個用於並行執行任務的框架,是一個把大任務分割成若干個小任務,最終彙總每一個小任務結果後獲得大任務結果的框架。 工做竊取(work-stealing)算法是Fork/Join框架最重要的特性。通常一個線程會對應一個任務隊列,當處理較快的線程處理完本身的任務以後,就會竊取另一個處理比較慢的線程對應的任務,這時候會存在兩個線程同時處理一個隊列的狀況,因此任務隊列通常使用雙端隊列,被竊取任務線程永遠從雙端隊列的頭部拿任務執行,而竊取任務的線程永遠從雙端隊列的尾部拿任務執行。優勢是充分利用線程進行並行計算,並減小了線程間的競爭。    61. 說說秒殺如何實現的?  核心思路是流量控制和性能優化。  **流量控制**  請求流控:能夠經過前端系統進行攔截,限制最終流入系統的請求數量。  客戶端流控:較爲合適的作法是屏蔽用戶高頻請求,好比在網頁中設置5s一次訪問限制,能夠防止用戶過分刷接口。  Web端流控:常見作法是能夠經過在內存或緩存服務中加入請求訪問信息,來實現訪問量限制。  數據庫存在瓶頸,爲了應對大量的併發請求,使用redis緩存來攔截大量請求,使用redis原子操做incr和decr來確保庫存。  **對此方案優化**  當庫存爲0時,須要在本地緩存中直接關閉標示位,便可以不去訪問Redis。  當扣減庫存以後,可使用異步操做來建立訂單等一系列操做。

相關文章
相關標籤/搜索