java開發面試大全刷題整理

題目源自Java團長公衆號,內容我的整理,來源於各大博客,未經容許,不許摘抄,僅供分享,不作商業使用。html

 本分享多數爲淺層知識體系,更爲底層的還請自行多寫寫代碼,如有不對之處,望廣大的人才指點,不喜勿噴,文明交流。前端

 

1、hashcode相等兩個類必定相等嗎?equals呢?相反呢?
不必定相等(不必定至關)。由於在散列表中存在不相等的對象的鍵值對的hash值相同。
equals() 的做用是用來判斷兩個對象是否相等。 equals()定義在JDK的Object.java中。經過判斷兩個對象的地址是否相等(即,是不是同一個對象)來區分它們是否相等。
兩個對象相等,則hashcode相等;hashcode相等,對象不必定相等(兩個對象的hashcode計算出來的散列鍵值對的hash值;兩個不一樣的鍵值對,哈希值相等也就是hash衝突)。
補充:一、不建立類對應的散列表:只是單純的用equals比較兩個對象是否相等。二、會建立類對應的散列表:⑴若兩個對象相等,則hashcode值相等.⑵若兩個對象的hashcode相等,但這兩個對象不必定相等.在散列表中存在不相等的對象的鍵值對的hash值相同。java

2、介紹一下集合框架?
宗介:一個用來表明和操縱集合的統一架構。包含如下:
一、接口:表明集合的抽象數據類型。容許集合獨立操縱其所表明的細節,面向對象中接口造成一層(簡單理解成service)。
二、實現(類):接口的具體實現。本質是可重複使用的數據結構(簡單理解成impl)。
三、算法:接口的對象裏的方法所執行的一些計算,相似排序等算法。(也稱爲多態,相同的算法在相似的接口上能夠實現不一樣的功能)node

3、hashmap hastable 底層實現什麼區別?hashtable和concurrenthashmap呢?
一、hashmap是異步、速度快、保存null,容許key值爲null、線程不安全;hashtable是同步、速度慢、不容許key值爲null、線程安全(同步線程、悲觀鎖)。
二、hashmap是異步、速度快、保存null,容許key值爲null、線程不安全(併發狀況下可能產生環狀鏈表);concurrenthashmap是異步、速度快、不容許key值爲null、線程安全(採用分段鎖,主幹是segment,繼承了ReentrantLock,是一種可重入鎖。JDK1.8引入紅黑樹概念,即查找時間複雜度爲 O(logn),鏈表長度大於8時轉換爲紅黑樹)。
補充:concurrentHashmap在8先後的變化,segment從桶結構的線性結構變爲基於synchronized的node數組,提升的性能點是從線性到二分。摒棄segment的緣由:一、鎖的粒度(下面補充);二、segment+hashentry的二次hash來實現的快速查找,8以後引入紅黑樹已經知足這方面;三、經過檢測紅黑樹來肯定是否要擴容,減少擴容粒度,提高效率。
鎖粒度:8以後摒棄分段鎖,採用unsafe類的cas自旋賦值+synchronize+lockSupport阻塞來實現高併發(可讀性差),鎖粒度更細,影響更小,併發的效果更好,可是對於動態擴容較差(引入forwardingnode類,併發擴容時其餘線程不會等待,也會參與擴容任務)。
hashmap不安全:hash衝突的時候,會在同一個數組的位置創建鏈表來解決,對鏈表而言,新的節點會添加到頭結點,可是這個實現不是同步的(多線程下多個線程同時訪問一個哈希映射,至少一個線程從結構上修改則必須保證同步)。一、多個線程同時put時,後來的線程會把前面的線程的值給替換掉(A、B同時put,A先B後,這個位置上只會存B的值);二、擴容時,與put機制相似,只有最後一個線程生成的新數據被賦給table變量,其餘線程都會丟失。mysql

4、hashmap和treemap什麼區別?底層數據結構是什麼?
hashmap是基於hash表的map接口實現的,提供了全部可選的映射操做,鍵、值都容許可爲null,但不保證順序;treemap是基於紅黑樹實現的,輸出的結果都是排好序的(由於紅黑樹永遠都出於平衡狀態)。(最根本的區別)
簡單點說,區別就是hashmap是無序的,是基於hash表的;treemap是有序的,基於紅黑樹的。
結構:
hashmap:底層是一個數組,數組中每個元素是一個鏈表。
treemap:底層是一個數組,數組中每個元素是一個紅黑樹。react

