面向?qū)ο蟮娜筇卣?/h3>
- 封裝
把客觀事物封裝成抽象的類澈段,并且類可以把自己的數(shù)據(jù)和方法只讓可信的類或?qū)ο蟛僮骱行叮瑢Σ豢尚诺男畔⑦M(jìn)行隱藏。
- 繼承
對象的繼承關(guān)系代表了一種‘is a’的關(guān)系海蔽,比如A和B撼嗓,可以描述為‘B是A’,表明B繼承A细移。
- 多態(tài)
接口的多種不同的實(shí)現(xiàn)方式即為多態(tài)搏予。
面向?qū)ο蠛兔嫦蜻^程的區(qū)別
面向過程:
- 優(yōu)點(diǎn):性能比面向?qū)ο蟾撸驗(yàn)轭愓{(diào)用時(shí)需要實(shí)例化弧轧,開銷比較大雪侥,比較消耗資源;比如單片機(jī)、嵌入式開發(fā)精绎、Linux/Unix等一般采用面向過程開發(fā)速缨,性能是最重要的因素。
- 缺點(diǎn):沒有面向?qū)ο笠拙S護(hù)代乃、易復(fù)用旬牲、易擴(kuò)展
面向?qū)ο螅?/h5>
- 優(yōu)點(diǎn):易維護(hù)仿粹、易復(fù)用、易擴(kuò)展原茅,由于面向?qū)ο笥蟹庋b吭历、繼承、多態(tài)性的特性擂橘,可以設(shè)計(jì)出低耦合的系統(tǒng)晌区,使系統(tǒng)更加靈活、更加易于維護(hù)
- 缺點(diǎn):性能比面向過程低
Java代碼的運(yùn)行
把客觀事物封裝成抽象的類澈段,并且類可以把自己的數(shù)據(jù)和方法只讓可信的類或?qū)ο蟛僮骱行叮瑢Σ豢尚诺男畔⑦M(jìn)行隱藏。
對象的繼承關(guān)系代表了一種‘is a’的關(guān)系海蔽,比如A和B撼嗓,可以描述為‘B是A’,表明B繼承A细移。
接口的多種不同的實(shí)現(xiàn)方式即為多態(tài)搏予。
- 優(yōu)點(diǎn):易維護(hù)仿粹、易復(fù)用、易擴(kuò)展原茅,由于面向?qū)ο笥蟹庋b吭历、繼承、多態(tài)性的特性擂橘,可以設(shè)計(jì)出低耦合的系統(tǒng)晌区,使系統(tǒng)更加靈活、更加易于維護(hù)
- 缺點(diǎn):性能比面向過程低
Java代碼的運(yùn)行
源代碼->編譯器將源代碼編譯為字節(jié)碼->JVM(Java虛擬機(jī)) 解釋器將字節(jié)碼解釋為可執(zhí)行的二進(jìn)制機(jī)器碼->程序運(yùn)行
JDK與JRE
JDK是Sun Microsystems針對Java開發(fā)人員發(fā)布的免費(fèi)軟件開發(fā)工具包(SDK通贞,Software development kit)朗若。除JRE(Java Runtime Environment),也就是Java運(yùn)行環(huán)境外還包含提供給開發(fā)者使用的javac(編譯器)昌罩、jar(打包器)捡偏、javadoc(文檔生成器)等工具包。
重載(overloading)與重寫(overriding)
- 重載
1.是在一個類里面峡迷,方法名字相同银伟,而參數(shù)不同。返回類型可以相同也可以不同绘搞。
2.每個重載的方法(或者構(gòu)造函數(shù))都必須有一個獨(dú)一無二的參數(shù)類型列表彤避。
3.最常用的地方就是構(gòu)造器的重載。 - 重寫
1.重寫是子類對父類的允許訪問的方法的實(shí)現(xiàn)過程進(jìn)行重新編寫, 返回值和形參都不能改變夯辖。
2.重寫方法不能拋出新的檢查異沉鹪ぃ或者比被重寫方法申明更加寬泛的異常。
把客觀事物封裝成抽象的類蒿褂,并且類可以把自己的數(shù)據(jù)和方法只讓可信的類或?qū)ο蟛僮髟裁祝瑢Σ豢尚诺男畔⑦M(jìn)行隱藏。
equals與==的區(qū)別
1.對于字符串變量來說啄栓,使用“==”和“equals()”方法比較字符串時(shí)娄帖,其比較方法不同£汲“==”比較兩個變量本身的值近速,即兩個對象在內(nèi)存中的首地址】熬桑“equals()”比較字符串中所包含的內(nèi)容是否相同削葱。
2.對于非字符串變量來說,"=="和"equals"方法的作用是相同的都是用來比較其對象在堆內(nèi)存的首地址淳梦,即用來比較兩個引用變量是否指向同一個對象析砸。
String、StringBuff爆袍、StringBuild的區(qū)別
- String類保存字符串的方式為:private final char value[]首繁,所以string對象不可變作郭。StringBuilder與StringBuffer都繼承自AbstractStringBuilder類,在AbstractStringBuilder中保存字符串的方式為char[] value蛮瞄,所以StringBuilder對象與StringBuilder對象可變所坯。
- String是常量谆扎,線程安全挂捅。StringBuff,對調(diào)用方法加了同步鎖(synchronized)因此線程安全堂湖,StringBuild闲先,未加鎖因此線程不安全。
- String改變會生成新的String對象无蜂,相對效率較低伺糠,StringBuff與StringBuild改變不會產(chǎn)生新的對象,并且StringBuild未加鎖斥季,因此效率最高训桶,但是可能存在線程安全的問題。操作少量數(shù)據(jù)時(shí)酣倾,使用String對象舵揭,操作大量數(shù)據(jù),單線程時(shí)使用StringBuild躁锡,多線程時(shí)使用StringBuff午绳。
類成員訪問修飾符
訪問修飾符 | 同一個類 | 同包 | 不同包,子類 | 不同包映之,非子類 |
---|---|---|---|---|
private | √ | |||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
默認(rèn) | √ | √ |
”static”關(guān)鍵字是什么意思拦焚?Java中是否可以覆蓋(override)一個static方法?
“static”關(guān)鍵字表明一個成員變量或者是成員方法可以在沒有所屬的類的實(shí)例變量的情況下被訪問杠输。Java中static方法不能被覆蓋赎败,因?yàn)榉椒ǜ采w是基于運(yùn)行時(shí)動態(tài)綁定的,而static方法是編譯時(shí)靜態(tài)綁定的蠢甲。static方法跟類的任何實(shí)例都不相關(guān)螟够,所以概念上不適用。
Java語言支持的8中基本數(shù)據(jù)類型對應(yīng)的長度峡钓、對應(yīng)的包裝類
基本數(shù)據(jù)類型 | 長度(字節(jié)) | 包裝類 | 默認(rèn)值 |
---|---|---|---|
boolean | 1 | Boolean | false |
byte | 1 | Byte | (byte)0 |
char | 2 | Character | '/uoooo'(null) |
short | 2 | Short | (short)0 |
int | 4 | Integer | 0 |
long | 8 | Long | 0L |
float | 4 | Float | 0.0f |
double | 8 | Double | 0.0d |
接口和抽象類的區(qū)別
- 類可以實(shí)現(xiàn)多個接口妓笙,但只能繼承一個抽象類
- 接口中所有的方法都是抽象的。而抽象類則可以包含非抽象的方法能岩。
- 都不可被實(shí)例化寞宫,但抽象類如果包含main方法是可以被調(diào)用的。
final拉鹃、finally辈赋、finalize
- final: 常量聲明鲫忍。final類無法繼承,final方法無法重寫钥屈,final值無法改變悟民。
- finally: 處理異常。 不管有無異常都會執(zhí)行的塊篷就,關(guān)閉連接通常在其中完成射亏。
- finalize: 幫助進(jìn)行垃圾回收。finalize()方法在一個對象被銷毀和回收前會被調(diào)用竭业。
native方法是什么智润?
native方法是非Java代碼實(shí)現(xiàn)的方法。
如何原地交換兩個變量的值未辆?
- 加減法
int a = 5,b = 10;
a = a + b;
b = a - b;
a = a - b;
同理可用乘除法窟绷。
注意類型范圍,防止溢出咐柜。
-
異或法
int a = 5,b = 10;
a = a ^ b;//1111 = 101 ^ 1010;
b = b ^ a;
a = a ^ b;
用最有效率的方法計(jì)算 2 乘以 8
2 << 3(左移3位相當(dāng)于乘以2的3次方兼蜈,右移3位相當(dāng)于除以2的3次方)。
集合框架中的泛型有什么優(yōu)點(diǎn)拙友?
Java1.5 引入了泛型为狸,所有的集合接口和實(shí)現(xiàn)都大量地使用它。泛型允許我們?yōu)榧咸峁┮粋€可以容納的對象類型献宫。因此钥平,如果你添加其它類型的任何元素,它會在編譯時(shí)報(bào)錯姊途。這避免了在運(yùn)行時(shí)出現(xiàn) ClassCastException涉瘾,因?yàn)槟銓诰幾g時(shí)得到報(bào)錯信息。泛型也使得代碼整潔捷兰,我們不需要使用顯式轉(zhuǎn)換和 instanceOf 操作符立叛。它也給運(yùn)行時(shí)帶來好處,因?yàn)椴粫a(chǎn)生類型檢查的字節(jié)碼指令贡茅。
Java 集合框架的基礎(chǔ)接口有哪些秘蛇?
- Collection 為集合層級的根接口。一個集合代表一組對象顶考,這些對象即為它的元素赁还。Java 平臺不提供這個接口任何直接的實(shí)現(xiàn)。
- Set 是一個不能包含重復(fù)元素的集合驹沿。這個接口對數(shù)學(xué)集合抽象進(jìn)行建模艘策,被用來代表集合,就如一副牌渊季。
- List 是一個有序集合朋蔫,可以包含重復(fù)元素罚渐。你可以通過它的索引來訪問任何元素。List 更像長度動態(tài)變換的數(shù)組驯妄。
- Map 是一個將 key 映射到 value 的對象荷并。一個 Map 不能包含重復(fù)的 key,每個 key 最多只能映射一個 value青扔。盡管 Map 接口和它的實(shí)現(xiàn)也是集合框架的一部分源织,但 Map 不是集合,集合也不是 Map赎懦。因此雀鹃,Map 繼承 Collection 毫無意義幻工,反之亦然励两。如果 Map 繼承 Collection 接口,那么元素去哪兒囊颅?Map 包含key-value 對当悔,它提供抽取 key 或 value 列表集合的方法,但是它不適合“一組對象”規(guī)范踢代。
-
一些其它的接口有 Queue盲憎、Dequeue、SortedSet胳挎、SortedMap 和 ListIterator饼疙。
集合框架圖
Iterator 和 ListIterator 的區(qū)別是什么?
- Iterator 可用來遍歷 Set 和 List 集合慕爬,但是 ListIterator 只能用來遍歷 List窑眯。
- Iterator 對集合只能是前向遍歷,ListIterator 既可以前向也可以后向医窿。
- ListIterator 實(shí)現(xiàn)了 Iterator 接口磅甩,并包含其他的功能。比如:增加元素姥卢,替換元素卷要,獲取前一個和后一個元素的索引等等。
Java 中的 HashMap 的工作原理是什么独榴?
簡單來說僧叉,HashMap由數(shù)組+鏈表組成的,數(shù)組是HashMap的主體棺榔,鏈表則是主要為了解決哈希沖突而存在的瓶堕,如果定位到的數(shù)組位置不含鏈表(當(dāng)前entry的next指向null),那么對于查找,添加等操作很快掷豺,僅需一次尋址即可捞烟;如果定位到的數(shù)組包含鏈表薄声,對于添加操作,其時(shí)間復(fù)雜度為O(n)题画,首先遍歷鏈表默辨,存在即覆蓋,否則新增苍息;對于查找操作來講缩幸,仍需遍歷鏈表,然后通過key對象的equals方法逐一比對查找竞思。所以表谊,性能考慮,HashMap中的鏈表出現(xiàn)越少盖喷,性能才會越好爆办。
HashMap 和 HashTable 有什么區(qū)別?
- HashMap 是非線程安全的课梳,HashTable 是線程安全的距辆。
- HashMap 的鍵和值都允許有 null 值存在,而 HashTable 則不行暮刃。
- 因?yàn)榫€程安全的問題跨算,HashMap 效率比 HashTable 的要高。
- HashTable 是同步的椭懊,而 HashMap 不是诸蚕。因此,HashMap 更適合于單線程環(huán)境氧猬,而 HashTable 適合于多線程環(huán)境背犯。
- 一般現(xiàn)在不建議用 HashTable,一是 HashTable 是遺留類狂窑,內(nèi)部實(shí)現(xiàn)很多沒優(yōu)化和冗余媳板。二是即使在多線程環(huán)境下,現(xiàn)在也有同步的 ConcurrentHashMap 替代泉哈,沒有必要因?yàn)槭嵌嗑€程而用 HashTable蛉幸。
ConcurrentHashMap的并發(fā)度是什么?
ConcurrentHashMap把實(shí)際map劃分成若干部分來實(shí)現(xiàn)它的可擴(kuò)展性和線程安全丛晦。這種劃分是使用并發(fā)度獲得的奕纫,它是ConcurrentHashMap類構(gòu)造函數(shù)的一個可選參數(shù),ConcurrentHashMap的并發(fā)度就是segment的大小烫沙,默認(rèn)值為16匹层,這意味著最多同時(shí)可以有16條線程操作ConcurrentHashMap,這樣在多線程情況下就能避免爭用。
快速失斏ぁ(fail-fast)和安全失敵湃帷(fail-safe)的區(qū)別是什么?
- 快速失斈谩:當(dāng)你在迭代一個集合的時(shí)候铅忿,如果有另一個線程正在修改你正在訪問的那個集合時(shí),就會拋出一個 ConcurrentModification 異常灵汪。 在 java.util 包下的都是快速失敗檀训。
- 安全失敗:你在迭代的時(shí)候會去底層集合做一個拷貝享言,所以你在修改上層集合的時(shí)候是不會受影響的峻凫,不會拋出 ConcurrentModification 異常。在java.util.concurrent 包下的全是安全失敗的览露。
值傳遞與引用傳遞
- 值傳遞
對象被值傳遞荧琼,意味著傳遞了對象的一個副本。因此肛循,就算是改變了對象副本铭腕,也不會影響源對象的值银择。我們可以來看下面的一個例子:
public class Break {
public static void change(int a) {
a = 1;
}
public static void main(String[] args) {
int a = 2;
System.out.println(a);
change(a);
System.out.println(a);
}
}
輸出結(jié)果是: 2 2
這個只是傳遞一份拷貝多糠,和a的值沒有什么關(guān)系,也可以看成是方法change的值沒有一個變量來接收浩考。
2.引用傳遞
對象被引用傳遞夹孔,意味著傳遞的并不是實(shí)際的對象,而是對象的引用析孽。因此搭伤,外部對引用對象所做的改變會反映到所有的對象上。
public class Break {
public static void change(int[] a) {
a[0] = 3;
}
public static void main(String[] args) {
int[] a = {1, 2};
System.out.println(a[0]);
change(a);
System.out.println(a[0]);
}
}
輸出結(jié)果是: 1 3
這個傳遞的袜瞬,就是實(shí)際傳遞的是引用的地址值怜俐。所以a[0]的值會改變。
什么是線程邓尤?線程和進(jìn)程區(qū)別在哪拍鲤?
- 線程是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位,它被包含在進(jìn)程之中汞扎,是進(jìn)程中的實(shí)際運(yùn)作單位季稳。
- 線程是進(jìn)程的子集,一個進(jìn)程可以有很多線程澈魄,每條線程并行執(zhí)行不同的任務(wù)景鼠。不同的進(jìn)程使用不同的內(nèi)存空間,而所有的線程共享一片相同的內(nèi)存空間痹扇。每個線程都擁有單獨(dú)的棧內(nèi)存用來存儲本地?cái)?shù)據(jù)铛漓。
Java中用到的線程調(diào)度算法是什么溯香?
搶占式。一個線程用完CPU之后浓恶,操作系統(tǒng)會根據(jù)線程優(yōu)先級逐哈、線程饑餓情況等數(shù)據(jù)算出一個總的優(yōu)先級并分配下一個時(shí)間片給某個線程執(zhí)行。
如何實(shí)現(xiàn)多線程问顷?
java.lang.Thread 類的實(shí)例就是一個線程昂秃,但是它需要調(diào)用java.lang.Runnable接口來執(zhí)行,由于線程類本身就是調(diào)用的Runnable接口杜窄,所以你可以繼承java.lang.Thread 類或者直接調(diào)用Runnable接口來重寫run()方法實(shí)現(xiàn)線程肠骆。
用Thread還是用Runnable?
大家都知道我們可以通過繼承Thread類或者調(diào)用Runnable接口來實(shí)現(xiàn)線程塞耕,問題是蚀腿,那個方法更好呢?什么情況下使用它扫外?這個問題很容易回答莉钙,如果你知道Java不支持類的多重繼承,但允許你調(diào)用多個接口筛谚。所以如果你要繼承其他類磁玉,當(dāng)然是調(diào)用Runnable接口好了。
Thread 類中的start() 和 run() 方法有什么區(qū)別驾讲?
這個問題經(jīng)常被問到蚊伞,但還是能從此區(qū)分出面試者對Java線程模型的理解程度。start()方法被用來啟動新創(chuàng)建的線程吮铭,而且start()內(nèi)部調(diào)用了run()方法时迫,這和直接調(diào)用run()方法的效果不一樣。當(dāng)你調(diào)用run()方法的時(shí)候谓晌,只會是在原來的線程中調(diào)用掠拳,沒有新的線程啟動,start()方法才會啟動新線程纸肉。
Runnable和Callable有什么不同溺欧?
使用ExecutorService、Callable毁靶、Future可以實(shí)現(xiàn)有返回結(jié)果的多線程胧奔。
Runnable和Callable都代表那些要在不同的線程中執(zhí)行的任務(wù)。Runnable從JDK1.0開始就有了预吆,Callable是在JDK1.5增加的龙填。它們的主要區(qū)別是Callable的 call() 方法可以返回值和拋出異常,而Runnable的run()方法沒有這些功能。Callable可以返回裝載有計(jì)算結(jié)果的Future對象岩遗。
常用線程池
- newCachedThreadPool創(chuàng)建一個可緩存線程池程
- newFixedThreadPool 創(chuàng)建一個定長線程池
- newScheduledThreadPool 創(chuàng)建一個定長線程池扇商,支持定時(shí)及周期性任務(wù)執(zhí)行
-
newSingleThreadExecutor 創(chuàng)建一個單線程化的線程池
線程池工作流程圖.png
sleep和wait的區(qū)別
- sleep是Thread線程類的方法,而wait是Object頂級類的方法宿礁。
- sleep可以在任何地方使用案铺,而wait只能在同步方法或者同步塊中使用。
- sleep,wait調(diào)用后都會暫停當(dāng)前線程并讓出cpu的執(zhí)行時(shí)間梆靖,但不同的是sleep不會釋放當(dāng)前持有的對象的鎖資源控汉,到時(shí)間后會繼續(xù)執(zhí)行,而wait會放棄所有鎖并需要notify/notifyAll后重新獲取到對象鎖資源后才能繼續(xù)執(zhí)行返吻。
- sleep需要捕獲或者拋出異常姑子,而wait/notify/notifyAll不需要。
如何強(qiáng)制啟動一個線程测僵?
這個問題就像是如何強(qiáng)制進(jìn)行Java垃圾回收街佑,目前還沒有可靠方法,雖然你可以使用System.gc()來進(jìn)行垃圾回收捍靠,但是不保證能成功沐旨。在Java里面沒有辦法強(qiáng)制啟動一個線程,它是被線程調(diào)度器控制著且Java沒有公布相關(guān)的API榨婆。
volatile關(guān)鍵字的作用是什么磁携?
- 多線程使用volatile關(guān)鍵字修飾的變量,保證了其在多線程之間的可見性纲辽,即每次讀取到volatile變量颜武,一定是最新的數(shù)據(jù)。
- Java代碼執(zhí)行中拖吼,為了獲取更好的性能JVM可能會對指令進(jìn)行重排序,多線程下可能會出現(xiàn)一些意想不到的問題这吻。使用volatile則會對禁止語義重排序吊档,當(dāng)然這也一定程度上降低了代碼執(zhí)行效率。
什么是樂觀鎖和悲觀鎖唾糯?
- 樂觀鎖:對于并發(fā)間操作產(chǎn)生的線程安全問題持樂觀狀態(tài)怠硼,樂觀鎖認(rèn)為競爭不總是會發(fā)生,因此它不需要持有鎖移怯,將比較-設(shè)置這兩個動作作為一個原子操作嘗試去修改內(nèi)存中的變量香璃,如果失敗則表示發(fā)生沖突婿脸,那么就應(yīng)該有相應(yīng)的重試邏輯汇荐。
- 悲觀鎖:對于并發(fā)間操作產(chǎn)生的線程安全問題持悲觀狀態(tài)病梢,悲觀鎖認(rèn)為競爭總是會發(fā)生险污,因此每次對某資源進(jìn)行操作時(shí)幻件,都會持有一個獨(dú)占的鎖,就像synchronized刻两,直接對操作資源上了鎖外恕。
共享鎖和排它鎖
- 共享鎖【S鎖,MyISAM 叫做讀鎖】
又稱讀鎖学少,若事務(wù)T對數(shù)據(jù)對象A加上S鎖剪个,則事務(wù)T可以讀A但不能修改A,其他事務(wù)只能再對A加S鎖版确,而不能加X鎖扣囊,直到T釋放A上的S鎖。這保證了其他事務(wù)可以讀A绒疗,但在T釋放A上的S鎖之前不能對A做任何修改如暖。
select * from table lock in share mode
- 排他鎖【X鎖,MyISAM 叫做寫鎖】
數(shù)據(jù)庫的增刪改操作默認(rèn)都會加排他鎖忌堂,而查詢不會加任何鎖盒至。
又稱寫鎖。若事務(wù)T對數(shù)據(jù)對象A加上X鎖士修,事務(wù)T可以讀A也可以修改A枷遂,其他事務(wù)不能再對A加任何鎖,直到T釋放A上的鎖棋嘲。這保證了其他事務(wù)在T釋放A上的鎖之前不能再讀取和修改A酒唉。
select * from table for update
- 計(jì)劃鎖
- 意向鎖
- 意向共享鎖
- 意向排它鎖
可重入鎖、可中斷鎖沸移、公平鎖痪伦、讀寫鎖
- 可重入鎖實(shí)際是指鎖的分配機(jī)制:基于線程的分配,而不是基于方法調(diào)用的分配雹锣。synchronized和Lock都具備可重入性网沾。
- 可中斷鎖,顧名思義蕊爵,就是可以相應(yīng)中斷的鎖辉哥。在Java中,synchronized就不是可中斷鎖攒射,而Lock是可中斷鎖醋旦。
- 公平鎖即盡量以請求鎖的順序來獲取鎖。在Java中会放,synchronized就是非公平鎖饲齐,它無法保證等待的線程獲取鎖的順序。而對于ReentrantLock和ReentrantReadWriteLock咧最,它默認(rèn)情況下是非公平鎖捂人,但是可以設(shè)置為公平鎖御雕。
- 讀寫鎖將對一個資源(比如文件)的訪問分成了2個鎖,一個讀鎖和一個寫鎖先慷。ReadWriteLock就是讀寫鎖饮笛,它是一個接口,ReentrantReadWriteLock實(shí)現(xiàn)了這個接口论熙「G啵可以通過readLock()獲取讀鎖,通過writeLock()獲取寫鎖脓诡。
表鎖无午、頁鎖、行鎖
在 Mysql 中祝谚,行級鎖并不是直接鎖記錄宪迟,而是鎖索引。索引分為主鍵索引和非主鍵索引兩種交惯,如果一條sql 語句操作了主鍵索引次泽,Mysql 就會鎖定這條主鍵索引;如果一條語句操作了非主鍵索引席爽,MySQL會先鎖定該非主鍵索引意荤,再鎖定相關(guān)的主鍵索引。
InnoDB 行鎖是通過給索引項(xiàng)加鎖實(shí)現(xiàn)的只锻,如果沒有索引玖像,InnoDB 會通過隱藏的聚簇索引來對記錄加鎖。也就是說:如果不通過索引條件檢索數(shù)據(jù)齐饮,那么InnoDB將對表中所有數(shù)據(jù)加鎖捐寥,實(shí)際效果跟表鎖一樣。因?yàn)闆]有了索引祖驱,找到某一條記錄就得掃描全表握恳,要掃描全表,就得鎖定表羹膳。
synchronized與lock的區(qū)別
public interface Lock {
void lock(); //用來獲取鎖睡互。如果鎖已被其他線程獲取,則進(jìn)行等待陵像。
void lockInterruptibly() throws InterruptedException;//當(dāng)通過這個方法去獲取鎖時(shí),如果線程正在等待獲取鎖寇壳,則這個線程能夠響應(yīng)中斷醒颖,即中斷線程的等待狀態(tài)。也就使說壳炎,當(dāng)兩個線程同時(shí)通過lock.lockInterruptibly()想獲取某個鎖時(shí)泞歉,假若此時(shí)線程A獲取到了鎖逼侦,而線程B只有在等待,那么對線程B調(diào)用threadB.interrupt()方法能夠中斷線程B的等待過程腰耙。
boolean tryLock();//方法是有返回值的榛丢,它表示用來嘗試獲取鎖,如果獲取成功挺庞,則返回true晰赞,如果獲取失敗(即鎖已被其他線程獲妊∏取)掖鱼,則返回false,也就說這個方法無論如何都會立即返回援制。在拿不到鎖時(shí)不會一直在那等待戏挡。
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;//和tryLock()方法是類似的,只不過區(qū)別在于這個方法在拿不到鎖時(shí)會等待一定的時(shí)間晨仑,在時(shí)間期限之內(nèi)如果還拿不到鎖褐墅,就返回false。如果如果一開始拿到鎖或者在等待期間內(nèi)拿到了鎖洪己,則返回true妥凳。
void unlock();//解鎖
Condition newCondition();
}
- Lock是一個接口,而synchronized是Java中的關(guān)鍵字码泛,synchronized是內(nèi)置的語言實(shí)現(xiàn)猾封;
- synchronized在發(fā)生異常時(shí),會自動釋放線程占有的鎖噪珊,因此不會導(dǎo)致死鎖現(xiàn)象發(fā)生晌缘;而Lock在發(fā)生異常時(shí),如果沒有主動通過unLock()去釋放鎖痢站,則很可能造成死鎖現(xiàn)象磷箕,因此使用Lock時(shí)需要在finally塊中釋放鎖;
- Lock可以讓等待鎖的線程響應(yīng)中斷阵难,而synchronized卻不行岳枷,使用synchronized時(shí),等待的線程會一直等待下去呜叫,不能夠響應(yīng)中斷空繁;
- 通過Lock可以知道有沒有成功獲取鎖,而synchronized卻無法辦到朱庆。
- Lock可以提高多個線程進(jìn)行讀操作的效率盛泡。
在靜態(tài)方法和非靜態(tài)方法上加 Synchronized的區(qū)別
- Synchronzied 修飾非靜態(tài)方法==》對象鎖。
- Synchronzied 修飾靜態(tài)方法==》其實(shí)是類鎖娱颊,因?yàn)槭庆o態(tài)方法傲诵,它把整個類鎖起來了凯砍;
jdk1.8新特性
- Lambda表達(dá)式
- 函數(shù)式接口
- 方法引用和構(gòu)造器調(diào)用
- Stream API
- 接口中的默認(rèn)方法和靜態(tài)方法
- 新時(shí)間日期API
常見算法
- 二分查找
public static int binSearch(int srcArray[], int key) {
int mid = srcArray.length / 2;
if (key == srcArray[mid]) {
return mid;
}
int start = 0;
int end = srcArray.length - 1;
while (start <= end) {
mid = (end - start) / 2 + start;
if (key < srcArray[mid]) {
end = mid - 1;
} else if (key > srcArray[mid]) {
start = mid + 1;
} else {
return mid;
}
}
return -1;
}
- 冒泡排序
public static void bubbleSort(int srcArray[]) {
for (int i = 0; i < srcArray.length - 1; i++) {//外層循環(huán)控制排序趟數(shù)
for (int j = 0; j < srcArray.length - 1 - i; j++) {//內(nèi)層循環(huán)控制每一趟排序多少次
if (srcArray[j] > srcArray[j + 1]) {
int temp = srcArray[j];
srcArray[j] = srcArray[j + 1];
srcArray[j + 1] = temp;
}
}
}
}
- 快速排序
public static void quickSort(int[] arr, int low, int high) {
int i, j, temp, t;
if (low > high) {
return;
}
i = low;
j = high;
//temp就是基準(zhǔn)位
temp = arr[low];
while (i < j) {
//先看右邊,依次往左遞減
while (temp <= arr[j] && i < j) {
j--;
}
//再看左邊拴竹,依次往右遞增
while (temp >= arr[i] && i < j) {
i++;
}
//如果滿足條件則交換
if (i < j) {
t = arr[j];
arr[j] = arr[i];
arr[i] = t;
}
}
//最后將基準(zhǔn)為與i和j相等位置的數(shù)字交換
arr[low] = arr[i];
arr[i] = temp;
//遞歸調(diào)用左半數(shù)組
quickSort(arr, low, j - 1);
//遞歸調(diào)用右半數(shù)組
quickSort(arr, j + 1, high);
}
常見數(shù)據(jù)結(jié)構(gòu)
數(shù)據(jù)結(jié)構(gòu)的物理存儲結(jié)構(gòu)只有兩種:順序存儲結(jié)構(gòu)和鏈?zhǔn)酱鎯Y(jié)構(gòu)(像棧悟衩,隊(duì)列,樹栓拜,圖等是從邏輯結(jié)構(gòu)去抽象的座泳,映射到內(nèi)存中,也這兩種物理組織形式)菱属。
- 線性表
- 數(shù)組
采用一段連續(xù)的存儲單元來存儲數(shù)據(jù)钳榨。對于指定下標(biāo)的查找,時(shí)間復(fù)雜度為O(1)纽门;通過給定值進(jìn)行查找薛耻,需要遍歷數(shù)組,逐一比對給定關(guān)鍵字和數(shù)組元素赏陵,時(shí)間復(fù)雜度為O(n)饼齿,當(dāng)然,對于有序數(shù)組蝙搔,則可采用二分查找缕溉,插值查找,斐波那契查找等方式吃型,可將查找復(fù)雜度提高為O(logn)证鸥;對于一般的插入刪除操作,涉及到數(shù)組元素的移動勤晚,其平均復(fù)雜度也為O(n)枉层。 - 鏈表
對于鏈表的新增,刪除等操作(在找到指定操作位置后)赐写,僅需處理結(jié)點(diǎn)間的引用即可鸟蜡,時(shí)間復(fù)雜度為O(1),而查找操作需要遍歷鏈表逐一進(jìn)行比對挺邀,復(fù)雜度為O(n)揉忘。
- 數(shù)組
- 棧與隊(duì)列
- 樹與二叉樹
- 樹
- 二叉樹基本概念
- 二叉查找樹
- 平衡二叉樹
- 紅黑樹
對一棵相對平衡的有序二叉樹,對其進(jìn)行插入端铛,查找泣矛,刪除等操作,平均復(fù)雜度均為O(logn)禾蚕。
- Hash表
在哈希表中進(jìn)行添加乳蓄,刪除,查找等操作夕膀,性能十分之高虚倒,不考慮哈希沖突的情況下,僅需一次定位即可完成产舞,時(shí)間復(fù)雜度為O(1)魂奥。
哈希沖突的解決方案有多種:開放定址法(發(fā)生沖突,繼續(xù)尋找下一塊未被占用的存儲地址)易猫,再散列函數(shù)法耻煤,鏈地址法。
常用設(shè)計(jì)模式
- 單例模式
單例設(shè)計(jì)模式簡單說就是無論程序如何運(yùn)行准颓,采用單例設(shè)計(jì)模式的類(Singleton類)永遠(yuǎn)只會有一個實(shí)例化對象產(chǎn)生哈蝇。
public class Singleton {
private Singleton() {
}
private static class SingletonHolder {
private final static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
- 工廠模式
程序在接口和子類之間加入了一個過渡端,通過此過渡端可以動態(tài)取得實(shí)現(xiàn)了共同接口的子類實(shí)例化對象攘已。 - 代理模式
指由一個代理主題來操作真實(shí)主題炮赦,真實(shí)主題執(zhí)行具體的業(yè)務(wù)操作,而代理主題負(fù)責(zé)其他相關(guān)業(yè)務(wù)的處理样勃。比如生活中的通過代理訪問網(wǎng)絡(luò)吠勘,客戶通過網(wǎng)絡(luò)代理連接網(wǎng)絡(luò)(具體業(yè)務(wù)),由代理服務(wù)器完成用戶權(quán)限和訪問限制等與上網(wǎng)相關(guān)的其他操作(相關(guān)業(yè)務(wù))峡眶。
對稱加密與非對稱加密
- 對稱加密:
對稱加密是最快速剧防、最簡單的一種加密方式,加密(encryption)與解密(decryption)用的是同樣的密鑰(secret key)辫樱。
常用對稱加密算法:AES峭拘、IDEA - 非對稱加密:
非對稱加密為數(shù)據(jù)的加密與解密提供了一個非常安全的方法,它使用了一對密鑰狮暑,公鑰(public key)和私鑰(private key)鸡挠。
常用非對稱加密算法:RSA、ElGamal
何謂RESTful心例?
RESTful(Representational State Transfer)架構(gòu)風(fēng)格宵凌,是一個Web自身的架構(gòu)風(fēng)格,底層主要基于HTTP協(xié)議(ps:提出者就是HTTP協(xié)議的作者)止后,是分布式應(yīng)用架構(gòu)的偉大實(shí)踐理論瞎惫。RESTful架構(gòu)是無狀態(tài)的,表現(xiàn)為請求-響應(yīng)的形式译株,有別于基于Bower的SessionId不同瓜喇。
何謂MVC?
- MVC是Model—View—Controler的簡稱歉糜,即模型—視圖—控制器乘寒。
- 模型:處理。
- 視圖:展示匪补。
- 控制器:接受伞辛。
- 流程:控制器接受用戶發(fā)來的請求烂翰,調(diào)用相應(yīng)模型處理邏輯,然后返回?cái)?shù)據(jù)給控制器蚤氏,控制器調(diào)用相應(yīng)視圖展示結(jié)果給用戶甘耿。
SpringMVC工作流程
- 客戶端請求提交到DispatcherServlet
- 由DispatcherServlet控制器查詢一個或多個HandlerMapping,找到處理請求的Controller
- DispatcherServlet將請求提交到Controller
- Controller調(diào)用業(yè)務(wù)邏輯處理后竿滨,返回ModelAndView
- DispatcherServlet查詢一個或多個ViewResoler視圖解析器佳恬,找到ModelAndView指定的視圖
- 視圖負(fù)責(zé)將結(jié)果顯示到客戶端
strus2與Spring MVC的區(qū)別
- Struts2是類級別上的攔截,一個類對應(yīng)一個request上下文于游,SpringMVC是方法級別的攔截毁葱,一個方法對應(yīng)一個request上下文。而且Struts過濾后是去Struts配置文件中找Action贰剥,而SpringMVC過濾后是去controller中找對應(yīng)于@RequestMapping注解的url綁定的方法倾剿。
- 因?yàn)閿r截器原因,導(dǎo)致Struts2的action比較亂鸠澈,因?yàn)樗x屬性來獲取請求中參數(shù)的數(shù)據(jù)柱告,而屬性在一個類的方法間是共享的(方法間不能獨(dú)享request、response數(shù)據(jù))笑陈,所以會有點(diǎn)亂际度。而SpringMVC中請求參數(shù)與controller中方法的形參自動配對(在名字相同,或請求參數(shù)與形參的屬性名相同涵妥,或通過@RequestParam注解指定條件下會自動將請求參數(shù)的值賦給形參)方法間可以獨(dú)享request乖菱、response數(shù)據(jù)。
- SpringMVC集成了Ajax蓬网,使用非常方便窒所,只需一個注解@ResponseBody就可以實(shí)現(xiàn),然后直接返回響應(yīng)文本即可帆锋,而Struts2攔截器集成了Ajax吵取,在Action中處理時(shí)一般必須安裝插件或者自己寫代碼集成進(jìn)去,使用起來也相對不方便锯厢。
SpringMVC常用參數(shù)綁定注解
- @RequestParam
- @RequestBody
- @RequestHeader
- @CookieValue
- @PathVariable
SpringMVC怎樣設(shè)定重定向和轉(zhuǎn)發(fā)的皮官?
- 在返回值前面加"forward:"就可以讓結(jié)果轉(zhuǎn)發(fā),譬如"forward:user.do?name=jianshu"
- 在返回值前面加"redirect:"就可以讓返回值重定向,譬如"redirect:http://www.baidu.com"
SpringIOC容器
Spring IOC負(fù)責(zé)創(chuàng)建對象、管理對象(通過依賴注入)实辑、整合對象捺氢、配置對象以及管理這些對象的生命周期,在Spring中BeanFactory是IOC容器的實(shí)際代表者剪撬。
BeanFactory 接口和 ApplicationContext 接口有什么區(qū)別 摄乒?
- ApplicationContext 接口繼承BeanFactory接口,Spring核心工廠是BeanFactory ,BeanFactory采取延遲加載,第一次getBean時(shí)才會初始化Bean, ApplicationContext是會在加載配置文件時(shí)初始化Bean馍佑。
- ApplicationContext是對BeanFactory擴(kuò)展斋否,它可以進(jìn)行國際化處理、事件傳遞和bean自動裝配以及各種不同應(yīng)用層的Context實(shí)現(xiàn)挤茄。
開發(fā)中基本都在使用ApplicationContext, web項(xiàng)目使用WebApplicationContext 如叼,很少用到BeanFactory。
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
IHelloService helloService = (IHelloService) beanFactory.getBean("helloService");
helloService.sayHello();
IOC穷劈、DI
- IOC(Inversion of Control):由IOC容器幫對象找相應(yīng)的依賴對象并注入,而不是由對象主動去找踊沸。
- DI(Dependency Injection):被注入對象依賴IOC容器配置依賴對象歇终。
依賴注入的幾種方式
- set注入
控制層代碼:
private OrderServiceImp orderService;
public void setOrderService(OrderServiceImp orderService) {
this.orderService = orderService;
}
Spring配置XML文件:其中配置聲明OrderAction類存在屬性orderService。程序運(yùn)行時(shí)候逼龟,會將已經(jīng)實(shí)例化的orderService對象調(diào)用setOrderService方式注入评凝。
<bean name="orderAction" class="com.pec.action.OrderAction">
<property name="orderService" ref="orderService"></property>
</bean>
<bean name="orderService" class="com.pec.service.imp.OrderServiceImp"></bean>
- 構(gòu)造器注入
控制層代碼:
private OrderServiceImp orderService;
public OrderAction(OrderServiceImp orderService) {
this.orderService = orderService;
}
Spring配置XML文件:
<bean name="orderAction" class="com.pec.action.OrderAction">
<constructor-arg ref="orderService"></constructor-arg>
</bean>
<bean name="orderService" class="com.pec.service.imp.OrderServiceImp"></bean>
- 注解注入
Spring中bean實(shí)例化有幾種方式?
- 使用類構(gòu)造器實(shí)例化(默認(rèn)無參數(shù))
<bean id="bean1" class="cn.jianshu.Bean1"></bean> - 靜態(tài)工廠
<bean id="bean2" class="cn.jianshu.Bean2Factory" factory-method="getBean2"></bean> - 實(shí)例工廠
<bean id="bean3Factory" class="cn.jianshu.Bean3Factory"></bean>
<bean id="bean3" factory-bean="bean3Factory" factory-method="getBean3"></bean>
簡單說下Bean的生命周期
- bean定義
- bean初始化
有兩種方式初始化:- 在配置文件中通過指定init-method屬性來完成
- 實(shí)現(xiàn)org.springframwork.beans.factory.InitializingBean接口
- bean調(diào)用
三種方式獲得bean實(shí)例(見上題) - bean銷毀
有兩種方式銷毀:- 使用配置文件指定的destroy-method屬性
- 實(shí)現(xiàn)org.springframwork.bean.factory.DisposeableBean接口
**注意:
在配置 <bean> 元素腺律,通過 init-method 指定Bean的初始化方法奕短,通過 destroy-method 指定Bean銷毀方法
<beanid="lifeCycleBean"class="cn.jianshu.LifeCycleBean"init-method="setup"destroy-method="teardown"></bean>
- destroy-method 只對 scope="singleton" 有效
- 銷毀方法,必須關(guān)閉ApplicationContext對象(手動調(diào)用)匀钧,才會被調(diào)用
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
applicationContext.close();**
Bean的作用域
- singleton
當(dāng)一個bean的作用域?yàn)閟ingleton, 那么Spring IoC容器中只會存在一個共享的bean實(shí)例翎碑,并且所有對bean的請求,只要id與該bean定義相匹配之斯,則只會返回bean的同一實(shí)例日杈。 - prototype
Prototype作用域的bean會導(dǎo)致在每次對該bean請求(將其注入到另一個bean中,或者以程序的方式調(diào)用容器的getBean() 方法)時(shí)都會創(chuàng)建一個新的bean實(shí)例佑刷。根據(jù)經(jīng)驗(yàn)莉擒,對所有有狀態(tài)的bean應(yīng)該使用prototype作用域,而對無狀態(tài)的bean則應(yīng)該使用 singleton作用域瘫絮。 - request
在一次HTTP請求中涨冀,一個bean定義對應(yīng)一個實(shí)例;即每次HTTP請求將會有各自的bean實(shí)例麦萤, 它們依據(jù)某個bean定義創(chuàng)建而成鹿鳖。該作用域僅在基于web的Spring ApplicationContext情形下有效。 - session
在一個HTTP Session中频鉴,一個bean定義對應(yīng)一個實(shí)例栓辜。該作用域僅在基于web的Spring ApplicationContext情形下有效。 - global session
在一個全局的HTTP Session中垛孔,一個bean定義對應(yīng)一個實(shí)例藕甩。典型情況下,僅在使用portlet context的時(shí)候有效。該作用域僅在基于web的Spring ApplicationContext情形下有效狭莱。
AOP的理解
- 面向切面編程(AOP)提供另外一種角度來思考程序結(jié)構(gòu)僵娃,通過這種方式彌補(bǔ)了面向?qū)ο缶幊蹋∣OP)的不足,除了類(classes)以外腋妙,AOP提供了切面默怨。切面對關(guān)注點(diǎn)進(jìn)行模塊化,例如橫切多個類型和對象的事務(wù)管理骤素。
-
Spring的一個關(guān)鍵的組件就是AOP框架匙睹,可以自由選擇是否使用AOP 提供聲明式企業(yè)服務(wù),特別是為了替代EJB聲明式服務(wù)济竹。最重要的服務(wù)是聲明性事務(wù)管理痕檬,這個服務(wù)建立在Spring的抽象事物管理之上。允許用戶實(shí)現(xiàn)自定義切面送浊,用AOP來完善OOP的使用,可以把Spring AOP看作是對Spring的一種增強(qiáng)梦谜。
AOP的理解圖.png
Spring里面的applicationContext.xml文件能不能改成其他名字?
ContextLoaderListener是一個ServletContextListener, 它在你的web應(yīng)用啟動的時(shí)候初始化袭景。缺省情況下唁桩, 它會在WEB-INF/applicationContext.xml文件找Spring的配置。 你可以通過定義一個<context-param>元素名字為”contextConfigLocation”來改變Spring配置文件的 位置耸棒。示例如下:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/jianshu.xml</param-value>
</context-param>
</listener-class>
</listener>
Spring如何處理線程并發(fā)問題荒澡?
Spring使用ThreadLocal解決線程安全問題
我們知道在一般情況下,只有無狀態(tài)的Bean才可以在多線程環(huán)境下共享榆纽,在Spring中仰猖,絕大部分Bean都可以聲明為singleton作用域。就是因?yàn)镾pring對一些Bean(如RequestContextHolder奈籽、TransactionSynchronizationManager饥侵、LocaleContextHolder等)中非線程安全狀態(tài)采用ThreadLocal進(jìn)行處理,讓它們也成為線程安全的狀態(tài)衣屏,因?yàn)橛袪顟B(tài)的Bean就可以在多線程中共享了躏升。
ThreadLocal和線程同步機(jī)制都是為了解決多線程中相同變量的訪問沖突問題。
在同步機(jī)制中狼忱,通過對象的鎖機(jī)制保證同一時(shí)間只有一個線程訪問變量膨疏。這時(shí)該變量是多個線程共享的,使用同步機(jī)制要求程序慎密地分析什么時(shí)候?qū)ψ兞窟M(jìn)行讀寫钻弄,什么時(shí)候需要鎖定某個對象佃却,什么時(shí)候釋放對象鎖等繁雜的問題,程序設(shè)計(jì)和編寫難度相對較大窘俺。
而ThreadLocal則從另一個角度來解決多線程的并發(fā)訪問饲帅。ThreadLocal會為每一個線程提供一個獨(dú)立的變量副本,從而隔離了多個線程對數(shù)據(jù)的訪問沖突。因?yàn)槊恳粋€線程都擁有自己的變量副本灶泵,從而也就沒有必要對該變量進(jìn)行同步了育八。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時(shí)赦邻,可以把不安全的變量封裝進(jìn)ThreadLocal髓棋。
由于ThreadLocal中可以持有任何類型的對象,低版本JDK所提供的get()返回的是Object對象惶洲,需要強(qiáng)制類型轉(zhuǎn)換按声。但JDK5.0通過泛型很好的解決了這個問題,在一定程度地簡化ThreadLocal的使用湃鹊。
概括起來說儒喊,對于多線程資源共享的問題,同步機(jī)制采用了“以時(shí)間換空間”的方式币呵,而ThreadLocal采用了“以空間換時(shí)間”的方式。前者僅提供一份變量侨颈,讓不同的線程排隊(duì)訪問余赢,而后者為每一個線程都提供了一份變量,因此可以同時(shí)訪問而互不影響哈垢。
如何解決GET妻柒、POST請求中文亂碼問題?
GET請求中文亂碼問題解決
- 重新編碼參數(shù)
String name= new String(request.getParamter("name").getBytes("ISO8859-1"),"utf-8")
- 修改tomcat中server.xml的配置
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" URIEncoding="utf-8"/>
POST請求中文亂碼問題解決
- web.xml中配置字符編碼過濾器
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
過濾器耘分、監(jiān)聽器举塔、攔截器
過濾器
所謂過濾器顧名思義是用來過濾的,Java的過濾器能夠?yàn)槲覀兲峁┫到y(tǒng)級別的過濾求泰,也就是說央渣,能過濾所有的web請求,這一點(diǎn)渴频,是攔截器無法做到的芽丹。在Java Web中,你傳入的request,response提前過濾掉一些信息卜朗,或者提前設(shè)置一些參數(shù)拔第,然后再傳入servlet或
者struts的action進(jìn)行業(yè)務(wù)邏輯,比如過濾掉非法url(不是login.do的地址請求场钉,如果用戶沒有登陸都過濾掉),或者在傳入servlet或者struts的action前統(tǒng)一設(shè)置字符集蚊俺,或者去除掉一些非法字符(聊天室經(jīng)常用到的,一些罵人的話)逛万。filter 流程是線性的泳猬,url傳來之后,檢查之后,可保持原來的流程繼續(xù)向下執(zhí)行暂殖,被下一個filter, servlet接收价匠。
監(jiān)聽器
Java的監(jiān)聽器,也是系統(tǒng)級別的監(jiān)聽呛每。監(jiān)聽器隨web應(yīng)用的啟動而啟動踩窖。Java的監(jiān)聽器在c/s模式里面經(jīng)常用到,它會對特定的事件產(chǎn)生產(chǎn)生一個處理晨横。監(jiān)聽在很多模式下用到洋腮,比如說觀察者模式,就是一個使用監(jiān)聽器來實(shí)現(xiàn)的手形,在比如統(tǒng)計(jì)網(wǎng)站的在線人數(shù)啥供。又比如struts2可以用監(jiān)聽來啟動。Servlet監(jiān)聽器用于監(jiān)聽一些重要事件的發(fā)生库糠,監(jiān)聽器對象可以在事情發(fā)生前伙狐、發(fā)生后可以做一些必要的處理。
攔截器
java里的攔截器提供的是非系統(tǒng)級別的攔截瞬欧,也就是說贷屎,就覆蓋面來說,攔截器不如過濾器強(qiáng)大艘虎,但是更有針對性唉侄。Java中的攔截器是基于Java反射機(jī)制實(shí)現(xiàn)的,更準(zhǔn)確的劃分野建,應(yīng)該是基于JDK實(shí)現(xiàn)的動態(tài)代理属划。它依賴于具體的接口,在運(yùn)行期間動態(tài)生成字節(jié)碼候生。攔截器是動態(tài)攔截Action調(diào)用的對象同眯,它提供了一種機(jī)制可以使開發(fā)者在一個Action執(zhí)行的前后執(zhí)行一段代碼,也可以在一個Action執(zhí)行前阻止其執(zhí)行陶舞,同時(shí)也提供了一種可以提取Action中可重用部分代碼的方式嗽测。在AOP中,攔截器用于在某個方法或者字段被訪問之前肿孵,進(jìn)行攔截然后再之前或者之后加入某些操作唠粥。java的攔截器主要是用在插件上骚揍,擴(kuò)展件上比如Hibernate Spring Struts2等含末,有點(diǎn)類似面向切片的技術(shù),在用之前先要在配置文件即xml勿侯,文件里聲明一段的那個東西蛉腌。
攔截器和過濾器的區(qū)別
- 攔截器是基于java的反射機(jī)制的官份,而過濾器是基于函數(shù)回調(diào)只厘。
- 攔截器不依賴與servlet容器,過濾器依賴與servlet容器舅巷。
- 攔截器只能對action請求起作用羔味,而過濾器則可以對幾乎所有的請求起作用。
- 攔截器可以訪問action上下文钠右、值棧里的對象赋元,而過濾器不能訪問。
- 在action的生命周期中飒房,攔截器可以多次被調(diào)用搁凸,而過濾器只能在容器初始化時(shí)被調(diào)用一次。
- 攔截器可以獲取IOC容器中的各個bean狠毯,而過濾器就不行护糖,這點(diǎn)很重要,在攔截器里注入一個service嚼松,可以調(diào)用業(yè)務(wù)邏輯嫡良。
- 攔截器需要在Spring配置文件中配置,過濾器只需要在web.xml中配置
為什么要有事務(wù)傳播行為献酗?
spring管理事務(wù)有幾種方式皆刺?
- 編程式事務(wù),在代碼中硬編碼凌摄。(不推薦使用)
- 聲明式事務(wù),在配置文件中配置(推薦使用)
聲明式事務(wù)又分為兩種:- 基于XML的聲明式事務(wù)
- 基于注解的聲明式事務(wù)
事務(wù)
'#{}'和'${}'的區(qū)別是什么漓帅?
'#{}'是預(yù)編譯處理锨亏,{}時(shí)捐迫,就是把${}替換成變量的值乾翔。
使用#{}可以有效的防止SQL注入,提高系統(tǒng)安全性施戴。
一對一反浓、一對多關(guān)聯(lián)查詢
<mapper namespace="com.jianshu.userMapper">
<!--association 一對一關(guān)聯(lián)查詢 -->
<select id="getClass" parameterType="int" resultMap="ClassesResultMap">
select * from class c,teacher t where c.teacher_id=t.t_id and c.c_id=#{id}
</select>
<resultMap type="com.jianshu.Classes" id="ClassesResultMap">
<!-- 實(shí)體類的字段名和數(shù)據(jù)表的字段名映射 -->
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" javaType="com.jianshu.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
</resultMap>
<!--collection 一對多關(guān)聯(lián)查詢 -->
<select id="getClass2" parameterType="int" resultMap="ClassesResultMap2">
select * from class c,teacher t,student s where c.teacher_id=t.t_id and c.c_id=s.class_id and c.c_id=#{id}
</select>
<resultMap type="com.jianshu.Classes" id="ClassesResultMap2">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" javaType="com.jianshu.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
<collection property="student" ofType="com.jianshu.Student">
<id property="id" column="s_id"/>
<result property="name" column="s_name"/>
</collection>
</resultMap>
</mapper>
MyBatis緩存
- MyBatis的緩存分為一級緩存和二級緩存。
- 一級緩存赞哗,SqlSession級別雷则,默認(rèn)開啟。
- 二級緩存肪笋,namespace級別月劈,需手動配置和開啟度迂。
- 總配置文件開啟二級緩存。
- 映射文件添加<cache>標(biāo)簽猜揪。
- 實(shí)體類實(shí)現(xiàn)序列化接口惭墓。
Spring Boot 的核心注解是哪個?它主要由哪幾個注解組成的而姐?
核心注解是啟動類上的@SpringBootApplication
它由以下四個注解組成:
- @SpringBootConfiguration:組合了 @Configuration 注解腊凶,實(shí)現(xiàn)配置文件的功能。
- @EnableAutoConfiguration:打開自動配置的功能毅人,也可以關(guān)閉某個自動配置的選項(xiàng)吭狡,如關(guān)閉數(shù)據(jù)源自動配置功能。
- @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })丈莺。
- @ComponentScan:Spring組件掃描划煮。
SpringCloud五大組件
- 服務(wù)發(fā)現(xiàn)
Netflix Eureka - 客戶端負(fù)載均衡
Netflix Ribbon - 斷路器
Netflix Hystri - 服務(wù)網(wǎng)關(guān)
Netflix Zuul - 分布式配置
Spring Cloud Config
dubbo支持的通信協(xié)議
- dubbo://
- rmi://
- hessian://
- http://
- webservice://
- thrift://
- memcached://
- redis://
底層采用socket進(jìn)行通信
CAP理論
任何一個分布式系統(tǒng)都無法同時(shí)滿足一致性(Consistency)、可用性(Availability)和分區(qū)容錯性(Partition tolerance)缔俄,最多只能同時(shí)滿足兩項(xiàng)弛秋。
分布式環(huán)境下的session處理策略
- 粘性session
upstream mycluster{
#這里添加的是上面啟動好的兩臺Tomcat服務(wù)器
ip_hash;#粘性Session
server 192.168.22.229:8080 weight=1;
server 192.168.22.230:8080 weight=1;
}
- 服務(wù)器session復(fù)制
- session共享機(jī)制
-
粘性session處理方式
-
非粘性session處理方式
-
- session持久化到數(shù)據(jù)庫
-
terracotta實(shí)現(xiàn)session復(fù)制
分布式事務(wù)
ByteTCC、LCN
阿里分布式事務(wù)框架GTS開源了一個免費(fèi)社區(qū)版Fescar
分布式鎖
基于數(shù)據(jù)庫做分布式鎖
- 基于表主鍵唯一做分布式鎖
- 基于表字段版本號做分布式鎖
- 基于數(shù)據(jù)庫排他鎖做分布式鎖
基于 Redis 做分布式鎖
public class RedisTool {
private static final String LOCK_SUCCESS = "OK";
private static final String SET_IF_NOT_EXIST = "NX";
private static final String SET_WITH_EXPIRE_TIME = "PX";
/**
* 嘗試獲取分布式鎖
* @param jedis Redis客戶端
* @param lockKey 鎖
* @param requestId 請求標(biāo)識
* @param expireTime 超期時(shí)間
* @return 是否獲取成功
*/
public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
if (LOCK_SUCCESS.equals(result)) {
return true;
}
return false;
}
}
public class RedisTool {
private static final Long RELEASE_SUCCESS = 1L;
/**
* 釋放分布式鎖
* @param jedis Redis客戶端
* @param lockKey 鎖
* @param requestId 請求標(biāo)識
* @return 是否釋放成功
*/
public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
if (RELEASE_SUCCESS.equals(result)) {
return true;
}
return false;
}
}
- 基于 REDIS 的 SETNX()俐载、EXPIRE() 方法做分布式鎖
- 基于 REDIS 的 SETNX()蟹略、GET()、GETSET()方法做分布式鎖
- 基于 REDLOCK 做分布式鎖
- 基于 REDISSON 做分布式鎖
基于 ZooKeeper 做分布式鎖
基于 Consul 做分布式鎖
RabbitMQ
MyISAM與InnoDB的區(qū)別
- 存儲結(jié)構(gòu)
- 存儲空間
- 可移值性遏佣、備份挖炬、恢復(fù)
- 事務(wù)支持
- AUTO_INCREMENT
- 表鎖差異
- 全文索引
- 表主鍵
- 表的具體行數(shù)
- CURD操作
- 外鍵
MySQL默認(rèn)采用的是MyISAM。
索引底層實(shí)現(xiàn)原理
-
索引的本質(zhì)
-
二叉樹
-
B樹
4.B+樹
-
帶有順序訪問指針的B+Tree
SQL優(yōu)化
避免全表掃描状婶,改為索引掃描意敛。
- 適當(dāng)?shù)乃饕?/li>
- 盡量不要有空判斷的語句,因?yàn)榭张袛鄬?dǎo)致全表掃描膛虫,而不是索引掃描草姻。盡量不要有空判斷的語句,因?yàn)榭张袛鄬?dǎo)致全表掃描稍刀,而不是索引掃描撩独。 對于空判斷這種情況,可以考慮對這個列創(chuàng)建數(shù)據(jù)庫默認(rèn)值账月。
- 盡量不要使用不等于條件综膀,因?yàn)椋@會導(dǎo)致全表掃描捶障,對于不等于這種情況僧须,考慮改為范圍查詢解決。
- 盡量不要使用or條件项炼,因?yàn)榈F剑@會導(dǎo)致全表掃描示绊,對于or這種情況,可以改為 分別查詢暂论,然后 union all面褐。
- 盡量不要使用左右模糊查詢,因?yàn)槿√ィ@會導(dǎo)致全表掃描展哭, 對于左右模糊查詢的情況,試著改為右側(cè)模糊查詢闻蛀,這樣是可以索引查找的匪傍。
- 盡量不要在執(zhí)行算數(shù)運(yùn)算后的比較,因?yàn)榫跬矗瘮?shù)役衡、算術(shù)運(yùn)算或其他表達(dá)式運(yùn)算通常將導(dǎo)致全表掃描,對于這種情況薪棒,可以考慮冗余部分?jǐn)?shù)據(jù)到表中手蝎。
- 盡量使用exists代替in。
- 盡量避免一次性返回大數(shù)據(jù)量俐芯,可以考慮分頁返回棵介。
union與union all
- union :得到兩個查詢結(jié)果的并集,并且自動去掉重復(fù)行吧史。不會排序邮辽。
- union all:得到兩個查詢結(jié)果的并集,不會去掉重復(fù)行贸营。也不會排序逆巍。
Oracle與MySQL分頁查詢的寫法
- Oracle
SELECT * FROM
(
SELECT A. *, ROWNUM RN
FROM(SELECT * FROM TABLE_NAME)A
WHERE ROWNUM <= 40
)
WHERE RN >=21
2.MySQL
SELECT * FROM TABLE LIMIT 5, 10;
SQL小貼士
- 執(zhí)行順序
from->where->group by->having->select->order by - HAVING 子句
在 SQL 中增加 HAVING 子句原因是,WHERE 關(guān)鍵字無法與合計(jì)函數(shù)一起使用莽使。 - union去重,union all 不去重笙僚。
- case when then else end
- 當(dāng)前時(shí)間
SELECT NOW(),CURDATE(),CURTIME() FROM DUAL
結(jié)果:
NOW() | CURDATE() | CURTIME() |
---|---|---|
2008-12-29 16:25:46 | 2008-12-29 | 16:25:46 |
- 時(shí)間間隔
mysql> SELECT DATEDIFF('2017-08-08','2017-08-17');
+-------------------------------------+
| DATEDIFF('2017-08-08','2017-08-17') |
+-------------------------------------+
| -9 |
+-------------------------------------+
1 row in set
查看數(shù)據(jù)庫引擎命令
show variables like '%storage_engine%';
Linux下查詢所有tomcat進(jìn)程命令
ps -ef|grep tomcat