一亮航、Java內(nèi)存模型(JMM)
堆(線程共享)
- Java程序中通過創(chuàng)建出來的對象存放在堆內(nèi)存中汽煮,其成員變量和數(shù)據(jù)存放在對象的內(nèi)部济丘,堆內(nèi)存中的對象不可以共享,空間不是連續(xù)的生巡。
- 堆是Java垃圾收集器管理的主要區(qū)域耙蔑,JVM會在CPU空閑時(shí)或內(nèi)存空間不足時(shí)會進(jìn)行垃圾回收,也可以通過代碼調(diào)用System.gc()方法請求JVM進(jìn)行垃圾回收孤荣,但JVM不一定立刻執(zhí)行垃圾回收甸陌,可以通過代碼調(diào)用System.runFinalization()方法強(qiáng)制調(diào)用失去引用的對象的finalize()方法,加速JVM垃圾回收速度盐股。
- 堆由三部分組成钱豁,分別是新生區(qū)、老年區(qū)疯汁、永久區(qū)寥院,所有新建的對象都會存放在新生區(qū),隨著對象的創(chuàng)建越來越多涛目,新生區(qū)會執(zhí)行輕GC秸谢,清理掉大量失去引用的局部變量凛澎,當(dāng)新生區(qū)滿了時(shí)會把部分對象轉(zhuǎn)移到老年區(qū),老年區(qū)會執(zhí)行重GC估蹄,當(dāng)新生區(qū)塑煎、老年區(qū)同時(shí)滿了時(shí)會拋出OOM異常。
Java棧(線程私有)
- Java棧的特點(diǎn)是先進(jìn)后出臭蚁,后進(jìn)先出最铁,生命周期和線程同步,線程結(jié)束時(shí)釋放棧內(nèi)存垮兑,不存在垃圾回收問題冷尉。
- Java程序中的八大基本類型的數(shù)據(jù)、堆中實(shí)例對象的引用地址系枪、實(shí)例對象的方法調(diào)用都存放在棧中雀哨,引用是棧指向堆的過程,也稱Java的指針私爷。
本地方法棧(線程私有)
- 本地方法棧主要存放被native關(guān)鍵字修飾的方法雾棺,本地方法可以調(diào)用本地方法接口JNI(JavaNativeInterface),可以實(shí)現(xiàn)對本地方法庫中底層語言C衬浑、C++方法的調(diào)用捌浩。
方法區(qū)(線程共享)
- Java程序中已經(jīng)被虛擬機(jī)加載的類信息(構(gòu)造方法、接口)工秩、常量(final)尸饺、靜態(tài)變量(static)、運(yùn)行時(shí)常量池助币,都存放在方法區(qū)中侵佃,可被線程共享。
- 運(yùn)行時(shí)常量池用來存放Java程序運(yùn)行時(shí)產(chǎn)生的字符串常量(String類的intern()方法)和八大基本數(shù)據(jù)類型的常量奠支,常量在編譯期以HashSet的形式放入常量池馋辈,常量可以實(shí)現(xiàn)對象共享。
程序計(jì)數(shù)器(線程私有)
- 程序計(jì)數(shù)器占據(jù)非常小的內(nèi)存空間倍谜,用來存儲即將執(zhí)行指令的地址迈螟,便于執(zhí)行引擎讀取下一條指令,這樣就能理解代碼為何能有序地從上往下執(zhí)行尔崔。
JVM參數(shù)設(shè)置
-Xmx128m -> Java堆內(nèi)存的最大值答毫,默認(rèn)為物理內(nèi)存的1/4
-Xms64m -> Java堆內(nèi)存的初始值
-Xmn32m -> Java堆內(nèi)存新生代的大小
-Xss16m -> Java線程的棧內(nèi)存大小
二、Java垃圾回收算法
- 標(biāo)記-清除算法:給對象中添加一個(gè)引用計(jì)數(shù)器季春,每當(dāng)有一個(gè)地方引用它時(shí)洗搂,計(jì)數(shù)器值就加1。當(dāng)引用失效時(shí),計(jì)數(shù)器值就減1耘拇。任何時(shí)刻計(jì)數(shù)器都為0的對象就是不再被使用的撵颊,垃圾收集器將回收該對象使用的內(nèi)存。
- 復(fù)制-清除算法:將可用內(nèi)存按容量劃分為大小相等的兩塊惫叛,每次只使用其中一塊倡勇。當(dāng)這一塊的內(nèi)存用完了,就把還存活著的對象復(fù)制到另外一塊上面嘉涌,然后再把已使用過的內(nèi)存空間一次清理掉妻熊。這樣使得每次都是對整個(gè)半?yún)^(qū)進(jìn)行內(nèi)存回收,內(nèi)存分配時(shí)也就不用考慮內(nèi)存碎片等復(fù)雜情況仑最。
- 標(biāo)記-壓縮算法:結(jié)合了標(biāo)記-清除算法和復(fù)制-清除算法扔役,通過標(biāo)記得到存活的對象,讓對象都緊挨在一起警医,從而避免內(nèi)存碎片的產(chǎn)生亿胸,同時(shí)保證內(nèi)存的高速分配。
三法严、對象的四種引用方式
- 強(qiáng)引用损敷,只要引用存在葫笼,垃圾回收器永遠(yuǎn)不會進(jìn)行垃圾回收深啤,當(dāng)內(nèi)存開銷不足時(shí),拋出OutOfMemory運(yùn)行時(shí)異常路星,即常說的內(nèi)存泄漏或內(nèi)存溢出溯街。強(qiáng)引用是開發(fā)中最常用的方式,如:Object obj = new Object()洋丐,直到obj對象的引用被釋放后呈昔,new Object()才會被垃圾回收器回收,如:obj = null友绝,obj = new Object()堤尾,前者沒有指向任何引用,后者指向新的對象迁客。
- 軟引用郭宝,當(dāng)內(nèi)存開銷不足時(shí),垃圾回收器會對該引用類型進(jìn)行回收掷漱。常用在內(nèi)存緩存的場景中粘室,內(nèi)存足夠時(shí)在軟引用對象中獲取數(shù)據(jù),內(nèi)存不足時(shí)從數(shù)據(jù)庫里獲取實(shí)時(shí)數(shù)據(jù)卜范。如:SoftReference<Object> softReference = new SoftReference<>(new Object())衔统,Object obj = softReference.get(),當(dāng)對象被回收后獲取的結(jié)果為Null。
- 弱引用锦爵,垃圾回收器進(jìn)行垃圾回收時(shí)會對該引用類型進(jìn)行回收舱殿。如:
WeakReference<Object> weakReference = new WeakReference<>(new Object()),Object obj = weakReference.get()棉浸,可以通過weakReference.isEnqueued()查詢對象是否被垃圾回收器標(biāo)記怀薛,當(dāng)對象被回收后獲取的結(jié)果為Null。 - 虛引用迷郑,也被稱為幽靈引用或者幻影引用枝恋,不會對對象的生命周期造成任何影響刽虹,也無法獲取到對象的引用實(shí)例拐辽,常用于跟蹤垃圾回收的過程和監(jiān)聽回收的頻率,垃圾回收器進(jìn)行垃圾回收時(shí)會對該引用類型進(jìn)行回收梦鉴。
Object object = new Object();
ReferenceQueue<Object> queue = new ReferenceQueue<>(); -> 保存對象被回收的虛引用
PhantomReference<Object> phantomReference = new PhantomReference<>(object,queue);
object = null; -> 切斷對象的引用
System.gc(); -> 請求垃圾回收
System.runFinalization(); -> 強(qiáng)制調(diào)用對象的finalize()方法
Reference<? extends Object> reference = queue.poll(); -> 取出虛引用
phantomReference == reference; -> true
- 編譯期:編譯器是一種計(jì)算機(jī)程序霸妹,它能將程序的源碼(.java)編譯成計(jì)算機(jī)可以執(zhí)行的文件(.class)十电,在翻譯過程中會檢查代碼語法錯誤,不會把代碼放入內(nèi)存中運(yùn)行叹螟,從中會產(chǎn)生一些指令鹃骂,如:分配內(nèi)存大小、存放位置等罢绽。
- 運(yùn)行期:程序編譯后的文件(.class)交由計(jì)算機(jī)執(zhí)行開始畏线,直至計(jì)算機(jī)不執(zhí)行結(jié)束,按照編譯期生成的指令運(yùn)行良价,類的加載也發(fā)生在該時(shí)期寝殴。
- 類加載機(jī)制:加載階段,JVM將字節(jié)碼文件轉(zhuǎn)化為二進(jìn)制字節(jié)流加載到內(nèi)存中明垢,接為這個(gè)類在方法區(qū)創(chuàng)建對應(yīng)的 Class 對象蚣常,這個(gè)對象就是各種數(shù)據(jù)的訪問入口。驗(yàn)證階段痊银,包括JVM規(guī)范校驗(yàn)和代碼邏輯校驗(yàn)抵蚊。準(zhǔn)備階段,分配類變量內(nèi)存和變量類型的初始化溯革。解析階段贞绳,針對類、接口鬓照、方法熔酷、字段、限定符等解析豺裆。初始化階段拒秘,用戶的代碼執(zhí)行初始化号显。使用階段,程序啟動完成供用戶使用躺酒。卸載階段押蚤,程序的字節(jié)碼在JVM內(nèi)存中卸載停止使用。
四羹应、包裝與解包
包裝類 | 基礎(chǔ)類型 | 包裝 | 解包 | 緩存 |
---|---|---|---|---|
Byte | byte | Byte b = (byte) 1 | b.byteValue() | -128~127 |
Boolean | boolean | Boolean b = true | b.booleanValue() | TRUE FLASE |
Short | short | Short s = (short) 1 | s.shortValue() | -128~127 |
Character | char | Character c = (char) 1 | c.charValue() | 0~127 |
Integer | int | Integer i = 1 | i.intValue() | -128~127 |
Long | long | Long l = Long.valueOf(1L) | l.longValue() | -128~127 |
Float | float | Float f = Float.valueOf(1f) | f.floatValue() | 無 |
Double | double | Double d = Double.valueOf(1d) | d.doubleValue() | 無 |
int int1 = 10,int2 = 10;
Integer in1 = 127,in2 = 127;
Integer out1 = 128,out2 = 128;
Integer integer1 = new Integer(10);
Integer integer2 = new Integer(10);
Integer integer3 = new Integer(127);
int1 == int2; -> true,基本類型比較數(shù)值
int1 == integer1; -> true,包裝類自動拆包,本質(zhì)是基本類型相比較
integer1 == integer2; -> false,兩個(gè)引用對象比較的是堆內(nèi)存的地址
integer3 == in1; -> false,引用對象和常量的存放地址不同
in1 == in2; -> true,數(shù)值在包裝類的緩存區(qū)間中
out1 == out2; -> false,數(shù)值不在包裝類的緩存區(qū)間中,本質(zhì)是兩個(gè)引用對象相比較
- 當(dāng)基本類型和包裝類型比較時(shí)揽碘,包裝類型會自動拆包生成其對應(yīng)的基本類型,基本類型之間的比較园匹,使用"=="即可雳刺。
- 當(dāng)包裝類型的對象是通過new關(guān)鍵字創(chuàng)建,對象實(shí)例存在放堆內(nèi)存中裸违,引用對象持有堆內(nèi)存的指針掖桦,兩個(gè)對象之間通過"=="比較的是對象的堆內(nèi)存地址,比較結(jié)果不會相等供汛,兩個(gè)對象之間通過equals()方法比較的是它們的值枪汪,數(shù)據(jù)存放在棧內(nèi)存中,棧的特點(diǎn)是數(shù)據(jù)共享怔昨,所以相同的數(shù)據(jù)僅有一份雀久,比較結(jié)果可能相等也可能不相等。
- 當(dāng)包裝類型中的一個(gè)對象是直接賦予確定的數(shù)值趁舀,另一個(gè)對象是通過new關(guān)鍵字創(chuàng)建時(shí)赖捌,直接定義的對象屬于常量,存放在常量池中赫编,new關(guān)鍵字創(chuàng)建的對象屬于實(shí)例對象巡蘸,存放在堆內(nèi)存中奋隶,兩個(gè)對象通過"=="比較的結(jié)果顯然是不相等的擂送,需要比較它們的值是否相等可以通過equals()方法。
- 當(dāng)包裝類型中的兩個(gè)對象同時(shí)直接賦予確定的數(shù)值唯欣,以Integer為例子嘹吨,包裝類會默認(rèn)緩存 -128~127區(qū)間中的數(shù)值,當(dāng)直接賦予的常量值在此區(qū)間內(nèi)境氢,兩個(gè)對象通過"=="比較結(jié)果會相等蟀拷,反之超出區(qū)間通過"=="比較結(jié)果不會相等。
String name = new String("wjx"); -> 這個(gè)過程會創(chuàng)建1~2個(gè)對象(堆內(nèi)存和常量池)
String wjx = "wjx";
String w = "w";
String j = "j";
String x = "x";
name == wjx; -> false,引用對象和常量比較,內(nèi)存地址不一樣
wjx == "w"+"j"+"x"; -> true,常量在編譯期已經(jīng)確定
wjx == w+j+x; -> false,變量在運(yùn)行期才能確定
wjx == (w+j+x).intern(); -> true,運(yùn)行期設(shè)置常量
五萍聊、常見面試題
運(yùn)算符“==”和equals()方法的區(qū)別
- “==”在比較Java基本數(shù)據(jù)類型(byte问芬、int、long寿桨、short此衅、double强戴、float、boolean挡鞍、char)時(shí)是比較它們的值骑歹,在比較引用對象類型時(shí)是比較它們在堆內(nèi)存中的地址。
- equals的本質(zhì)是==墨微,Object類中的equals()方法默認(rèn)是比較兩個(gè)對象在堆內(nèi)存中的地址道媚,重寫后比較它們兩個(gè)的值是否相等。
equals()和hashCode()的區(qū)別
- equals()相等的兩個(gè)對象其hashCode()肯定相等翘县。
- hashCode()相等的兩個(gè)對象其equals()不一定相等最域。
- equals()的本質(zhì)是==,比較的是對象在棧中的引用地址锈麸。
- hashCode()的本質(zhì)是對象在哈希表中的索引羡宙,通過索引找到對象。
- 在自定義比較兩個(gè)對象時(shí)需要重寫equals()和hashCode()方法掐隐。
變量命名規(guī)范
- 首字母為英文(a~z)狗热、美元符($)、下劃線(_)虑省。
- 英文匿刮、美元符、下劃線探颈、數(shù)字隨機(jī)搭配熟丸,單詞間建議駝峰格式。
- 命名直至中文伪节,但不建議使用光羞。
- 不允許使用java中的關(guān)鍵字命名。
定義 float怀大、double纱兑、long 變量的規(guī)范
- JVM的小數(shù)默認(rèn)解析為double類型。
- float單精度化借,double雙精度潜慎,double可以接收float。
- float和double都可以接收任意長度的小數(shù)并截取指定精度蓖康。
- 以float铐炫、double、long的形式接收整型值時(shí)不需添加后綴蒜焊。
String倒信、StringBuffer、StringBuilder的區(qū)別
- String修飾不可變的對象泳梆,每次操作都會生成新的對象鳖悠,指針也隨之發(fā)生改變唆迁。
- StringBuffer、StringBuilder修飾可變的對象竞穷,可以對原有的對象進(jìn)行操作唐责。
- StringBuffer是線程安全的,其內(nèi)部的所有方法都添加了synchronized關(guān)鍵字進(jìn)行修飾瘾带,而StringBuilder是非線程安全的鼠哥。
- 三者性能間比較:StringBuilder > StringBuffer > String 。
普通類和抽象類的區(qū)別
- 普通類不含有抽象方法看政,可以直接實(shí)例化對象朴恳,可被final關(guān)鍵字修飾。
- 抽象類可以含有抽象方法允蚣,不可以直接實(shí)例化對象于颖,不可被final關(guān)鍵字修飾。
接口和抽象類的區(qū)別
- 抽象類的子類通過extends關(guān)鍵字繼承嚷兔,一個(gè)實(shí)體類只能繼承一個(gè)抽象類森渐,抽象類可以有構(gòu)造方法、普通成員方法冒晰、任意類型的成員變量同衣,抽象類的設(shè)計(jì)目的是代碼復(fù)用。
- 接口的子類通過implements關(guān)鍵字實(shí)現(xiàn)壶运,一個(gè)實(shí)體類可以繼承多個(gè)接口耐齐,接口沒有構(gòu)造方法,只有抽象普通成員方法蒋情、final和static修飾的成員變量埠况,接口的設(shè)計(jì)目的是約束類的行為。
深拷貝和淺拷貝的區(qū)別
- 淺拷貝只是復(fù)制了對象的引用地址棵癣,兩個(gè)對象指向同一個(gè)內(nèi)存地址辕翰,修改其中一個(gè)對象的值,另一個(gè)對象的值也會隨之發(fā)生改變浙巫。
String s1 = "wjx";
String s2 = s1;
- 深拷貝實(shí)現(xiàn)Cloneable接口金蜀,重寫clone()方法的畴,把對象和屬性值都復(fù)制了,兩個(gè)對象間互不影響尝胆,都是獨(dú)立的對象丧裁。
public class Node implements Cloneable {
private String name;
private Node next;
@Override
protected Object clone() throws CloneNotSupportedException {
Node node = (Node) super.clone();
if (this.next != null) {
node.next = (Node) next.clone(); -> 手動拷貝對象成員
}
return node;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
線性表、B-Tree含衔、B+Tree
- 線性表是最基本煎娇、最簡單二庵、最常用的一種數(shù)據(jù)結(jié)構(gòu),一個(gè)線性表包含n個(gè)相同特性的數(shù)據(jù)元素缓呛,存儲結(jié)構(gòu)是鏈?zhǔn)酱鎯Υ呦恚谝粋€(gè)元素沒有頭,最后一個(gè)元素沒有尾哟绊,中間的元素都是首尾連接的因妙,有序。
-
B-Tree是多路平衡查找樹票髓,一棵m階層的B樹攀涵,每個(gè)節(jié)點(diǎn)里最多存放(m-1)個(gè)關(guān)鍵字,關(guān)鍵字以key和value形式存儲洽沟,每個(gè)節(jié)點(diǎn)最多有m個(gè)子節(jié)點(diǎn)以故,結(jié)點(diǎn)中包含多個(gè)關(guān)鍵字、父結(jié)點(diǎn)的指針裆操、子結(jié)點(diǎn)的指針怒详,關(guān)鍵字不可重復(fù)出現(xiàn)在不同的結(jié)點(diǎn)中,左子結(jié)點(diǎn)的值會比右子結(jié)點(diǎn)的值小踪区,B樹會把關(guān)鍵字添加到最底層的非葉子結(jié)點(diǎn)中棘利,如果不破壞m階層樹的結(jié)構(gòu)則結(jié)束,反之結(jié)點(diǎn)會進(jìn)行分裂使之恢復(fù)到m階層樹的結(jié)構(gòu)朽缴。
- B+Tree是在B-Tree基礎(chǔ)上的一種優(yōu)化善玫,非葉子結(jié)點(diǎn)不存放value,使之可以存放更多的key密强,降低樹的高度茅郎,最底層的葉子結(jié)點(diǎn)包含所有的key和value,key從小到大從左往右排列或渤,相鄰的兩個(gè)結(jié)點(diǎn)通過指針關(guān)聯(lián)系冗。
什么是面向過程,什么是面向?qū)ο?/p>
- 面向過程會把任務(wù)拆解為一系列的動作薪鹦,比如洗衣服掌敬,包含步驟:1、打開洗衣機(jī)池磁;2奔害、往里面放衣服;3地熄、往里面放洗衣粉华临;4、清洗端考;5雅潭、烘干揭厚;
- 面向?qū)ο髶碛忻嫦蜻^程的特點(diǎn),會更注重于任務(wù)的參與者以及各自需要完成的步驟扶供,比如洗衣服筛圆,包含參與者:人、洗衣機(jī)椿浓,包含步驟:1顽染、人打開洗衣機(jī);2轰绵、人往洗衣機(jī)里面放衣服粉寞;3、人往洗衣機(jī)里面放洗衣粉左腔;4唧垦、洗衣機(jī)對衣服進(jìn)行清洗;5液样、洗衣機(jī)對衣服進(jìn)行烘干振亮;
- 面向過程直接高效,面向?qū)ο笠子趶?fù)用鞭莽、擴(kuò)展坊秸、維護(hù)。
JDK澎怒、JRE褒搔、JVM三者的區(qū)別和聯(lián)系
- JDK(Java Development Kit)是開發(fā)Java程序的工具。
- JRE(Java Runtime Environment)是運(yùn)行Java程序的環(huán)境喷面。
- JVM(Java Virtual Machine)是Java的虛擬機(jī)星瘾。
- *.java文件通過JDK的javac命令編譯成 *.class文件,JRE通過ClassLoader加載 *.class文件解析到JVM里惧辈,JDK中包含JRE琳状,JRE中包含JVM。
final的作用
- 修飾的類不可被繼承盒齿,修飾的方法不可被覆蓋念逞。
- 修飾基本類型的變量不可更改值,修飾引用類型的變量不可更改對象边翁,引用值可以改變翎承。
- 局部內(nèi)部類和匿名內(nèi)部類只能訪問final修飾的變量。
重載和重寫的區(qū)別
- 重載:在同一個(gè)類中倒彰,方法名相同审洞,方法修飾符、方法返回值待讳、參數(shù)類型芒澜、參數(shù)個(gè)數(shù)不同,發(fā)生在編譯期创淡。
- 重寫:在子類中痴晦,方法名、參數(shù)列表必須相同琳彩,返回值誊酌、拋出異常小于等于父類,修飾符大于等于父類(private除外)露乏。
ArrayList和LinkList的區(qū)別
- ArrayList基于動態(tài)數(shù)組碧浊,數(shù)組的特點(diǎn)是內(nèi)存存儲空間連續(xù),適合使用下標(biāo)訪問數(shù)組里的元素瘟仿,查詢速度快箱锐,新增、修改劳较、刪除速度慢驹止,每次擴(kuò)容空間的量為原來的1.5倍,把原數(shù)組的元素遷移到新數(shù)組上观蜗。
- LinkList基于鏈表臊恋,鏈表的特點(diǎn)是內(nèi)存儲存空間不連續(xù),只能通過iterator迭代器去遍歷墓捻,查詢速度慢抖仅,新增、修改砖第、刪除速度快岸售,不適合使用下標(biāo)訪問數(shù)組里的元素。
HashMap和HashTable的區(qū)別
- 底層原理:數(shù)組+鏈表+紅黑樹厂画,當(dāng)數(shù)組的長度超過64凸丸,鏈表的長度達(dá)到8轉(zhuǎn)變成紅黑樹,紅黑樹的長度小于等于6轉(zhuǎn)變成鏈表袱院,取出key的hashCode進(jìn)行二次hash屎慢,然后對數(shù)組的長度進(jìn)行取模,得到數(shù)組的存放下標(biāo)忽洛,如果沒有產(chǎn)生hash沖突(數(shù)組下標(biāo)的位置為空)腻惠,則創(chuàng)建節(jié)點(diǎn)存入數(shù)組,如果產(chǎn)生hash沖突(數(shù)組下標(biāo)的位置存在鏈表)欲虚,則遍歷鏈表通過equals()方法判斷元素是否在鏈表中集灌,如果存在就覆蓋原來的元素,如果不存在就創(chuàng)建節(jié)點(diǎn)添加到鏈表的尾部。
- HashMap是線程不安全的欣喧,key和value都允許為null腌零,key為null時(shí),元素存放在數(shù)組的第一個(gè)位置唆阿,即下標(biāo)是0益涧。
- HashTable是線程安全的,其內(nèi)部的所有方法都添加了synchronized關(guān)鍵字進(jìn)行修飾驯鳖,key和value都不允許為null闲询。
Thread.sleep(0)的作用
- 由于大部分操作系統(tǒng)采用的是搶占式線程調(diào)度算法,因此可能會出現(xiàn)某條線程經(jīng)常獲取到CPU控制權(quán)的情況浅辙,為了讓某些優(yōu)先級低的線程也能獲取到CPU的控制權(quán)扭弧,可以通過調(diào)用Thread.sleep(0)來手動觸發(fā)操作系統(tǒng)重新給線程分配時(shí)間片。
- 在大循環(huán)里寫上Thread.sleep(0)记舆,間歇地給其他線程獲取CPU的控制權(quán)鸽捻,避免優(yōu)先級低的線程出現(xiàn)假死的情況,是一種平衡CPU控制權(quán)的操作氨淌。
什么是字節(jié)碼泊愧,采用字節(jié)碼有什么好處
- 不同操作系統(tǒng)(Windows、Linux盛正、Mac)的解析器實(shí)現(xiàn)是不一樣的删咱,但它們的虛擬機(jī)實(shí)現(xiàn)是一致的,Java中引入了虛擬機(jī)的概念豪筝,Java編譯器面向的對象是虛擬機(jī)痰滋,通過把源文件(*.java)編譯成虛擬機(jī)可以理解的字節(jié)碼( *.class),虛擬機(jī)中的解析器將每一條需要執(zhí)行的字節(jié)碼翻譯成特定機(jī)器上的機(jī)器碼续崖,然后在機(jī)器上執(zhí)行敲街,這也解析了Java的編譯與解析共存的特點(diǎn)。
- 在一定程度上解決了傳統(tǒng)解析型語言執(zhí)行效率低的問題严望,同時(shí)又保留了解析型語言可移植的特點(diǎn)多艇,而且字節(jié)碼只面向虛擬機(jī),所以Java程序只需要編譯一次就可以在不同的操作系統(tǒng)上運(yùn)行使用像吻。
Java中的類加載器有哪些
- BootStrapClassLoader峻黍,負(fù)責(zé)加載%JAVA_HOME%/lib文件夾下的*.jar文件和 *.class文件。
- ExtClassLoader拨匆,是BootStrapClassLoader的子類姆涩,負(fù)責(zé)加載%JAVA_HOME%/lib/ext文件夾下的*.jar文件和 *.class文件。
- AppClassLoader惭每,是ExtClassLoader的子類骨饿,用于實(shí)現(xiàn)自定義的類加載,負(fù)責(zé)加載開發(fā)人員編寫的文件。
Java中的異常體系
- 異常的頂級父類是Throwable宏赘,下面有Exception和Error兩個(gè)子類绒北。
- Error是程序無法處理的錯誤,一旦出現(xiàn)則會終止程序的運(yùn)行置鼻,如內(nèi)存溢出(OutOfMemoryError)镇饮、線程死鎖(ThreadDeath)蜓竹、虛擬機(jī)錯誤(VirtualMachineError)等等箕母。
- Exception不會終止程序的運(yùn)行,它可以分為CheckedException和RuntimeException兩種俱济,CheckedException發(fā)生在程序編譯過程中嘶是,導(dǎo)致程序編譯不通過,RuntimeException發(fā)生在程序運(yùn)行過程中蛛碌,導(dǎo)致程序線程執(zhí)行失敗聂喇。
什么是線程安全
- 多個(gè)線程對同一個(gè)對象進(jìn)行訪問,如果對象不需要進(jìn)行同步控制或者其他協(xié)調(diào)操作蔚携,調(diào)用該對象的行為都可以獲得正確的結(jié)果希太,就證明是線程安全。
- 棧是每個(gè)線程獨(dú)有的酝蜒,生命周期和線程同步誊辉,線程切換時(shí)棧也會隨之切換,所以棧是線程安全的亡脑。
- 堆是線程共享的堕澄,多個(gè)線程可以對堆中的同一個(gè)對象進(jìn)行訪問,所以堆是線程不安全的霉咨。
串行蛙紫、并行、并發(fā)的區(qū)別
- 串行在時(shí)間上不會出現(xiàn)重疊途戒,前一個(gè)任務(wù)完成才會執(zhí)行后一個(gè)任務(wù)坑傅。
- 并行在時(shí)間上會出現(xiàn)重疊,兩個(gè)任務(wù)獨(dú)立完成喷斋,互不干擾唁毒。
- 并發(fā)在時(shí)間上會出現(xiàn)重疊,兩個(gè)任務(wù)間存在干擾继准,干擾階段串行執(zhí)行枉证。
并發(fā)編程的三要素
- 原子性:不可分割的操作,多個(gè)步驟要保證同時(shí)成功或者同時(shí)失敗移必。
- 有序性:程序執(zhí)行的順序和代碼的順序保持一致室谚。
- 可用性:一個(gè)線程對共享變量的修改,另一個(gè)線程能馬上看見。
線程池的線程復(fù)用原理是什么
- 線程池把線程和任務(wù)進(jìn)行解耦秒赤,擺脫了直接創(chuàng)建線程猪瞬,線程和任務(wù)一對一的綁定限制。
- 線程池中的線程會不斷輪詢堵塞隊(duì)列入篮,不斷地檢查和獲取新的任務(wù)來執(zhí)行妈候。
- 直至堵塞隊(duì)列的任務(wù)全部執(zhí)行完欠肾,調(diào)用線程的wait()方法,釋放出CPU。
談?wù)勀銓OP的理解
- 系統(tǒng)由諸多不同的組件構(gòu)成陷谱,每個(gè)組件都負(fù)責(zé)特定的功能兢卵,除此以外還經(jīng)常承擔(dān)著額外的職責(zé)匙隔,例如操作日志琼懊、事務(wù)管理、權(quán)限控制等等的核心服務(wù)肮帐,當(dāng)需要為分散的對象引入公共行為時(shí)咖驮,OOP則顯得乏力,它導(dǎo)致大量重復(fù)的代碼训枢,不利于給各個(gè)組件復(fù)用公共行為托修。
- 將公共行為封裝成一個(gè)切面,然后注入到每個(gè)組件中恒界,目的是增強(qiáng)組件的功能睦刃,常見的用法是在組件調(diào)用某個(gè)方法前、后做些額外的事情仗处,例如:在操作前校驗(yàn)權(quán)限眯勾、在操作后記錄日志等等。
談?wù)勀銓OC的理解
- 控制反轉(zhuǎn)婆誓,在沒有IOC容器之前吃环,對象A依賴對象B(A a = new B();),A必須主動創(chuàng)建對象B洋幻,控制權(quán)在A手里郁轻,在引入IOC容器之后,對象A和對象B失去了直接聯(lián)系文留,當(dāng)對象A需要依賴對象B時(shí)好唯,IOC容器會主動創(chuàng)建對象B提供給對象A,控制權(quán)在容器手里燥翅。
- 依賴注入骑篙,對象A和對象B的依賴關(guān)系由IOC容器動態(tài)地注入,使用到簡單工廠設(shè)計(jì)模式和Java反射技術(shù)森书,原理是動態(tài)創(chuàng)建對象靶端。
談?wù)勀銓ξ⒎?wù)的理解
- 微服務(wù)是一種架構(gòu)風(fēng)格谎势,通過將大型的單體應(yīng)用劃分為比較小的服務(wù)單元,從而降低整個(gè)系統(tǒng)的復(fù)雜度杨名。
- 優(yōu)點(diǎn)是每個(gè)微服務(wù)都是獨(dú)立的脏榆,應(yīng)用性能提高,技術(shù)選擇靈活台谍,耦合性降低须喂,代碼復(fù)用強(qiáng)。
- 缺點(diǎn)是微服務(wù)之間的通信難度提高了趁蕊,如負(fù)載均衡坞生、熔斷降級、分布式鎖介衔、分布式事務(wù)等等恨胚。
如何實(shí)現(xiàn)一個(gè)IOC容器
- 配置文件中指定需要掃描的包路徑骂因。
- 定義一些注解炎咖,分別表示訪問控制層、業(yè)務(wù)服務(wù)層寒波、數(shù)據(jù)持久層乘盼、依賴注入、獲取配置俄烁。
- 遞歸掃描包下面的文件夾及文件信息绸栅,用Set集合存放所有以class結(jié)尾的文件。
- 遍歷Set集合页屠,獲取在類上有指定注解的類交給IOC容器粹胯,并在容器內(nèi)部定義一個(gè)安全的Map集合來存放這些被容器管理的類。
- 遍歷Map集合辰企,獲取到每個(gè)類的實(shí)例對象风纠,判斷里面是否有依賴其他類的實(shí)例對象,然后進(jìn)行遞歸的依賴注入牢贸。
BeanFactory和ApplicationContext的區(qū)別
- BeanFactory采用懶加載的形式注入Bean竹观,即只有調(diào)用getBean()方法時(shí)才會實(shí)例化,這樣就不能及時(shí)發(fā)現(xiàn)Spring配置的問題潜索,直到實(shí)例化的時(shí)候才拋出異常臭增。
- ApplicationContext在容器啟動時(shí)會一次性創(chuàng)建好所有的Bean,這樣能在容器啟動時(shí)及時(shí)發(fā)現(xiàn)Spring配置的問題竹习,在需要Bean對象時(shí)可以直接獲取誊抛,無需等待。不足的是占用內(nèi)存空間大整陌,容器啟動速度慢拗窃。
- BeanFactory和ApplicationContext都支持BeanPostProcessor昔园、BeanFactoryPostProcessor的使用,區(qū)別是BeanFactory需要手動注冊并炮,而ApplicationContext是自動注冊默刚,ApplicationContext是BeanFactory的子接口,提供了更完成的功能逃魄,還可以訪問資源文件荤西、獲取系統(tǒng)變量、支持國際化伍俘、注冊事件發(fā)布等等邪锌。
Spring容器的啟動流程
- 首先掃描得到所有的BeanDefinition對象,并存放在Map中癌瘾。
- 篩選出非懶加載的單例Bean進(jìn)行創(chuàng)建觅丰,步驟包括推斷構(gòu)造方法、實(shí)例化妨退、屬性填充妇萄、初始化前、初始化中咬荷、初始化后冠句,其中AOP就發(fā)生在初始化后這一步驟里。
- 所有的單例Bean創(chuàng)建完成后幸乒,Spring會發(fā)布一個(gè)容器啟動事件懦底。
Spring Bean的生命周期
- Spring容器啟動時(shí)解析類得到BeanDefinition,它主要存儲Bean的定義信息罕扎,決定Bean的生產(chǎn)方式聚唐。
- 當(dāng)類存在多個(gè)構(gòu)造方法時(shí),需要推斷用哪個(gè)構(gòu)造方法實(shí)例化得到對象腔召。
- 對類中添加了@Autowired注解的成員變量進(jìn)行依賴注入杆查。
- 回調(diào)Aware方法,例如BeanNameAware宴咧、BeanFactoryAware等等根灯。
- 調(diào)用BeanPostProcessor初始化前(AOP)、初始化掺栅、初始化后(AOP)的方法烙肺。
- 如果Bean是單例,則放進(jìn)單例池中氧卧,使用Bean桃笙。
- Spring容器關(guān)閉前調(diào)用DisposableBean中的destory()方法。
Spring框架中的單例Bean線程安不安全
- 不安全沙绝,Spring加載Bean默認(rèn)使用單例模式搏明,并沒有對Bean進(jìn)行多線程封裝處理鼠锈。
- Controller層、Service層星著、Dao層购笆,本身并不是線程安全的,如果需要定義實(shí)例變量虚循,就需要用ThreadLocal把變量設(shè)為線程私有同欠,如果需要多線程之間共享,就需要使用Lock實(shí)現(xiàn)同步横缔。
- 可以修改Bean的作用域铺遂,使每次請求Bean都重新實(shí)例化對象,保證線程安全茎刚。
Spring Bean有幾種作用域
- singleton:默認(rèn)創(chuàng)建方式襟锐,由BeanFactory來維護(hù),生命周期和IOC容器一樣膛锭。
- prototype:每次請求Bean都重新注入一個(gè)新的對象粮坞。
- request:每個(gè)HTTP請求中都創(chuàng)建一個(gè)單例對象。
- session:每次會話中都創(chuàng)建一個(gè)單例對象泉沾。
- application:ServletContext生命周期中創(chuàng)建一個(gè)單例對象捞蚂。
- websocket:WebSocket生命周期中創(chuàng)建一個(gè)單例對象。
Spring事務(wù)的實(shí)現(xiàn)方式跷究、原理、隔離級別
- 類和方法上添加@Transactional注解便可以使用Spring的事務(wù)敲霍。
- Spring的事務(wù)基于數(shù)據(jù)庫的事務(wù)進(jìn)行了擴(kuò)展俊马,為啟用事務(wù)的Bean創(chuàng)建代理對象,代理對象會取消事務(wù)的自動提交肩杈,再執(zhí)行原來的邏輯柴我,過程沒有異常再把事務(wù)提交,反之進(jìn)行邏輯回滾扩然,默認(rèn)回滾RuntimeException和Error艘儒,也可以通過注解的rollbackFor屬性自定義回滾的異常。
- 未提交讀(read uncommitted):事務(wù)的最低隔離等級夫偶,AB兩個(gè)事務(wù)都開啟的前提下界睁,A方對表數(shù)據(jù)進(jìn)行了修改,在未提交事務(wù)的情況下兵拢,B方對表進(jìn)行查詢時(shí)能讀取到A方修改后的數(shù)據(jù)翻斟,存在臟讀現(xiàn)象,安全性最低说铃。
- 已提交讀(read committed):事務(wù)隔離等級比未提交讀的高访惜,AB兩個(gè)事務(wù)都開啟的前提下嘹履,A方在未提交事務(wù)的情況下對表做的任何修改B方都不會看到,A方提交事務(wù)后债热,B方在未提交事務(wù)的情況下能看到A方對表做的修改砾嫉,A方對表數(shù)據(jù)進(jìn)行更新則B方出現(xiàn)不可重復(fù)讀的現(xiàn)象(相同的查詢語句查出來的數(shù)據(jù)值不一樣),A方對表數(shù)據(jù)進(jìn)行新增窒篱、刪除則B方出現(xiàn)幻讀的現(xiàn)象(相同的查詢語句查出來的數(shù)據(jù)行不一樣)焰枢。
- 可重復(fù)讀(repeatable read):事務(wù)隔離等級比已提交讀的高,AB兩個(gè)事務(wù)都開啟的前提下舌剂,各自會生成一個(gè)數(shù)據(jù)表的快照济锄,A方對表數(shù)據(jù)進(jìn)行了修改并提交了事務(wù),B方在未提交事務(wù)的情況下霍转,仍然看不到A方做的任何修改荐绝,解決了不可重復(fù)讀的現(xiàn)象,B方提交事務(wù)后避消,如果A方做的操作是新增或刪除低滩,則此時(shí)會出現(xiàn)幻讀現(xiàn)象。
- 可串行化(serializable):事務(wù)的最高隔離等級岩喷,AB兩個(gè)事務(wù)都開啟的前提下恕沫,A方對表數(shù)據(jù)進(jìn)行了修改,在未提交事務(wù)的情況下表會加鎖纱意,B方對表進(jìn)行查詢時(shí)會被堵塞婶溯,直到A方提交事務(wù)或者超時(shí)為止。
Spring事務(wù)的傳播機(jī)制
- REQUIRED:如果沒有事務(wù)偷霉,則創(chuàng)建一個(gè)事務(wù)迄委,反之加入當(dāng)前事務(wù)。
- SUPPORTS:當(dāng)前存在事務(wù)类少,則加入事務(wù)叙身,反之以非事務(wù)形式執(zhí)行。
- MANDATORY:當(dāng)前存在事務(wù)硫狞,則加入事務(wù)信轿,反之拋出異常。
- REQUIRES_NEW:創(chuàng)建一個(gè)事務(wù)残吩,如果已存在事務(wù)财忽,則掛起當(dāng)前事務(wù)。
- NOT_SUPPORTED:以非事務(wù)方式執(zhí)行世剖,如果已存在事務(wù)定罢,則掛起當(dāng)前事務(wù)。
- NEVER:不使用事務(wù)旁瘫,如果已存在事務(wù)祖凫,則拋出異常琼蚯。
- NESTED:當(dāng)前存在事務(wù),則創(chuàng)建一個(gè)子事務(wù)進(jìn)行嵌套惠况,子事務(wù)發(fā)生異常不提交遭庶,但不會影響到父事務(wù)的提交,反之創(chuàng)建一個(gè)事務(wù)稠屠。
Spring事務(wù)的隔離級別
- ISOLATION_DEFAULT:使用數(shù)據(jù)庫默認(rèn)的事務(wù)隔離級別峦睡。
- ISOLATION_READ_UNCOMMITTED:讀未提交,允許事務(wù)執(zhí)行過程中讀取其它事務(wù)未提交的數(shù)據(jù)权埠。
- ISOLATION_READ_COMMITTED:讀已提交榨了,允許事務(wù)執(zhí)行過程中讀取其它事務(wù)已提交的數(shù)據(jù)。
- ISOLATION_REPEATABLE_READ:可重復(fù)讀攘蔽,在同一個(gè)事務(wù)內(nèi)龙屉,任意時(shí)刻查詢的數(shù)據(jù)結(jié)果都是一樣的。
- ISOLATION_SERIALIZABLE:可串行化满俗,所有事務(wù)按順序
依次執(zhí)行转捕。
Spring事務(wù)什么時(shí)候會失效
- 類方法的自調(diào)用,Spring事務(wù)的原理是AOP唆垃,自調(diào)用方法的對象不是代理類五芝。
- @Transactional注解只作用于public修飾的方法,非public修飾的方法不支持事務(wù)辕万。
- 數(shù)據(jù)庫不支持事務(wù)枢步、類沒有被Spring容器管理、手動捕獲處理了異常蓄坏。
Spring使用到哪些設(shè)計(jì)模式
- 單例模式:Bean對象默認(rèn)的創(chuàng)建方式是Singleton价捧。
- 觀察者模式:Spring的事件監(jiān)聽和訂閱。
- 代理模式:AOP的實(shí)現(xiàn)涡戳,為不同的功能引入公共行為。
- 簡單工廠模式:BeanFactory和ApplicationContext都是創(chuàng)建Bean的工廠脯倚。
- 工廠方法模式:FactoryBean是一個(gè)工廠接口渔彰,需要通過不同具體的Bean來實(shí)現(xiàn),對象初始化采用的是懶加載方式推正,Spring管理BeanFactory恍涂,BeanFactory根據(jù)使用場景創(chuàng)建FactoryBean。
- 裝飾設(shè)計(jì)模式:DataSource可以是不同的數(shù)據(jù)庫植榕,根據(jù)客戶端請求動態(tài)更改屬性達(dá)到連接不同數(shù)據(jù)源的目的再沧。
- 適配器模式:AOP的增強(qiáng)通知,如前置通知尊残、后置通知炒瘸、環(huán)繞通知等等淤堵。
- 模板方法模式:定義流程的算法骨架,把一些步驟延遲到子類中執(zhí)行顷扩,使得子類在不改變算法骨架的情況下重寫算法拐邪。
- 策略模式:定義一系列的算法并封裝起來,使得算法獨(dú)立也可以相互替換隘截。
Spring扎阶、SpringMVC、SpringBoot的區(qū)別
- Spring是一個(gè)IOC容器婶芭,用來集中管理Bean东臀,支持餓漢式初始化和懶加載,通過依賴注入實(shí)現(xiàn)控制反轉(zhuǎn)犀农,降低了代碼的耦合度惰赋,通過AOP面向切面編程為不同的功能引入公共行為,彌補(bǔ)了OOP面向?qū)ο蟠a冗余的問題井赌,用最小的侵入性實(shí)現(xiàn)松散耦合谤逼,可以很方便整合各種框架。
- SpringMVC是Spring對Web框架的一種解決方案仇穗,提供了前端控制器接收請求流部,通過定義的路由策略和視圖解析技術(shù)展現(xiàn)給前端。
- SpringBoot是Spring提供的快速開發(fā)工具纹坐,內(nèi)置了Web容器枝冀,可以直接啟動運(yùn)行Web應(yīng)用,管理了常用的第三方依賴包的版本耘子,減少了版本依賴的沖突果漾,提供了Java配置的方式,減少了大量的Xml配置谷誓,提供了很多的Starter結(jié)合自動配置绒障,對主流框架無配置集成,提供了監(jiān)控功能捍歪,可以查看應(yīng)用程序的運(yùn)行狀況户辱,如內(nèi)存、線程池糙臼、網(wǎng)絡(luò)請求統(tǒng)計(jì)等等庐镐。
SpringMVC的工作流程
- 用戶發(fā)送請求至前端控制器DispatcherServlet,DispatcherServlet調(diào)用HandlerMapping映射器变逃,HandlerMapping通過XML配置必逆、注解(@Controller)的方式找到后端控制器和攔截器,并返回給DispatcherServlet。
- DispatcherServlet通過HandlerAdapter處理適配器執(zhí)行Controller并返回結(jié)果ModelAndView名眉。
- DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器粟矿,通過解析生成View視圖,DispatcherServlet根據(jù)View進(jìn)行渲染璧针,響應(yīng)用戶嚷炉。
CAP 理論
- Consistency:一致性,即更新操作成功返回給客戶端后探橱,所有節(jié)點(diǎn)在同一時(shí)間的數(shù)據(jù)完全一致申屹。
- Availability:可用性,即服務(wù)一直可用隧膏,而且是正常響應(yīng)時(shí)間哗讥。
- Partition Tolerance:分區(qū)容錯性,即分布式系統(tǒng)在遇到某節(jié)點(diǎn)或網(wǎng)絡(luò)分區(qū)故障的時(shí)候胞枕,仍然能夠?qū)ν馓峁M足一致性和可用性的服務(wù)杆煞。
- CP是強(qiáng)一致性,AP是可用性腐泻,分區(qū)容錯時(shí)只能二選一决乎。
BASE 理論
- Basically Avaliable:基本可用,響應(yīng)時(shí)間上的損失和系統(tǒng)功能上的損失派桩。
- Soft State:軟狀態(tài)构诚,數(shù)據(jù)同步允許一定的延時(shí)。
- Eventually Consistent:最終一致性铆惑,系統(tǒng)中所有的數(shù)據(jù)副本范嘱,在經(jīng)過一段時(shí)間的同步后,最終能夠達(dá)到一致的狀態(tài)员魏。
GC如何判斷對象可以被回收
- 引用計(jì)數(shù)法:每個(gè)對象都有一個(gè)引用計(jì)數(shù)屬性丑蛤,新增一個(gè)引用時(shí)計(jì)數(shù)加一,釋放一個(gè)引用時(shí)計(jì)數(shù)減一撕阎,計(jì)數(shù)為零時(shí)可以回收受裹。
- 可達(dá)性分析法:從GC的Roots開始向下搜索,當(dāng)一個(gè)對象不存在引用鏈時(shí)可以回收虏束,常見的GC Roots對象有虛擬機(jī)棧的引用對象名斟、方法區(qū)的靜態(tài)引用對象和常量引用對象、本地方法棧的JNI引用對象魄眉、正在運(yùn)行的線程。不可達(dá)對象需要經(jīng)過兩次標(biāo)記過程闷袒,第一次是不存在引用鏈時(shí)坑律,第二次是執(zhí)行對象的finalize()方法。
消息隊(duì)列有哪些作用
- 解耦:系統(tǒng)間的通訊依賴消息隊(duì)列,單個(gè)系統(tǒng)獨(dú)立晃择。
- 異步:上游不受下游執(zhí)行結(jié)果影響時(shí)冀值,下游操作放在消息隊(duì)列中執(zhí)行,提高上游返回的效率宫屠。
- 流量削峰:在高并發(fā)的環(huán)境中列疗,系統(tǒng)在同一時(shí)間點(diǎn)接收大量的網(wǎng)絡(luò)請求容易引起宕機(jī),把網(wǎng)絡(luò)請求放在消息隊(duì)列中排隊(duì)消費(fèi)浪蹂,減輕了服務(wù)器承受的壓力抵栈。
- 使用場景:業(yè)務(wù)審批流的消息推送、系統(tǒng)功能錯誤日志的記錄坤次。
消息隊(duì)列如何保證消息的可靠傳輸
- 生產(chǎn)者不能重復(fù)生產(chǎn)消息古劲,消費(fèi)者不能重復(fù)消費(fèi)消息。
- 生產(chǎn)者發(fā)送成功的消息缰猴,消費(fèi)者一定能消費(fèi)成功产艾。
死信隊(duì)列和延時(shí)隊(duì)列分別是什么
- 死信隊(duì)列中存放著消費(fèi)失敗的消息,可用來消息的消費(fèi)重試滑绒。
- 延時(shí)隊(duì)列中存放著需要延時(shí)消費(fèi)的消息闷堡,可用來處理具有過期性的業(yè)務(wù),如訂單在十分鐘內(nèi)未完成支付則取消訂單疑故。
Kafka吞吐量高的原因
- 生產(chǎn)者采用異步發(fā)送消息機(jī)制杠览,消息緩存起來后就直接返回成功的操作提示。
- 當(dāng)緩存的消息量達(dá)到某個(gè)閾值時(shí)焰扳,批量發(fā)送給Broker處理倦零,減少了網(wǎng)絡(luò)的IO,從而提高了吞吐量吨悍。
- 但生產(chǎn)者宕機(jī)會導(dǎo)致消息丟失扫茅,通過降低可靠性來提高性能。
Netty和Tomcat的特點(diǎn)和區(qū)別
- Netty是基于NIO的異步網(wǎng)絡(luò)通訊框架育瓜,關(guān)注網(wǎng)絡(luò)數(shù)據(jù)的傳輸葫隙,不關(guān)注傳輸?shù)木W(wǎng)絡(luò)協(xié)議,可用于開發(fā)各種高效的網(wǎng)絡(luò)服務(wù)器躏仇。
- Tomcat是Web服務(wù)器恋脚,內(nèi)部只運(yùn)行Servlet的程序和處理http請求。
數(shù)據(jù)庫的事務(wù)ACID是怎么保證的
- A:原子性(Atomicity)焰手,事務(wù)需要回滾時(shí)從undo log中獲取信息糟描。
- C:一致性,由其他三大特征保證书妻,程序保證業(yè)務(wù)上的一致性船响。
- I:隔離性(Isolation),由多版本并發(fā)控制(Multi-Version Concurrency Control)保證。
- D:持久性(Duration)见间,事務(wù)需要前滾時(shí)從redo log中獲取信息聊闯。
MySQL中binlog、redolog米诉、undolog的區(qū)別和作用
- binlog是MySQL Service層的邏輯日志菱蔬,記錄了數(shù)據(jù)庫事務(wù)提交后的增刪改操作語句,日志文件寫滿后史侣,會寫入到另一個(gè)新的文件拴泌,適合用于備份,如主從復(fù)制抵窒。
- redolog和undolog是InnoDB引擎的日志弛针,用于支持事務(wù)。
- 事務(wù)執(zhí)行的完整過程李皇,執(zhí)行器先查詢數(shù)據(jù)是否在InnoDB存儲引擎的內(nèi)存中削茁,不在則從磁盤加載到內(nèi)存去,有則直接返回?cái)?shù)據(jù)掉房,然后把數(shù)據(jù)的舊值寫入undolog中茧跋,再把值更新到InnoDB存儲引擎的內(nèi)存中,再把數(shù)據(jù)的新值寫入redolog中卓囚,此時(shí)狀態(tài)為prepare瘾杭,當(dāng)事務(wù)發(fā)生回滾,先刪除prepare狀態(tài)的redolog哪亿,再根據(jù)undolog將數(shù)據(jù)還原粥烁,當(dāng)事務(wù)提交后,先把redolog的狀態(tài)改為commit蝇棉,再把binlog日志寫入磁盤讨阻。
MySQL 主從同步原理
- binlog是數(shù)據(jù)庫服務(wù)從啟用起記錄所有修改操作的文件。
- 當(dāng)主節(jié)點(diǎn)的binlog發(fā)生改變篡殷,log-dump線程會向從節(jié)點(diǎn)發(fā)送變化的binlog钝吮。
- 從節(jié)點(diǎn)的IO線程接收到binlog后,寫入到relaylog中板辽。
- 從節(jié)點(diǎn)的SQL線程讀取relaylog文件對數(shù)據(jù)更新進(jìn)行重放奇瘦,確保了數(shù)據(jù)的一致性。
Redis過期鍵的刪除策略
- 惰性過期:只有訪問key時(shí)劲弦,才判斷是否過期耳标,過期則刪除,該策略可以節(jié)省CPU資源邑跪,但對內(nèi)存不友好麻捻,如果大量的key沒有被再次訪問纲仍,就不會被刪除,占用大量內(nèi)存贸毕。
- 定期過期:每隔一段時(shí)間就去掃描expires字典剖煌,字典中保存了所有的key和expire-time端姚,從中清除已過期的key。
Redis內(nèi)存不足的淘汰策略
- volatile-lru:從設(shè)置了過期時(shí)間的數(shù)據(jù)集中篩選出最近使用最少的數(shù)據(jù)進(jìn)行淘汰牵啦。
- volatile-ttl:從設(shè)置了過期時(shí)間的數(shù)據(jù)集中篩選出即將要過期的數(shù)據(jù)進(jìn)行淘汰寇僧。
- volatile-random:從設(shè)置了過期時(shí)間的數(shù)據(jù)集中隨機(jī)篩選出數(shù)據(jù)進(jìn)行淘汰摊腋。
- allkeys-lru:從數(shù)據(jù)集中篩選出最近使用最少的數(shù)據(jù)進(jìn)行淘汰。
- allkeys-random:從數(shù)據(jù)集中隨機(jī)篩選出數(shù)據(jù)進(jìn)行淘汰嘁傀。
- noeviction:默認(rèn)配置兴蒸,禁止驅(qū)逐數(shù)據(jù),所有申請內(nèi)存的命令都引起報(bào)錯细办。
Redis單線程速度快的原因
- 核心基于非堵塞的IO多路復(fù)用機(jī)制橙凳。
- 單線程避免了多線程頻繁切換上下文的性能開銷。
- 純內(nèi)存操作笑撞。
Redis集群方案
- 哨兵模式:sentinel是redis集群非常重要的組件岛啸,本身就是分布式系統(tǒng)。
- 集群監(jiān)控:負(fù)責(zé)監(jiān)控主(master)從(slave)結(jié)構(gòu)中的每臺服務(wù)器是否正常工作茴肥。
- 消息通知:當(dāng)某個(gè)redis實(shí)例發(fā)生故障坚踩,哨兵會向其它哨兵和redis實(shí)例發(fā)送通知。
- 故障轉(zhuǎn)移:當(dāng)master服務(wù)掛掉后瓤狐,哨兵會選舉一個(gè)slave服務(wù)作為master服務(wù)瞬铸,告知其它slave服務(wù)新的連接地址并重新連接。
zookeeper和eureka的區(qū)別
- zookeeper的設(shè)計(jì)是強(qiáng)一致性础锐,是分布式的協(xié)調(diào)系統(tǒng)嗓节,用于資源的統(tǒng)一管理,當(dāng)節(jié)點(diǎn)crash后郁稍,需要進(jìn)行l(wèi)eader的選舉赦政,這期間zookeeper的服務(wù)是不可用的。
- eureka的設(shè)計(jì)是高可用性耀怜,是服務(wù)注冊發(fā)現(xiàn)系統(tǒng)恢着,用于微服務(wù)的注冊和發(fā)現(xiàn),各個(gè)節(jié)點(diǎn)都是平等的财破,當(dāng)一個(gè)節(jié)點(diǎn)crash后掰派,剩余的節(jié)點(diǎn)依然可以提供服務(wù)。
SpringCloud和Dubbo的區(qū)別
- 底層協(xié)議:SpringCloud基于http協(xié)議左痢,Dubbo基于tcp協(xié)議靡羡,決定了dubbo性能更好一些系洛。
- 注冊中心:SpringCloud使用的是eureka,Dubbo使用的是zookeeper略步。
- 模型定義:SpringCloud將一個(gè)應(yīng)用定義為服務(wù)描扯,Dubbo將一個(gè)接口定義為服務(wù)。SpringCloud是一個(gè)生態(tài)趟薄,而Dubbo是SpringCloud生態(tài)中關(guān)于服務(wù)治理的一種方案绽诚。
ThreadLocal的原理
- ThreadLocal是Java中所提供的線程本地存儲機(jī)制,可以把數(shù)據(jù)緩存到線程內(nèi)部杭煎。
- 每個(gè)Thread對象中都包含ThreadLocalMap恩够,key為ThreadLocal對象,value為緩存數(shù)據(jù)羡铲,在線程池中使用ThreadLocal會造成內(nèi)存泄漏蜂桶,原因是線程池的線程不會回收,ThreadLocal的引用也不會釋放也切,因此使用完需要手動調(diào)用ThreadLocal的remove方法扑媚。
- ThreadLocal的應(yīng)用場景是數(shù)據(jù)庫連接管理,線程之間不共享連接對象贾费,如Spring的事務(wù)管理就是基于單線程的钦购,Connection存放在線程內(nèi)部,因此Spring無法保證多線程事務(wù)的一致性褂萧。
ReentrantLock中的公平鎖和非公平鎖的原理
- 公平鎖:線程調(diào)用lock()方法時(shí)押桃,先檢查AQS隊(duì)列中是否存在線程在排隊(duì),如果有則排隊(duì)等待导犹,沒有則獲取到鎖唱凯。
- 非公平鎖:線程調(diào)用lock()方法時(shí),直接和AQS隊(duì)列的線程競爭鎖谎痢,如果獲取到鎖就結(jié)束了磕昼,沒有則加入AQS隊(duì)列等待。
類加載器的雙親委派模型节猿,有什么好處
- JVM中存在三個(gè)類加載器:BootstrapClassLoader > ExtClassLoader > AppClassLoader票从。
- JVM在加載一個(gè)類時(shí)會調(diào)用AppClassLoader的loadClass()方法,這里面又會調(diào)用ExtClassLoader的loadClass()方法滨嘱,這里面又會調(diào)用BootstrapClassLoader的loadClass()方法峰鄙,加載成功則直接返回,反之則往下執(zhí)行加載太雨。
- 好處在于加載安全吟榴,避免用戶編寫的類覆蓋了Java的核心類,也避免了類的重復(fù)加載囊扳。
Sychronized的偏向鎖吩翻、輕量級鎖兜看、重量級鎖
- 偏向鎖:Sychronized會在對象頭存放當(dāng)前線程的ID作為鎖的信息,當(dāng)線程下次再來訪問對象時(shí)狭瞎,可以直接獲得鎖细移,是可重入的概念。
- 輕量級鎖:由偏向鎖升級而來脚作,當(dāng)一個(gè)線程來獲取對象鎖時(shí)葫哗,對象頭已經(jīng)存在另一個(gè)線程的鎖信息時(shí),會進(jìn)行自旋來等待鎖球涛,這時(shí)不會堵塞線程。
- 重量級鎖:當(dāng)輕量級鎖自旋次數(shù)達(dá)到一定次數(shù)時(shí)仍沒有獲取到鎖時(shí)校镐,會升級成重量級鎖亿扁,這時(shí)會堵塞線程。
CopyOnWriteArrayList的實(shí)現(xiàn)原理
- 底層是對數(shù)組的封裝鸟廓,當(dāng)需要add元素時(shí)从祝,添加ReentrantLock鎖。
- 新增時(shí)通過復(fù)制舊數(shù)組來創(chuàng)建新數(shù)組引谜,新數(shù)組比舊數(shù)組的長度多一牍陌,再把新元素放到新數(shù)組的末位。
- 刪除時(shí)先找出被移除元素的下標(biāo)员咽,然后把該元素后面的元素下標(biāo)全部都往前進(jìn)一毒涧,再通過復(fù)制舊數(shù)組來創(chuàng)建新數(shù)組,新數(shù)組比舊數(shù)組的長度少一贝室。
- 當(dāng)需要get元素時(shí)契讲,不會添加鎖。
ConcurrentHashMap的實(shí)現(xiàn)原理
- 底層是Segment對象的數(shù)組滑频,Segment對象的結(jié)構(gòu)是數(shù)組+鏈表捡偏。
- 實(shí)現(xiàn)了鎖分段技術(shù),JDK7中鎖的粒度為Segment對象峡迷,JDK8中鎖的粒度為Segment對象的鏈表银伟,降低了鎖的粒度。
- put()方法和get()方法都需要調(diào)用二次hash()方法绘搞,第一次是定位到Segment對象彤避,第二次是定位到Segment對象的鏈表。
SpringMVC的九大核心組件
- HandlerMapping:用于接收用戶的請求看杭,根據(jù)訪問的url來找到對應(yīng)的Handler作出響應(yīng)忠藤。
- HandlerAdapter:用于Handler適配Servlet的請求,Servlet相當(dāng)固定楼雹,分為request和response模孩,Handler則形式多樣化尖阔。
- HandlerExceptionResolver:異常處理解析器,通過捕獲解析異常榨咐,返回ModelAndView對象介却。
- LocaleResolver:區(qū)域解析器,從request請求中解析出Locale對象块茁,用于配置國際化資源以及結(jié)合ViewResolver解析視圖齿坷。
- ViewResolver:視圖解析器,結(jié)合Local對象使用数焊,把String類型的視圖名解析成View類型的視圖永淌,用于渲染頁面。
- MultipartResolver:文件解析器佩耳,把request請求封裝為MultipartHttpServletRequest請求遂蛀,用于接收文件上傳請求并清理上傳過程產(chǎn)生的臨時(shí)資源。
- ThemeResolver:主題解析器干厚,用于解析*.properties文件李滴,同時(shí)支持國際化。
- FlashMapManager:用于管理FlashMap蛮瞄,F(xiàn)lashMap主要用在redirect中傳遞參數(shù)所坯。
- RequestToViewNameTranslator:從request請求中獲取ViewName,交由ViewResolver查找View視圖挂捅。
分布式事務(wù)的解決方案有哪些
- 2PC(Prepare Commit):第一階段芹助,事務(wù)管理器(協(xié)調(diào)者)會執(zhí)行SQL腳本,但不會提交事務(wù)籍凝,此時(shí)數(shù)據(jù)庫資源被鎖定周瞎,資源管理器(參與者)將undo和redo寫入事務(wù)日志,第二階段饵蒂,資源管理器根據(jù)操作結(jié)果提交事務(wù)或者回滾事務(wù)声诸,釋放資源。缺點(diǎn)是協(xié)調(diào)者或者參與者宕機(jī)會引起數(shù)據(jù)不一致退盯。
- 3PC(Prepare Commit):第一階段CanCommit彼乌,協(xié)調(diào)者詢問參與者是否可以提交事務(wù),第二階段PreCommit渊迁,協(xié)調(diào)者執(zhí)行SQL腳本但不提交事務(wù)慰照,第三階段DoCommit,如果二階段中參與者宕機(jī)或者預(yù)提交操作失敗則執(zhí)行回滾琉朽,反之執(zhí)行事務(wù)的提交毒租,釋放資源。優(yōu)點(diǎn)是加入超時(shí)機(jī)制箱叁,解決2PC宕機(jī)時(shí)遇到的問題墅垮。
- TCC(Try Confirm Cancel):通過系統(tǒng)提供的業(yè)務(wù)邏輯流程調(diào)度惕医,分為三個(gè)步驟,首先是try(entity)算色,這個(gè)過程會鎖定資源抬伺,給所有服務(wù)提供更新的預(yù)校驗(yàn),如庫存更新時(shí)分為即時(shí)庫存和可用庫存灾梦,此階段將會凍結(jié)部分可用庫存峡钓,同時(shí)會記錄即時(shí)庫存、凍結(jié)庫存若河、可用庫存的日志能岩,滿足條件時(shí)再執(zhí)行Confirm(entity),此階段將會實(shí)際更新即時(shí)庫存萧福,同時(shí)會記錄即時(shí)庫存捧灰、凍結(jié)庫存、可用庫存的日志统锤,當(dāng)所有服務(wù)提交成功時(shí)釋放資源,當(dāng)某個(gè)服務(wù)提交失敗時(shí)炭庙,再執(zhí)行所有服務(wù)的Cancel(entity)饲窿,把數(shù)據(jù)統(tǒng)一回滾,此階段將會反凍結(jié)部分可用庫存焕蹄,同時(shí)會記錄即時(shí)庫存逾雄、凍結(jié)庫存、可用庫存的日志腻脏,保證了數(shù)據(jù)的一致性鸦泳。
- AT(Auto Transcation):業(yè)務(wù)無侵入二階段提交,在一階段中Seata會攔截業(yè)務(wù)SQL永品,解析其語義并找到需要更新的業(yè)務(wù)數(shù)據(jù)做鹰,在更新前把數(shù)據(jù)保存為前鏡像(before-image),再執(zhí)行業(yè)務(wù)SQL更新數(shù)據(jù)鼎姐,在更新后把數(shù)據(jù)保存為后鏡像(after-image)钾麸,最后生成行鎖(避免臟讀),保證了一階段的原子性炕桨。在二階段提交時(shí)饭尝,只需將一階段的鏡像和行鎖刪除即可。在二階段回滾時(shí)献宫,先對比數(shù)據(jù)庫當(dāng)前的業(yè)務(wù)數(shù)據(jù)和后鏡像的業(yè)務(wù)數(shù)據(jù)是否相同钥平,如果相同則說明沒有臟寫,通過前鏡像的業(yè)務(wù)數(shù)據(jù)還原到數(shù)據(jù)庫姊途,最后把一階段的鏡像和行鎖刪除涉瘾,反之需要人工處理知态。
- Seata框架:提供了AT 模式、TCC 模式睡汹、Saga 模式和 XA 模式四種分布式事務(wù)解決方案肴甸。
泛型中extends和super的區(qū)別
- <? extends T> 表示包括T在內(nèi)的任何子類。
- <? super T> 表示包括T在內(nèi)的任何父類囚巴。
TCP的三次握手和四次揮手
- TCP協(xié)議是七層網(wǎng)絡(luò)協(xié)議中的傳輸層協(xié)議原在,負(fù)責(zé)數(shù)據(jù)的可靠傳輸。
- 在建立TCP連接時(shí)彤叉,需要通過三次握手庶柿,首先是客戶端向服務(wù)端發(fā)送SYN(Synchronize Sequence Numbers),其次是服務(wù)端接收到SYN后給客戶端返回SYN_ACK秽浇,最后是客戶端接收到SYN_ACK后給服務(wù)端發(fā)送一個(gè)ACK(Acknowledge character)浮庐。
- 在斷開TCP連接時(shí),需要通過四次揮手柬焕,首先是客戶端向服務(wù)端發(fā)送FIN(finish)审残,其次是服務(wù)端接收到FIN后向客戶端發(fā)送ACK,意味著服務(wù)端接收到斷開連接的請求斑举,客戶端可以不發(fā)送數(shù)據(jù)了搅轿,但服務(wù)端可能還有數(shù)據(jù)在處理,待數(shù)據(jù)完成處理后富玷,服務(wù)端向客戶端發(fā)送FIN璧坟,表示當(dāng)前可以斷開連接,最后是客戶端接收到FIN后向服務(wù)端發(fā)送ACK赎懦,表示當(dāng)前也可以斷開連接雀鹃。
HTTPS如何保證安全傳輸
- 通過使用對稱加密、非對稱加密励两、數(shù)字證書等方式來保證數(shù)據(jù)的安全傳輸黎茎。
- 客戶端向服務(wù)端發(fā)送數(shù)據(jù)前,需要先建立TCP連接伐蒋,建立完成后服務(wù)端會向客戶端發(fā)送公鑰工三,客戶端通過公鑰來對傳輸數(shù)據(jù)進(jìn)行加密,服務(wù)端接收到傳輸數(shù)據(jù)后通過私鑰進(jìn)行解密先鱼,這種就是非對稱加密俭正。
- 服務(wù)端向客戶端發(fā)送非對稱公鑰時(shí),可以先把非對稱公鑰和服務(wù)端相關(guān)信息通過hash算法生成消息摘要焙畔,再通過數(shù)字證書提供的私鑰對消息摘要進(jìn)行加密生成數(shù)字簽名掸读,再把服務(wù)端相關(guān)信息和數(shù)字簽名一起形成數(shù)字證書發(fā)送到客戶端,客戶端通過數(shù)字證書提供的公鑰進(jìn)行解密,從而得到非對稱加密的公鑰儿惫。
- 在服務(wù)端給客戶端傳輸?shù)倪^程中澡罚,數(shù)據(jù)包可能會被中間人截獲,同時(shí)被解密出非對稱的公鑰肾请,但是中間人是沒辦法偽造數(shù)字證書發(fā)送給客戶端的留搔,生成數(shù)字證書需要私鑰,網(wǎng)站如果需要支持HTTPS铛铁,就需要申請數(shù)字證書的私鑰隔显,這樣就確保安全了。
Dubbo的工作流程
- Spring容器啟動時(shí)饵逐,Dubbo的Provider會同時(shí)啟動括眠,向Zookeeper服務(wù)中心注冊相關(guān)信息,如IP倍权、端口掷豺、接口、版本薄声、協(xié)議等当船。
- Dubbo的Consumer啟動時(shí),會去Zookeeper中獲取已注冊服務(wù)的信息默辨,當(dāng)Provider的信息發(fā)生變化時(shí)生年,Zookeeper會向Consumer推送通知。
- Consumer通過RPC的方式調(diào)用Provider的方法廓奕,每隔兩分鐘,Provider和Consumer都會向Monitor發(fā)送訪問次數(shù)档叔,由Monitor進(jìn)行統(tǒng)計(jì)桌粉。
如何進(jìn)行自我介紹
- 基本信息,姓名衙四、年齡铃肯、學(xué)校、學(xué)歷传蹈。
- 工作經(jīng)驗(yàn)押逼,最近一段時(shí)間開發(fā)的最熟悉、最有價(jià)值惦界、技術(shù)棧最豐富的項(xiàng)目挑格,在項(xiàng)目中承擔(dān)的主要職責(zé)以及解決項(xiàng)目的主要問題。
- 企業(yè)背調(diào)沾歪,說下對這家面試公司的了解漂彤,行業(yè)解決方案。
- 面試官,上面就是我的個(gè)人簡介挫望,您看您有什么想了解的立润。
如何陳述自己的項(xiàng)目
- 用一個(gè)最近且最熟悉的項(xiàng)目進(jìn)行陳述。
- 描述項(xiàng)目的核心價(jià)值和包含的功能以及參與的核心模塊和使用到的技術(shù)棧媳板。
- 描述項(xiàng)目開發(fā)過程中存在的技術(shù)問題以及解決思路和方案桑腮。
- 面試官,上面就是我的項(xiàng)目經(jīng)驗(yàn)的簡單介紹蛉幸,您看您有什么想問的破讨。
如何回答自己會的問題
- 按照總分的思想,分步驟來說明實(shí)現(xiàn)的機(jī)制巨缘,結(jié)合實(shí)際項(xiàng)目經(jīng)驗(yàn)談怎么解決添忘。
- 面試官,我已經(jīng)回答完了若锁,剛剛是我對于這個(gè)知識的理解搁骑,您看一下哪里有問題,可以幫我指點(diǎn)下又固。
如何回答自己不會的問題
- 有一點(diǎn)了解或者接觸過類似的仲器,按照知道的表述出來。
- 一點(diǎn)都不會仰冠,可以問面試官乏冀,這個(gè)技術(shù)在項(xiàng)目中有什么作用。
如何回答自己的缺點(diǎn)
- 把優(yōu)點(diǎn)說成缺點(diǎn)洋只,如個(gè)人執(zhí)著辆沦、代碼潔癖等等。
如何回答自己的職業(yè)規(guī)劃
- 我從不做三年以上的職業(yè)規(guī)劃识虚,但我的終極目標(biāo)是系統(tǒng)架構(gòu)師肢扯。
- 如果我有幸入職貴公司的話,我會從本職工作做起担锤,爭取讓自己先做到高級開發(fā)工程師蔚晨。
- 我相信在貴公司的平臺下,我能獲得更好的發(fā)展肛循,取得更高的成就铭腕,給公司創(chuàng)造更大的價(jià)值。
- 如果我有幸入職的話多糠,貴公司對我的安排是怎樣的累舷。
如何回答離職原因
- 千萬不要說上家公司的不好,這是禁忌夹孔。
- 公司倒閉笋粟、不發(fā)工資怀挠、仲裁。
- 之前的項(xiàng)目一直在改動害捕,沒有新項(xiàng)目绿淋。
- 個(gè)人發(fā)展問題。
如何回答你有什么想問的
- HR尝盼,公司福利吞滞、晉升機(jī)制、加班情況等等盾沫。
- 面試官裁赠,公司內(nèi)部有沒有技術(shù)培訓(xùn)或者技術(shù)分享,開發(fā)團(tuán)隊(duì)的規(guī)模赴精,行業(yè)解決方案中使用到的技術(shù)佩捞,如果有幸入職公司對自己的安排。