5、線程池用過嗎?都有什麼參數?底層如何實現的?
線程池的參數:corePoolSize(核心線程數)、queueCapacity(任務隊列容量)、maxPoolSize(最大線程數)、keepAliveTime(線程空閒時間)、allowCoreThreadTimeout(容許核心線程超時)、rejectedExcutionHandler任務拒絕處理器。
默認值:
* corePoolSize=1
* queueCapacity=Integer.MAX_VALUE
* maxPoolSize=Integer.MAX_VALUE
* keepAliveTime=60s
* allowCoreThreadTimeout=false
* rejectedExecutionHandler=AbortPolicy()
底層實現:一個線程集合workerSet和一個阻塞隊列workQueue。
一、線程池的狀態;二、執行過程;三、任務拒絕策略;四、執行過程當中涉及到的方法。
一、running 111,-1<<count_bits;shutdown 000,0<<count_bits;stop 011,1<<count_bits; tidying 010,2<<count_bits; terminated 100, 3<<count_bits(只寫了高3位,低29位均爲0).大小關係爲1<2<3<4<5,基本遵循線程池從運行到終止。
二、當前線程數 < corePoolSize,來一個任務建立一個線程;corePoolSize <= 當前線程數 < maxPoolSize && queueCapacity沒有滿,每來一個任務,將其添加到緩存隊列中,等待有空閒線程時去執行;corePoolSize <= 當前線程數 < maxPoolSize && queueCapacity已滿,每來一個任務,建立新的線程來處理被添加的任務;當前線程數 > maxPoolSize,再來新的任務時,採起任務拒絕策略進行處理。
三、①AbortPolicy:丟棄任務並拋出異常;②DiscardPolicy:丟棄任務(不拋出異常);③DiscardOldesPolicy:丟棄最前面的任務,從新嘗試執行新進來的任務(並重復操做直到新進來的任務進入線程池);④CallerRunPolicy:由調用線程處理該任務(直接在 execute 方法的調用線程中運行被拒絕的任務;若是執行程序已關閉,則會丟棄該任務)。
四、(1)execute(Runnable command)(提交任務);(2)addwork(Runnable firstTask,boolean core)(添加任務);(3)內部類worker;(4)runwork(Worker w)(執行任務);(5)getTask()(獲取任務);(6)processWorkerExit(Worker w,boolean completedAbruptly)(worker線程退出)。
(參照博客:http://www.cnblogs.com/sxkgeek/p/9343519.html#_label2)linux

6、synchronized和Lock什麼區別?synchronized什麼狀況是對象鎖? 何時是全局鎖?爲何?
區別:
一、Lock是可中斷鎖,Synchronized是不可中斷鎖(在等待獲取鎖過程當中能夠中斷)
二、Lock是可公平可非公平鎖,Synchronized是公平鎖(按等待獲取鎖的線程的等待時間進行獲取,等待時間長的具備優先獲取鎖權利——先到先得即爲公平鎖)
三、Synchronized是jvm層,是java的一個關鍵字;Lock是一個類
四、Synchronized:獲取鎖的線程結束時同步釋放所,線程異常是jvm會讓線程釋放鎖;Lock必須由代碼釋放鎖,否則會形成線程死鎖。
五、Synchronized是悲觀鎖,前一個線程獲取鎖後,以後的線程都必須等待;Lock則分狀況而定,包含了讀寫鎖、公平鎖等(讀鎖爲樂觀鎖,寫鎖爲悲觀鎖)。
使用Synchronized關鍵字處理同步問題有兩種模式,一個是同步代碼塊,一個是同步方法。同步代碼塊必須設置一個須要鎖定的對象,Synchronized鎖定的代碼塊同一時間只容許一個線程進入,這種方式是在方法中攔截,進入到方法中的線程依然能夠是多個,可是隻有一個線程進入被鎖的代碼塊。同步方法就是隻容許一個線程進入到被鎖定的方法中,即爲全局鎖。須要鎖住的是整個代碼段,鎖住多個對象的同一方法,被鎖住的是class類,而不是this。git

7、ThreadLocal 是什麼?底層如何實現?寫一個例子唄?
ThreadLocall的實例表明了一個線程局部的變量,每條線程都只能看到本身的值,並不會意識到其它的線程中也存在該變量。
原理:針對於每個線程建立一份新的對象設置在其中。
底層實現:封裝了ThreadLocalMap集合類來綁定當前線程和變量副本的關係,各個線程獨立而且訪問安全!
設計思想:(1) ThreadLocal僅僅是個變量訪問的入口;(2) 每個Thread對象都有一個ThreadLocalMap對象,這個ThreadLocalMap持有對象的引用;(3) ThreadLocalMap以當前的threadLocal對象爲key,以真正的存儲對象爲value。get()方法時經過threadLocal實例就能夠找到綁定在當前線程上的副本對象。
demo:
private static final ThreadLocal threadSession = new ThreadLocal();
public static Session getSession() throws InfrastructureException {
Session s = (Session) threadSession.get();
try {
if (s == null) {
s = getSessionFactory().openSession();
threadSession.set(s);
}
} catch (HibernateException ex) {
throw new InfrastructureException(ex);
}
return s;
}github

8、volatile的工做原理?
核心思想:當CPU寫數據時,若是發現操做的變量是共享變量,即在其餘CPU中也存在該變量的副本,會發出信號通知其餘CPU將該變量的緩存行置爲無效狀態,所以當其餘CPU須要讀取這個變量時,發現本身緩存中緩存該變量的緩存行是無效的,那麼它就會從內存從新讀取。
volatile能夠保證線程可見性且提供了必定的有序性,可是沒法保證原子性。在JVM底層volatile是採用「內存屏障」來實現的。即1.保證可見性、不保證原子性,2.禁止指令重排序。
相對於Synchronized的輕量級,在某些場合能夠代替synchronized,但不能徹底代替(須要知足兩個條件:一、對變量的寫操做不依賴當前值,二、該變量沒有包含在具備其餘變量的不變式中。)
惟一須要用到volatile的場合是爲了不活性失敗,可是又不想用鎖和同步類。web

9、cas知道嗎?如何實現的?
compare and swap:用於實現多線程同步的原子指令(cas的底層是java -> C++ -> 彙編)。
邏輯執行流程:
一、obj是AtomicInteger對象,經過 JNIHandles::resolve() 獲取obj在內存中OOP實例p
二、根據成員變量value反射後計算出的內存偏移值offset去內存中取指針addr
三、得到更新值x、指針addr、期待值e三個參數後,調用Atomic::cmpxchg(x, addr, e)
四、經過Atomic::cmpxchg(x, addr, e)實現CAS
實現:以cas僞代碼來解釋,比較內存位置p(指針*p)的內容和已知值oldval(當前*p所指向的值),當他們相同時,將newval寫入*p中,若其餘線程在此前已經對*p作了操做則返回false。
將內存塊和給定值比較,相同時將該內存位置的內容修改成新的給定值(保證新值基於最新信息計算),若是改值在同一時間被另外一個線程更新,則寫入失敗。
cas算法的特性:一、由若干條指令組成,用於完成必定功能的過程;二、連續,執行不容許被中斷。(CPU提供了指令執行期間對總線加鎖,加鎖方式爲拉低電位)。無論使用什麼鎖都會有必定的代價,加鎖、釋放鎖、等待、掛起等都會形成性能的損耗。可能會形成ABA問題。

10、請用至少四種寫法寫一個單例模式?
https://www.cnblogs.com/zhaoyan001/p/6365064.html
一、餓漢式(靜態常量)[可用]
public class Singleton {
private final static Singleton INSTANCE = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return INSTANCE;
}
}
二、餓漢式(靜態代碼塊)[可用]
public class Singleton {
private static Singleton instance;
static {
instance = new Singleton();
}
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
三、懶漢式(線程不安全)[不可用]
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
四、懶漢式(線程安全,同步方法)[不推薦用]
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
五、懶漢式(線程安全,同步代碼塊)[不可用]
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
singleton = new Singleton();
}
}
return singleton;
}
}
六、雙重檢查[推薦用]
public class Singleton {
private static volatile Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
七、靜態內部類[推薦用]
public class Singleton {
private Singleton() {}
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
八、枚舉[推薦用]
public enum Singleton {
INSTANCE;
public void whateverMethod() {}
}

11、請介紹一下JVM內存模型?用過什麼垃圾回收器?都說說唄
JVM內存模型分爲哪些區:程序計數器、虛擬機棧、本地方法棧、方法區、堆。
虛擬機的堆做爲主要的垃圾回收場所,分爲年輕代、年老代、永久代,不一樣區域的對象根據不一樣的算法進行垃圾回收,觸發minor gc和full gc來實現垃圾回收(參照阿里五面:JVM自動內存管理,Minor GC與Full GC的觸發機制)。
哪些垃圾回收器:清除(死亡的對象清理)、壓縮(把存活的彙集,放到內存的起始位置,整理內存碎片)、複製(年輕代的兩個survior區的轉移過程)。

12、線上發送頻繁full gc如何處理? CPU 使用率太高怎麼辦?
一、頻繁full gc:首先分析問題:①機器負載是否太高②機器內存的使用狀況是否不平穩③jvm的內存(各區的使用狀況,年輕代、年老代區域的使用)8以後永久代被Meetadata元數據區替代。
①調整機器負載。
②垃圾回收算法會將eden區的對象往survior區轉移,若是這兩個區(使用狀況不超過70%即爲正常)過小的話會常常發生minor gc,致使對象不斷的往年老代寫入,不斷觸發fullgc;若是是old區的對象再也不被回收多是內存泄漏的緣由(1秒1次的gc基本就是內存泄漏致使的了)。
③補充:full gc先後java堆大小的變化,是否會是xms的值的緣由(默認值爲物理內存的1/64),每次gc,jvm會根據各類條件自動調節,java堆的取值範圍是(Xms,Xmx),將Xms修改成Xmx就不會由於所使用的java堆不夠用而進行調節。另外,也有多是程序中不斷調用system.gc致使的。
二、cpu使用率太高:us用戶進程太高(死循環經過阻塞隊列解決——使用阻塞隊列非阻塞方法也可能出現cpu太高;大計算放在後臺或者使用分佈式實現,避免影響用戶)、sy系統進程太高(減小線程數,當線程數與CPU核心數相同時效率最高-不會形成線程切換也不會浪費cpu資源)。

十3、如何定位問題?如何解決說一下解決思路和處理方法
emmmm。。。。。。(雖然很熟悉這一塊,也專門查問題作了近一年,但好像仍是不怎麼會描述呀)

十4、知道字節碼嗎?字節碼都有哪些?Integer x =5,int y =5,比較x =y 都通過哪些步驟?
一、字節碼:java程序經過編譯器編譯成字節碼文件,也就是計算機能夠識別的二進制
二、byte (8位), short (16位), int (32位), long (64-bit位), char(16位無符號Unicode), float(32-bit IEEE 754 單精度浮點型), double (64-bit IEEE 754 雙精度浮點型)
三、①給x、y賦值②取值y③將y的值賦值給x
補充:Integer是int的包裝類,能夠直接比較,java會自動拆包裝,x==y爲true。

十5、講講類加載機制唄,都有哪些類加載器,這些類加載器都加載哪些文件?
jvm的類加載機制有3種:
全盤負責。當一個類加載器負責加載某個Class時,該Class所依賴的和引用的其餘Class也將由該類加載器負責載入。
父類委託。先讓父類加載器試圖加載該Class,只有在父類加載器沒法加載該類時才嘗試從本身的類路徑中加載該類。
緩存機制。緩存機制保證全部加載過的Class都會被緩存,當程序中須要使用某個Class時,類加載器先從緩存區中搜尋該Class,緩存區中不存在該Class對象時,系統纔會讀取該類對應的二進制數據,並將其轉換爲Class對象,存入緩存區中。
有哪些及對應加載的對象類文件:類加載器有4種分別是bootstrapClassLoader (主要加載java核心api) , ExtClassLoaders是擴展類的類加載器,AppClassLoader 程序類加載器,還有一個是用戶繼承ClassLoader重寫的類加載器。

十6、手寫一下類加載Demo
//ExtClassLoader類中獲取路徑的代碼
private static File[] getExtDirs() {
//加載<JAVA_HOME>/lib/ext目錄中的類庫
String s = System.getProperty("java.ext.dirs");
File[] dirs;
if (s != null) {
StringTokenizer st =
new StringTokenizer(s, File.pathSeparator);
int count = st.countTokens();
dirs = new File[count];
for (int i = 0; i < count; i++) {
dirs[i] = new File(st.nextToken());
}
} else {
dirs = new File[0];
}
return dirs;
}

十7、知道osgi嗎? 他是如何實現的?
osgi:open service gateway initiative開放服務網關,以java爲技術平臺的動態模塊化規範。
從概念上能夠分爲三層:模塊層、生命週期層和服務層。
Module Layer:模塊層主要涉及包及共享的代碼;
Lifecycle Layer:生命週期層主要涉及Bundle的運行時生命週期管理;
Service Layer:服務層主要涉及模塊之間的交互和通訊。

模塊化是經過爲Jar包添加metadata 來定義哪些類該暴露,哪些類該隱藏,其控制單元叫作 Bundle(jar 包)。
在OSGi框架中屬於模塊層上面的一層,它的運做是創建在模塊層的功能之上的。主要功能是控制動態安裝、開啓、關閉、更新和卸載的bundles。
一個OSGi 服務就是註冊到 OSGi 框架中的一個 Java 對象。註冊的時候能夠設置這個 Service 的屬性。而在獲取 Service的時候能夠根據屬性進行過濾。


十8、請問你作過哪些JVM優化?使用什麼方法達到什麼效果?
根據不一樣的狀況進行不一樣的調優操做。
一、CPU太高:us用戶進程太高(死循環經過阻塞隊列解決——使用阻塞隊列非阻塞方法也可能出現cpu太高;大計算放在後臺或者使用分佈式實現,避免影響用戶)、sy系統進程太高(減小線程數,當線程數與CPU核心數相同時效率最高-不會形成線程切換也不會浪費cpu資源)。
二、內存消耗太高:使用對象緩存池做爲緩衝、及時釋放沒必要要的對象(另,NIO操做的是物理內存,分配太小的話也會出現內存溢出的狀況且監控堆、棧的內存消耗不大)。
三、磁盤IO太高:增長緩存、採用異步讀寫、採起文件批量讀寫處理(大量線程讀寫同一個文件容易形成磁盤IO飆升)。
四、網絡消耗過大:增長帶寬(java程序通常不會出現網絡I/O的問題)。
五、資源消耗很少但程序運行緩慢:增長分佈式處理,增長併發包減小鎖的競爭;對於必須單線程的使用隊列。(a、鎖競爭激烈;b、單線程過多致使硬件未充分利用;c、大量的分佈式處理,cpu負載低,sql的壓力過大)。
六、未充分利用硬件資源:優化代碼、業務拆分。
另外,對於代碼調優(已達到節約資源的目的):
一、使用局部變量。
二、單線程使用hashmap和ArrayList(避免使用hashtable,下降性能)。
三、在finally塊中釋放資源。
四、經常使用的數據放緩存。
五、內存分配細化。

十9、classforName("java.lang.String")和String classgetClassLoader() LoadClass("java.lang.String") 什麼區別啊?
類裝載過程:加載 => 連接(校驗、準備、解析) => 初始化
classforName("java.lang.String"):返回的是一個類,做用是要求jvm查找並加載指定的類(jvm會執行該類的靜態代碼段)。
String classgetClassLoader() LoadClass("java.lang.String"):
相同:都能在運行時對任意一個類,知道該類的全部屬性和方法;對於任意一個對象,調用他的任意方法和屬性。
區別:Class.forName獲得的class是已經初始化完成的,一旦初始化,就會觸發目標對象的 static塊代碼執行,static參數也也會被再次初始化;而Classloder.loaderClass獲得的class是尚未連接的,不進行連接意味着不進行包括初始化等一些列步驟,那麼靜態塊和靜態對象就不會獲得執行。
補充——數據庫連接使用class.forName(className):使用這個才能在反射回去類的時候執行static塊(附:JDBC源碼)。
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}

二10、探查Tomcat的運行機制及框架?
運行機制:Tomcat其實就是一個servlet的容器:
1:實現Servlet api規範。這是最基礎的一個實現,servlet api大部分都是接口規範。如request、response、session、cookie。爲了咱們應用端能正常使用,容器必須有一套完整實現。
2:啓動Socket監聽端口,等待http請求。
3:獲取http請求,分發請求給不一樣的協議處理器,如http和https在處理上是不同的。
4:封裝請求,構造HttpServletRequest。把socket獲取的用戶請求字節流轉換成java對象httprequest。構造httpResponse。
5:調用(若未建立,則先加載)servlet,調用init初始化,執行servlet.service()方法。
6:爲httpResponse添加header等頭部信息。
7:socket回寫流,返回知足http協議格式的數據給瀏覽器。
8:實現JSP語法分析器,JSP標記解釋器。JSPservlet實現和渲染引擎。
9:JNDI、JMX等服務實現。容器通常額外提供命名空間服務管理。
10:線程池管理,建立線程池,併爲每一個請求分配線程。

tomcat框架:
1、tomcat組成:server、service、connector、protocol、engine、host、context、wrapper組件。參照:https://www.jianshu.com/p/4866852b3462
2、處理過程:
1:Tomcat啓動後,Connector組件的接收器(Acceptor)將會監聽是否有客戶端套接字鏈接並接收Socket。
2:監聽到客戶端鏈接後將鏈接交由線程池Executor處理,開始執行請求響應任務。
3:Http11Processor組件負責從客戶端鏈接中讀取信息報文,解析HTTP的請求行、請求頭部、請求體;將解析後的報文封裝成Request對象,方便後面處理時經過Request對象獲取HTTP協議的相關值。
4:Mapper組件根據HTTP協議請求行的URL屬性值和請求頭部的Host屬性值匹配對應的Servlet;將路由的結果封裝到Request對象中。
5:CoyoteAdaptor組件負責將Connector組件和Engine容器鏈接起來,將Request和Response傳遞到Engine容器,調用它的管道。
6:Engine容器的管道(Pipeline)開始處理請求,管道里包含若干閥門(Valve),每一個閥門負責某些處理邏輯;能夠根據本身的須要往管道中添加自定義的閥門;最後執行基礎閥門EngineValve,負責調用Host容器的管道。
7:Host容器的管道開始處理請求;執行完若干閥門後執行基礎閥門HostValve,調用Context容器的管道。
8:Context容器的管道開始處理請求;執行完若干閥門後執行基礎閥門ContextValve,調用Wrapper容器的管道。
9:Wrapper容器的管道開始處理請求;執行若干閥門後執行基礎閥門WrapperValve,執行該Wrapper容器對應的Servlet對象的處理方法,對請求進行邏輯處理並將結果輸出到客戶端。

二11、分析Tomcat線程模型?
tomcat做爲最經常使用的服務器之一,應用範圍很是廣。支持4種線程模型:BIO、NIO、APR、AIO(tomcat8以後支持)。
一、BIO:阻塞I/O,使用的是傳統的java I/O操做,tomcat7如下版本默認使用BIO運行,每一個請求都要建立一個線程處理,致使線程開銷大,不能高併發,性能最低。
二、NIO:java SE1.4及之後提供的一種新I/O操做,一個機遇緩衝區並能提供非阻塞I/O操做的java api,擁有比BIO更好的併發性能。(tomcat8前在安裝目錄/conf/server.xml修改protocol,從"HTTP/1.1"修改爲"org.apache.coyote.http11.Http11NioProtocol"便可,tomcat8後的默認使用NIO)
三、APR:從操做系統級別解決異步IO問題,大幅度提升服務器的處理和響應性能(tomcat運行高併發的首選)。
四、AIO:Linux異步I/O,基本思想是容許進程發起不少I/O操做,而不用阻塞或等待任何操做完成。(java裏使用與jdk7之後的版本,網上以前的案例不太好查)

tomcat的NIO模型實現方式就是有專門的線程負責IO事件監聽,這些線程有本身的Selector,一旦監聽到有IO讀寫事件,並非像第一種實現方式那樣(本身去執行IO操做),而是將IO操做封裝成一個Runnable交給Worker線程池來執行,這種狀況每一個鏈接可能會被多個線程同時操做,相比第一種併發性提升了,可是也可能引來多線程問題,在處理上要更加謹慎些。通常參數就是Acceptor線程個數,Worker線程個數。(NIO源碼分析:https://yq.aliyun.com/articles/39093)
tomcat的NioEndpoint(下圖:tomcat高併發場景的bug排查圖之一):


二12、Tomcat系統參數認識和調優?
className 官方文檔上說了This MUST be set to org.apache.catalina.valves.AccessLogValve to use the default access log valve小於60; 想訪問日誌這就必須得寫成這樣。
directory 這個東西是日誌文件放置的目錄,在tomcat下面有個logs文件夾,那裏面是專門放置日誌文件的,固然你也能夠修改,我就給改爲了D:
prefix 這個是日誌文件的名稱前綴,個人日誌名稱爲localhost_access_log.2007-09-22.txt,前面的前綴就是這個localhost_access_log
suffix 這就是後綴名啦,能夠改爲別的
pattern 這個是最主要的參數了,具體的我們下面講,這個參數的內容比較豐富。
resolveHosts 若是這個值是true的話,tomcat會將這個服務器IP地址經過DNS轉換爲主機名,若是是false,就直接寫服務器IP地址啦
rotatable 默認爲true,默認的設置使得你的tomcat生成的文件命爲prefix(前綴)+.+時間(通常是按天算)+.+suffix(後綴),參照個人日誌名就知道了:localhost_access_log.2007-09-22.txt。使用這個須要謹慎,由於你將其設置爲false的話,tomcat會忽略時間,不會新生成文件,最後致使你的文件超級大,這樣生成的文件名就是:localhost_access_log.txt
condition 這個參數不太實用,能夠設置任何值,好比我們設置成condition=」tkq」,那麼只有當ServletRequest.getAttribute(「tkq」)爲空的時候,纔會被記錄下來
fileDateFormat 最後的一個參數,很明白,這就是時間格式嘛,可是這個時間格式是針對日誌文件起做用的,還記得我們生成的日誌文件全名麼:localhost_access_log.2007-09-22.txt,這裏面的2007-09-22就是這麼來的,若是你想讓tomcat每小時生成一個日誌文件,也很簡單,將這個值設置爲:fileDateFormat=」yyyy-MM-dd.HH」,固然也能夠按分鐘生成什麼的,本身改改吧

 

 


二十3、MySQL底層B+Tree機制?
由二叉查找樹演變而來,與跳錶結構類似。經過存儲在磁盤的多叉樹結構作到時間、空間的平衡。B+樹的葉子節點使用單鏈表串聯。
B+樹特色:
一、每一個節點中子節點的個數不超過m,不小於m/2(m取決於磁盤數據塊的大小,innoDB的m大小大約爲1200)
二、根節點的子節點個數不超過m/2;
三、m叉樹是存儲索引,不真正存儲數據,相似跳錶;
四、經過鏈表將葉子節點串聯在一塊兒,這一頁能夠方便按區間查找;
五、通常狀況,根節點會被存儲在內存中,其餘節點存儲在磁盤中。
B+樹與B樹的區別:
一、B+樹中的節點不存儲數據,只是索引,而B樹種的節點存儲數據;
二、B樹種的椰子節點並不須要鏈表來串聯。
B+tree的查詢效率比es低:es是基於lucence的倒排索引技術,實現比B+tree更快的過濾數據。


二十5、索引優化詳解?
最左前綴匹配原則,上面講到了
主鍵外鍵必定要建索引
對 where,on,group by,order by 中出現的列使用索引
儘可能選擇區分度高的列做爲索引,區分度的公式是count(distinct col)/count(*),表示字段不重複的比例,比例越大咱們掃描的記錄數越少,惟一鍵的區分度是1,而一些狀態、性別字段可能在大數據面前區分度就是0
對較小的數據列使用索引,這樣會使索引文件更小,同時內存中也能夠裝載更多的索引鍵
索引列不能參與計算,保持列「乾淨」,好比from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,緣由很簡單,b+樹中存的都是數據表中的字段值,但進行檢索時,須要把全部元素都應用函數才能比較,顯然成本太大。因此語句應該寫成create_time = unix_timestamp(’2014-05-29’);
爲較長的字符串使用前綴索引
儘可能的擴展索引,不要新建索引。好比表中已經有a的索引,如今要加(a,b)的索引,那麼只須要修改原來的索引便可
不要過多建立索引, 權衡索引個數與DML之間關係,DML也就是插入、刪除數據操做。這裏須要權衡一個問題,創建索引的目的是爲了提升查詢效率的,但創建的索引過多,會影響插入、刪除數據的速度,由於咱們修改的表數據,索引也須要進行調整重建
對於like查詢,」%」不要放在前面。
SELECT * FROMhoudunwangWHEREunameLIKE'後盾%' -- 走索引
SELECT * FROMhoudunwangWHEREunameLIKE "%後盾%" -- 不走索引
查詢where條件數據類型不匹配也沒法使用索引
字符串與數字比較不使用索引;
CREATE TABLEa(achar(10));
EXPLAIN SELECT * FROM a WHERE a="1" – 走索引
EXPLAIN SELECT * FROM a WHERE a=1 – 不走索引
正則表達式不使用索引,這應該很好理解,因此爲何在SQL中很難看到regexp關鍵字的緣由


二十7、spring都有哪些機制啊?AOP底層如何實現的?IOC呢?
aop、ioc、jdbc、web、webmvc、core、tx、context、beans、orm。
aop底層實現:基於JDK動態代理或者cglib字節碼操縱等技術,運行時動態生成被調用類型的子類等,並實例化代理對象,實際的方法調用會被代理給相應的代理對象。
ioc:Inversion of Control(控制反轉,一種設計思想),ioc將設計好的對象交給容器控制,而不是傳統的在你的對象內部直接控制。一、ioc容器控制對象,控制了外部資源獲取(誰控制誰,控制了什麼)。二、由容器幫咱們查找及注入依賴對象,對象只是被動地接受依賴對象,因此是反轉(爲何反轉);依賴對象的獲取被反轉(哪一個方面反轉了)。由ioc容器幫對象找相應的依賴對象並注入,而不是由對象主動去找。

二十8、cgLib知道嗎?他和jdk動態代理什麼區別?手寫一個jdk動態代理唄?
jdk動態代理是以接口爲中心,至關於添加了一種被調用者沒有太大意義的限制,實例化的是proxy對象,而不是真正的被調用類型,有可能帶來不便和能力退化。
cglib採起的是建立目標類的子類的方式,因爲子類化因此可達到近似使用被調用者自己的效果。
相比於cglib,jdk動態代理一、最小化了依賴關係(意味着簡化開發和維護),jdk自己的支持比cglib更可靠;二、平滑的進行jdk版本升級,而字節碼類庫通常須要進行更新以保證在新版java上能使用;三、代碼實現簡單。
而cglib的優點在於一、不用實現額外接口(對於某些調用目標不變實現額外接口的比較友好,不會有侵入性的實踐);二、只操做咱們關心的類;三、高性能。
public class MyDynamicProxy {
public static void main(String[] args) {
HelloImpl hello = new HelloImpl();
MyInvocationHandler handler = new MyInvocationHandler(hello);
// 構造實例
Hello proxyHello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(),
HelloImpl.class.getInterfaces(), handler);
// 代理方法
proxyHello.sayHello();
}
}
interface Hello {
void sayHello();
}
class HelloImpl implements Hello {
@Override
public void sayHello() {
System.out.println("Hello");
}
}
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Invoking sayHello");
Object result = method.invoke(target, args);
return result;
}
}

二十9、使用mysql索引都有哪些原則? 索引是什麼數據結構? B+tree 和B tree 什麼區別?
原則:一、索引列不能參與計算,保持列「乾淨」;二、選擇惟一性索引;三、爲常常須要排序、分組和聯合操做的字段創建索引;四、爲常做爲查詢條件的字段創建索引;五、限制索引的數目;六、儘可能使用數據量少的索引;七、儘可能使用前綴來索引;八、刪除再也不使用或者不多使用的索引;九、最左前綴匹配原則(重要);十、=和in能夠亂序;十一、儘可能選擇區分度高的列做爲索引;十二、儘可能的擴展索引,不要新建索引。
數據結構:一、散列表;二、有序數組(應用於再也不改變的歷史數據);三、B+樹。
區別:
一、B+樹中的節點不存儲數據,只是索引,而B樹中的節點存儲數據;
二、B樹中的葉子節點並不須要鏈表來串聯。

三10、MySQL有哪些存儲引擎啊?都有啥區別? 要詳細!
一、MyISAM:分爲靜態(適用於數據表的各數據列長度都預先固定)、動態(相比靜態,存儲空間較小,但每條數據的長度不必定。應爲數據存儲的碎片化致使的,須要常用命令和工具對內存碎片進行整理)和壓縮(動靜態的均可以進行壓縮,壓縮後所需空間減少,可是壓縮後數據不能變化,每次讀取需先解壓)。
二、MyISAM Merge引擎:MyISAM的變種,將幾個相同的MyISAM表合併爲一個虛表(應用於日誌和數倉)。
三、InnoDB存儲引擎:對MyISAM的進階版,提供了事物、行級鎖機制和外鍵約束
四、memory(heap):只存在於內存中,使用散列索引,存取很快(應用於臨時表)。對於按區間查找效率較低,時間複雜度爲O(n)。
五、archive:只支持select和insert,不支持索引(常應用於日誌記錄和聚合分析)。

三11、設計高併發系統數據庫層面該怎麼設計?數據庫鎖有哪些類型?如何實現呀?
如何設計:高併發環境下,一、要支持10萬次/秒的更新,首先要對數據庫作分庫分表(單庫表是不可能實現的),以支持數據的存取;二、其次高併發下數據增加快,每次信澤鞥須要獲取一個全局id,自增不太合適,能夠使用squeeze或者snowflake來實現全局惟一id的獲取,在全局id頭部增長其分庫分表信息(即維一鍵,並以維一鍵做爲索引,方便查詢;若是是寫動做頻繁的適合使用惟一索引)。若是當前表的數據相似訂單數據,須要同步到商務表的:一、商務表對實時性要求不高,使用消息隊列來實現,同事引入實時監控,以保證數據的一致性(使用強一致性的分佈式事務效率過低);二、商務標實時要求高的(及在訂單表寫入後會有對商務標進行實時查詢到的,能夠使用redis緩存,只存訂單表-商務表的主鍵索引id)。
類型&實現:
共享鎖:在查詢語句後面增長LOCK IN SHARE MODE,在查詢是添加一個共享鎖表示A在執行查詢,其餘共享鎖能夠繼續獲取,可是排它鎖須要等待。
更新鎖:在語句後面增長(updlock)。
排它鎖:在查詢語句後面增長FOR UPDATE。
意向鎖:不是鎖,是一種意向,也能夠認爲是 行鎖+表鎖,當A對某行數據加了共享鎖後,事務B來獲取該表的排它鎖時發現有共享鎖(意向共享鎖),排它鎖獲取失敗,等待。
計劃鎖:。
Bulk Update Locks:主要在批量導數據時用(好比用相似於oracle中的imp/exp的bcp命令)。

三12、數據庫事務有哪些(特色)?
關於事務,ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔離性、持久性)
當數據庫上有多個事務同時執行的時候,就可能出現髒讀(dirty read)、不可重複讀(non-repeatable read)、幻讀(phantom read)的問題,爲了解決這些問題,就有了「隔離級別」的概念。
事務隔離的級別包含:讀未提交、讀提交、可重複讀、串行化。


三十4、用過哪些分庫分表中間件,有啥優勢和缺點?講一下你瞭解的分庫分表中間件的底層實現原理?
主流:
cobar:分佈式服務的中間件,它可讓傳統的數據庫獲得良好的線性擴展,並看上去仍是一個數據庫,對應用保持透明。
Mycat:在cobar基礎上進行二次開發,解決了cobar當時存在的一些問題,不只僅能夠用做讀寫分離,以及分表分庫、容災管理,並且能夠用於多租戶應用開發、雲平臺基礎設施,讓架構具有很強的適應性和靈活性。
tddl:基於集中式配置的jdbc datasourcce實現,具備主備,讀寫分離,動態數據庫配置等功能,主要解決了分庫分表對應用的透明化以及異構數據庫之間的數據複製。複雜度相對較高,還須要依賴diamond。
DRDS:脫胎於開源的Cobar分佈式數據庫引擎,吸取了Cobar核心的Cobar-Proxy源碼,對應用程序屏蔽各類複雜的底層DB拓撲結構,借鑑TDDL實現了對分佈式Join支持。
Atlas:實現了MySQL的客戶端和服務端協議,做爲服務端與應用程序通信,同時做爲客戶端與MySQL通信。不能實現分佈式分表,沒有自動建表的功能。
DBProxy:美團點評內部基於Atlas改進的,高可靠、高可用企業級數據庫中間件,項目的Github地址是https://github.com/Meituan-Dianping/DBProxy。
sharding-JDBC:從關係型數據庫模塊dd-rdb中分離出來的數據庫水平分片框架,實現透明化數據庫分庫分表訪問,理論上可支持任意實現JDBC規範的數據庫,輕量Java框架,使用客戶端直連數據庫,以jar包形式提供服務,無proxy代理層,無需額外部署,無其餘依賴,DBA也無需改變原有的運維方式。
市場上用的相對較少的:
Heisenberg(baidu):優勢:分庫分表與應用脫離,分庫表如同使用單庫表同樣,減小db鏈接數壓力,熱重啓配置,可水平擴容,遵照MySQL原生協議,讀寫分離,無語言限制,能夠調整採用velocity的分庫分表腳本進行自定義分庫表,至關的靈活。
CDS:一款基於客戶端開發的分庫分表中間件產品,實現了JDBC標準API,支持分庫分表,讀寫分離和數據運維等諸多共,提供高性能,高併發和高可靠的海量數據路由存取服務。
oneProxy:基於mysql官方的proxy思想利用c進行開發的,OneProxy是一款商業收費的中間件, 捨去了一些功能點,專一在性能和穩定性上,高併發下很穩定。
Oceanus(58同城):易上手,分庫分表邏輯再也不與業務緊密耦合,擴容有標準模式,減小意外錯誤的發生。
Vitess(Youtube):使用Vitess應用改動比較大要 使用他提供語言的API接口。架構複雜。
原理(以cobar爲例):Cobar的前、後端模塊都實現了MySQL協議;當接受到SQL請求時,會依次進行解釋(SQL Parser)和路由(SQL Router)工做,而後使用SQL Executor去後端模塊獲取數據集(後端模塊還負責心跳檢測功能);若是數據集來自多個數據源,Cobar則須要把數據集進行組合(Result Merge),最後返回響應。(主要提供水平切分,其原理是根據字段值的一致性Hash分佈進行多維拆分;數據查詢方式,根據where中的拆分字段分發,SQL語句其餘元素的處理,將Cobar收到的SQL語句作變換 分發到各個分庫執行,對執行結果合併、處理 保證返回前端的內容知足語義。)
補充:Cobar採用了主流的Reactor設計模式來處理請求,並使用NIO進行底層的數據交換,這大大提高系統的負載能力。其中,NIOAcceptor用於處理前端請求,NIOConnector則用於管理後端的鏈接,NIOProcessor用於管理多線程事件處理,NIOReactor則用於完成底層的事件驅動機制,就是看起來和Mina和Netty的網絡模型比較類似。

三十6、分佈式事務知道嗎? 大家怎麼解決的?
cap定理:一致性、可用性、分區容錯性。
一、兩階段提交(2PC),使用是XA協議的原理,犧牲一部分可用性來換取一致性。優勢:儘可能保證一致性,適合數據強一致性高的領域(非100%);缺點:實現複雜,犧牲了可用性,性能影響大。
二、TCC(補償事務try-confirm-cancel):t成功,confirm必定成功,cancel主要是在業務執行錯誤,須要回滾的狀態下執行取消,預留資源釋放。實現和流程相對2PC簡單,可是後兩步可能失敗,屬於補償方式。
三、本地消息表(異步確保):生產者建個表,生產者和消費者定是掃描消息表,沒處理的重試。(經典場景)最終實現一致性;但消息表耦合到系統中,可能會有不少雜貨須要處理。
四、MQ事務:rocketMq。
五、sagas:。

三十7、爲何要分庫分表啊?
高併發環境下,若是隻單純支持讀操做的話,要支持10萬次/秒以上的系統並不複雜,經過一致性哈希擴展緩存節點,或者水平擴展web服務器等,可是要支持更新操做的話,單庫表是不可能實現的,獨立數據庫沒法支持大數據下的高併發insert和update。

三十8、RPC通訊原理,分佈式通訊原理
RPC:分爲用戶層、服務層和stub層,客戶端發起一個遠程調用時,經過本地 調用 本地調用方的stub,經過本地的RPCRuntime將網絡包發送給服務端,服務端的RPCRuntime收到請求後交給提供方stub解碼,而後調用服務端方法,服務端執行方法後返回結果,提供方stub把結果編碼後發送給客戶端,客戶端RPCRuntime接收到結果發給調用方stub解碼獲得結果返回客戶端。對於RPCRuntime,主要處理高性能的傳輸,以及網絡的錯誤和異常。
分佈式通訊的基本原理:主要是使用客戶端上的Stub(存根)和遠程對象上的Skeleton(骨架)做爲中介,來實現分佈式通訊的,在客戶端會有一個叫作Stub(存根)的東西,其實現採用的是很是典型的代理模式,是遠程對象在客戶端的代理。Stub會封裝所交互的數據的訪問細節(如何壓縮、壓包、編碼等),而後經過相應的協議與Skeleton(骨架)交換數據,對於Java領域的分佈式通訊技術,較常見的有EJB技術、CORBA技術、WebService技術等等。若是是EJB技術,那麼Stub就會採用RMI-IIOP協議來傳送數據給Skeleton;若是是CORBA技術,那麼Stub就會採用IIOP協議來傳送數據給Skeleton;若是是WebServices技術,那麼Stub就會經過SOAP協議來傳送數據給Skeleton。也就是說Stub會按照特定協議將信息傳送給Skeletion,而Skeleton會將Stub傳送過來的數據解析成特定的語言對象併發送給遠程對象,即服務端。好比說服務端是採用Java開發的,那麼Skeleton就會將接收到的數據解析成Java對象,再傳送給服務端。

三十9、分佈式尋址方式都有哪些算法?知道一致性hash嗎?手寫一下java實現代碼?你若userId取摸分片,那我要查一段連續時間裏的數據怎麼辦?
分佈式尋址方式:hash算法(大量緩存重建)、一致性hash(自動緩存遷移) + 虛擬節點(自動負載均衡)、redis cluster的hash slot算法。
一致性hash:相同參數的請求老是發到同一服務節點。當某一個服務節點出現故障時,本來發往該節點的請求,基於虛擬節點機制,平攤到其餘節點上,不會引發劇烈變更。


四10、如何解決分庫分表主鍵問題?有什麼實現方案?
併發量不大時使用數據庫自增來解決是一個方案(只能在非高併發環境下),高併發環境使用squeeze或者snowflake(生成的ID總體上按照時間自增排序,而且整個分佈式系統內不會產生ID碰撞,秒級26萬個ID)來實現全局惟一id的獲取。

四11、redis和memcached什麼區別?爲何單線程的redis比多線程的memcached效率要高啊?
一、除了數據外,memcache還能緩存圖片、視頻等。
二、redis除了鍵值對外,還支持list、set、hash等數據結構存儲(支持的數據類型多)。
三、當物理內存用完時redis能夠將好久沒使用的value交換到磁盤。
四、redis的過時策略支持經過expire來設定。
五、redis存儲數據更安全,支持數據持久化到磁盤。
六、redis數據丟失後能夠經過aof找回。
七、redis支持數據備份(master-slave模式數據備份)
八、redis只能在linux下運行。
九、底層模型不一樣,redis本身構建VM。
爲何redis更高:
一、純內存操做。
二、異步非阻塞IO。
三、單線程操做不存在切換CPU致使的性能消耗。
四、沒有鎖機制形成的性能消耗問題。

redis使用單線程的緣由:使用多線程是由於CPU不夠,而對於redis,值簡單的存儲key-value,hash查找能夠輕鬆達到秒級數百萬的量級,因此redis的瓶頸主要來源於網絡IO,固然內存也有可能,可是通常狀況下內存都是夠用的,因此單線程就足夠了(redis的單線程是指一個線程處理全部網絡請求,其餘模塊仍是有用了多線程的)。

四12、redis有什麼數據類型?都在哪些場景下使用啊?
一、String:緩存、計數器、共享session、限速。
二、哈希:哈希結構更加直觀,操做更加敏捷,經常使用於用戶信息等的管理。
三、列表:消息隊列。
四、集合:標籤(tag),例如一個用戶對某一方面(娛樂、體育)比較感興趣另外一個對新聞感興趣。
五、有序集合:排行榜。

四十3、reids的主從複製是怎麼實現的?redis的集羣模式是如何實現的呢?redis的key是如何尋址的啊?
主從複製:用的是RDB快照方式實現的,與持久化的實現方式之一相似,將Redis主機中的數據,完整的生成一個快照,以二進制格式文件(後綴RDB)保存在從機當中。
集羣:Redis Cluster是一個實現了分佈式且容許單點故障的Redis高級版本,它沒有中心節點,各個節點地位一致,具備線性可伸縮的功能。如圖給出Redis Cluster的分佈式存儲架構,其中節點與節點之間經過二進制協議進行通訊,節點與客戶端之間經過ascii協議進行通訊。在數據的放置策略上,Redis Cluster將整個 key的數值域分紅16384個哈希槽,每一個節點上能夠存儲一個或多個哈希槽,也就是說當前Redis Cluster支持的最大節點數就是16384。

 

尋址:KEYS命令(速度快,但在大數據庫中可能形成性能問題,在數據集中查找特定的KEYS可用集合結構SETS代替)和SCAN命令(每次返回少許元素,適用生產環境,不會出現相似KEYS和SMEMBERS帶來可能阻塞服務器的問題,是基於遊標的迭代器。)。

四十4、使用redis如何設計分佈式鎖?使用zk能夠嗎?如何實現啊?這兩種哪一個效率更高啊?
分佈式鎖:主要用於在分佈式環境中保護跨進程、跨主機、跨網絡的共享資源實現互斥訪問,以達到保證數據的一致性;基本原理是用用一個狀態值表示鎖,對鎖的佔用和釋放經過狀態值來標識。
分佈式鎖實現方式:1.使用redis的setnx()和expire();2.使用redis的getset();3.使用zookeeper的建立節點node;4.使用zookeeper的建立臨時序列節點。
redis:採用隊列模式將併發訪問變成串行訪問,且多客戶端對redis的連接並不存在競爭關係。redis的SETNX命令能夠方便的實現分佈式鎖。(setnx(key,value) 若是key不存在,設置爲當前key的值爲value;若是key存在,直接返回;expire()來設置超時時間)
zk:使用zookeeper建立節點node,若是建立節點成功,表示獲取了此分佈式鎖;若是建立節點失敗,表示此分佈式鎖已經被其餘程序佔用(多個程序同時建立一個節點node,只有一個可以建立成功)。
區別:Redis分佈式鎖,必須使用者本身間隔時間輪詢去嘗試加鎖,當鎖被釋放後,存在多線程去爭搶鎖,而且可能每次間隔時間去嘗試鎖的時候,都不成功,對性能浪費很大。Zookeeper分佈鎖,首先建立加鎖標誌文件,若是須要等待其餘鎖,則添加監聽後等待通知或者超時,當有鎖釋放,無須爭搶,按照節點順序,依次通知使用者。二者都是企業級分佈式鎖,效率方面可能差距不大,可是redis更消耗性能。

四十5、知道redis的持久化嗎?都有什麼缺點優勢啊? 具體底層實現呢?
兩種方式:一、使用RDB快照的方式,將內存中的數據不斷寫入磁盤;二、使用相似MySQL的AOF日誌方式,記錄每次更新的日誌。前者性能較高,可是可能會引發必定程度的數據丟失;後者相反。 Redis支持將數據同步到多臺從數據庫上,這種特性對提升讀取性能很是有益。
一、快照:將Redis內存中的數據,完整的生成一個快照,以二進制格式文件(後綴RDB)保存在硬盤當中。當須要進行恢復時,再從硬盤加載到內存中。redis主從複製用的也是RDB,作一個複製文件的傳輸。
二、寫日誌方式:每次執行Redis寫命令,讓命令同時記錄日誌(以AOF日誌格式)。Redis宕機時,只要進行日誌回放就能夠恢復數據。

四十6、redis過時策略都有哪些LRU?寫一下java版本的代碼吧?
LRU策略:一、主動淘汰(經過定時任務serverCron按期清理過時的key);二、被動淘汰(①每次寫入key時若發現內存不夠則調用activeExpireCycle釋放一部份內存;②每次訪問相關的key,若發現key過時直接釋放掉該key相關的內存)。
主動淘汰僞代碼:
/* Expire keys by random sampling. Not required for slaves
* as master will synthesize DELs for us. */
if (server.active_expire_enabled && server.masterhost == NULL)
activeExpireCycle(ACTIVE_EXPIRE_CYCLE_SLOW);

四十7、說一下dubbo的實現過程註冊中心掛了能夠繼續通訊嗎?
能夠。啓動dubbo時消費者會從註冊中心拉取server註冊在註冊中心的server地址、接口鄧數據緩存在本地。
註冊中心主要是一、按期發送心跳包來監聽server提供的服務是否存活;二、server節點變動時,registry會同步變動並讓client感知刷新本地緩存的節點列表。

四十8、dubbo支持哪些序列化協議?hessian,說一下hessian的數據結構。PB知道嗎?爲啥PB效率是最高的啊?
序列化協議:hessian、二進制序列化、json、SOAP文本序列化(基於xml)。(通訊協議包括:rmi、hessian、http、webservice)
數據結構:不知道!!!hession將遠程調用序列化爲二進制進行傳輸,而且能夠進行必定的壓縮。傳輸機制與SOAP相似,可是相比於SOAP,hessian傳輸數據量比SOAP小了一個數量級,更適用於分佈式應用的大數據量的數據交換。
PB通常用做大型數據庫開發。代碼量少,訪問MYsql的效率僅次於VB,可是VB的開發效率低。

四十9、知道netty嗎?netty能夠幹嗎呀?NIO,BIO,AIO 都是什麼啊?有什麼區別啊?
netty是基於事件的NIO(非阻塞)網絡傳輸框架,在服務端啓動時會監聽一個端口並註冊事件(註冊的事件包括:鏈接時間、可寫事件、可讀事件、發生異常)。典型的reactor模型結構,能夠經過ChannelHandler鏈來控制執行流向。
NIO(同步非阻塞方式):client每次發送請求,server不是每次都生成一個新線程來處理,經過I/O多路複用處理,將多個I/O的阻塞服務用到同一個select的阻塞上,使得單線程下能夠同時處理多個客戶端請求(開銷小)。適用於鏈接數多且請求消耗輕的場景。NIO經過selector來實現一個線程監聽多個channel的IO事件。
BIO(同步阻塞方式):client每次發送請求,server就生成一個線程處理,當client發送請求達到瓶頸時,新來的請求將沒法被處理。適用於鏈接數小的場景。
AIO(異步非阻塞方式):client發送一個I/O操做當即返回,等I/O操做完成後client會獲得I/O操做完成的通知,client只需對數據處理便可,真正的I/O操做在內核中完成(不存在阻塞等待)。適用於鏈接數多且請求消耗重的場景。

五10、dubbo負載均衡策略和高可用策略都有哪些啊?動態代理策略呢?
負載均衡(loadbalance):random(默認使用,對provider不一樣勢力設置不一樣權限,按權重負載均衡)、roundrobin(均勻分佈流量,可是若是機器性能不一,可能形成某些機器負載太高)、leastactive(自動感知,性能越差的機器活躍度越低,給這些機器的請求變少)、consistanthash(一致性hash)。
高可用(容錯策略cluster):failover(默認使用,失敗自動切換,自動重試其餘機器)、failfast(一次調用失敗則當即失敗,經常使用於寫操做)、failsafe(出現異常時忽略,用於記錄日誌等不重要的接口調用)、failbackc(後臺自動記錄失敗請求,定時重發,適用於消息隊列)、forking(並行調用多個provider,一個成功當即返回)、broadcacst(諸葛調用provider)
動態代理:默認使用javassist動態字節碼生成,建立代理類;經過spi擴展機制配置動態代理策略。

五12、爲何使用消息隊列啊?消息隊列有什麼優勢和缺點啊?
使用:一、數據須要交互或同步;二、瞬間流量峯值太高,使用消息隊列來緩衝(當峯值超過存儲空間的上限消息隊列也可能被壓垮);
優勢:解耦、異步、削峯。
缺點:性能下降、複雜性提升、數據一致性

五十3、如何保證消息隊列的高可用?如何保證消息不被重複消費啊
高可用:failbackc cluster策略,後臺自動記錄失敗的請求,定時重發,以此來保證高可用。
重複消費問題:冪等,將消息的惟一標識保存到外部介中,每次消費處理時判斷是否處理過。

五十4、kafka ,activemq,rabbitmq,rocketmq都有什麼優勢,缺點啊?
kafka:單機十萬級吞吐量,ms級,topic從幾十升到幾百時吞吐量會大幅降低(大規模topic須要增長機器),基於分佈式的高可用,一個數據多個副本,少數機器宕機不會丟失數據和不可用,消息可作到0丟失,應用於大數據領域的實時計算和日誌採集中,惟一的劣勢是存在消息被重複消費的可能(概率不大,並且這點能夠用冪等來解決,重點是kafka是業內標準)。
activemq:單機萬級,ms,基於主從的高可用,較低機率丟失數據,主要基於解耦和異步,適用較少的大規模吞吐場景。
rabbitmq:單機萬級,μs,基於主從的高可用,基於erlong開發,併發性能好、延時低,動態擴容麻煩,可讀性差。
rocketmq:單機十萬級,ms,可支持大量topic(可達幾百到幾千,吞吐量會有小規模降低),基於分佈式的高可用性(比active、rabbit好),參數優化配置可達數據0丟失,擴展性好;沒有按照JMS標準,可能形成部分系統遷移修改量大。

五十5、若是讓你寫一個消息隊列,該如何進行架構設計啊?說一下你的思路
一、分佈式,支持快速擴容(給topic增長partition,作數據遷移,增長機器)
二、數據落地磁盤,數據持久化,不至於因宕機或斷電致使數據丟失。
三、可用性,相似kafka給數據作多副本。
四、生產者發消息時增長確認反饋機制來確保消息正常能被收到;消費者經過offset commit每次記錄消費的offset值來確保消息不丟失。

五十6、說一下TCP/IP四層?
(自上而下)
應用層:在用戶空間實現,處理業務邏輯(包含DNS、telne、OSPF、http、ftp等協議)。
傳輸層:向用戶提供可靠的端到端的差錯和流量控制,保證報文的正確傳輸(監控服務質量)。
網絡層:經過路由選擇算法爲報文或分組經過子網選擇最適當的路徑,主要解決不一樣子網間的通訊。
數據鏈路:第二層,負責創建和管理節點間的鏈路,提供可靠的經過物理介質傳輸數據的方法。
物理層:最底層,實現相鄰計算機節點間比特流的透明傳輸,儘量屏蔽掉傳輸介質和物理設備的差別。(數據鏈路層與物理層同屬物理層)

另外2層
表示層:處理用戶信息的表示問題,相似編碼、數據格式轉換、加解密等。
會話層:向兩個實體的表示層提供創建和使用鏈接的方法。

五十7、http的工做流程?http1.0 http1.1http2.0 具體哪些區別啊?
http基於tcp協議,面向鏈接的方式發送請求,經過stream二進制流的方式傳給對方。
流程:地址解析 => 封裝HTTP請求 => 封裝TCP包 => 客戶端發送請求 => 服務器端響應 => 關閉鏈接
1.0:早期的應用層網絡協議,只使用在一些簡單的網頁和網絡請求上。
1.1:相比於1.0,一、緩存處理(1.0使用header裏的呃呃if-modified-since,expires來做爲緩存判斷標準,1.1引入了Entitytag、If-Match等新的緩存策略);二、1.0中存在浪費帶寬的現象,1.1引入range頭域;三、錯誤通知管理的區別,新增了24個錯誤狀態響應碼;四、增長Host頭(1.0默認每臺服務器綁定惟一ip,隨着後續一臺物理服務器能夠有多個虛擬主機,1.1中沒有添加Host頭的會報錯);五、支持長鏈接和請求的流水線處理。
2.0:先比與1.*,新增了一些特性,一、新的二進制格式(1.*的解析基於文本);二、多路複用(鏈接共享,一個鏈接上能夠有多個request,接收方根據request的id將其歸屬到不一樣的額服務端請求);三、服務端推送,server push功能;四、header壓縮(使用encoder減小header的大小,通信雙方各cachee一份header fields表,避免重傳,減少大小)。
補充:1.1的長鏈接複用是一次請求-響應創建一個鏈接,用完關閉;2.0的多路複用是多個請求能夠同時在一個鏈接上並行執行。

五十8、TCP三次握手,四層分手的工做流程畫一下流程圖。爲何不是四次五次或者二次啊?
第一次握手,A的消息有去;第二次握手,A有回,B有去;第三次,B有回。第三次握手完成猜能達到客戶端有去有回,服務端的消息也有去有回的要求,次數在增長的結果與3此一致。
3次握手保證了服務端與客戶端的連接已經創建(至此雙方能夠開始通訊),可是不管是3次仍是次數再增長上去都不能保證消息必定是可靠的。

A發送報文給B(你好,我是A),B反饋給A(你好,我是B),A返回消息給B確認(你好)。

A告訴B,不玩了,B回覆好的;B發送不玩了給A,A回覆好的。(若是B回覆了好的以後「直接跑路,B結束了,可是A的狀態會一直停留在當前狀態。」)A最後的回覆須要等待時間,等待時間的間隔爲B發送的包所有都時間到期(即報文的時間超過時限時間後若B沒有拿到A回覆的消息會再度發送「不玩了」的消息給A)。

五十9、畫一下https的工做流程?具體如何實現啊?如何防止被抓包啊?
防抓包:一、流量加密,抓到的內容亂碼;二、https採用的公鑰私鑰的非對稱加密來傳輸對稱加密的密鑰,通訊採用獲取到的對稱加密的私鑰進行加密,沒法獲取到密鑰抓到的包不能解密。


六11、系統架構如何選擇合適日誌技術(log4j、log4j二、slf4j、jcl…….)
slf4j是一個簡單Facade,容許最終用戶在部署時使用其所但願的日誌系統,對於類庫和嵌入式開發時使用比較合適。
log4j是Apache的開源項目,能夠控制每一條日誌輸出和級別。
log4j2基於log4j基礎上改良的,各方面與logback相似,優點在於一、改成插件式結構,根據須要隨時擴展;二、配置文件優化,增長json格式的支持,從新配置後不會丟失原文件。
logback:可靠、通用、快速靈活的java日誌框架,消耗低速度快(log4j的10倍速度),實現了slf4j已有的接口,可配置化(xml配置文件,配置文件更新會自動檢測),可主動設置日誌上限(自動刪除舊日誌),日誌壓縮

六12、springAOP的原理,springAOP和Aspectj的關係,springAOP的源碼問題
AOP底層:基於JDK動態代理或者cglib字節碼操縱等技術,運行時動態生成被調用類型的子類等,並實例化代理對象,實際的方法調用會被代理給相應的代理對象。
AOP底層基於動態代理,在不修改原有類的基礎上對其進行加強,拓展原有類的功能。
關係:AspectJ就是AOP(面向方面編程)中的方面,定義了AOP的語法。spring對於aop的支持(總共4種)中包含了@AspectJ註解驅動切面和注入式AspectJ切面(這個使用AspectJ框架實現aop編程)。
實際聯繫在於AspectJ提供了註解驅動的AOP,本質spring基於代理的AOP,但編程模型與AspectJ一致,不須要使用XML。

六十3、dubbo框架的底層通訊原理
底層通訊採用的是netty來實現的。netty是一個非阻塞的基於事件的網絡傳輸框架,工做在socket層上,採用的是IO多路複用的方式。

六十8、mybaits的底層實現原理,如何從源碼來分析mybaits。
實現方式:
傳統:傳遞Statement Id 和查詢參數給 SqlSession 對象,使用 SqlSession對象完成和數據庫的交互;MyBatis 提供了很是方便和簡單的API,供用戶實現對數據庫的增刪改查數據操做,以及對數據庫鏈接信息和MyBatis自身配置信息的維護操做。
改進:爲適應面向接口的編程,增長了第二種使用MyBatis 支持接口(Interface)調用方式,將配置文件中的每個<mapper> 節點抽象爲一個 Mapper 接口,而這個接口中聲明的方法和跟<mapper> 節點中的<select|update|delete|insert> 節點項對應,以此來實現。


六十9、mysql的索引原理,索引是怎麼實現的
底層使用的是B+樹。

七10、索引的底層算法、如何正確使用、優化索引索引底層算法:散列表、二叉查找樹、B+樹、跳錶、紅黑樹。

相關文章
相關標籤/搜索