1、Java基礎
1. String類爲何是final的。
最佳答案:主要是爲了「
效率」和「安全性」 的緣故。如String容許被繼承,因爲它的高度被實用性,可能會下降程序的性能,全部String被定義成final。
2. HashMap的源碼,實現原理,底層結構。
3. 說說你知道的幾個Java集合類:list、set、queue、map實現類咯。。。
Hashtable
是一個古老的Map實現類
2.1) Properties
Properties對象在處理屬性文件時特別方便(windows平臺上的.ini文件),Properties類能夠把Map對象和屬性文件關聯起來,從而能夠把Map對象中的key-value對寫入到屬性文
HashSet
HashSet是Set接口的典型實現,HashSet使用HASH算法來存儲集合中的元素,所以具備良好的存取和查找性能。當向HashSet集合中存入一個元素時,HashSet會調用該對象的 hashCode()方法來獲得該對象的hashCode值,而後根據該HashCode值決定該對象在HashSet中的存儲位置。
值得主要的是,HashSet集合判斷兩個元素相等的標準是兩個對象經過equals()方法比較相等,而且兩個對象的hashCode()方法的返回值相等
1.1.1) LinkedHashSet
LinkedHashSet集合也是根據元素的hashCode值來決定元素的存儲位置,但和HashSet不一樣的是,它同時使用鏈表維護元素的次序,這樣使得元素看起來是以插入的順序保存的。 當遍歷LinkedHashSet集合裏的元素時,LinkedHashSet將會按元素的添加順序來訪問集合裏的元素。
LinkedHashSet須要維護元素的插入順序,所以性能略低於HashSet的性能,但在迭代訪問Set裏的所有元素時(遍歷)將有很好的性能(鏈表很適合進行遍歷)
Deque
Deque接口表明一個"雙端隊列",雙端隊列能夠同時從兩端來添加、刪除元素,所以Deque的實現類既能夠當成隊列使用、也能夠當成棧使用
3.2.1) ArrayDeque
是一個基於數組的雙端隊列,和ArrayList相似,它們的底層都採用一個動態的、可重分配的Object[]數組來存儲集合元素,當集合元素超出該數組的容量時,系統會在底層重
PriorityQueue並非一個比較標準的隊列實現,PriorityQueue保存隊列元素的順序並非按照加入隊列的順序,而是按照隊列元素的大小進行從新排序 ,這點從它的類名也能夠
4. 描述一下ArrayList和LinkedList各自實現和區別
5. Java中的隊列都有哪些,有什麼區別。
種類:普通隊列、阻塞隊列、非阻塞隊列
區別:
(1)
阻塞隊列與普通隊列區別在於 ,當隊列是空時,從隊列中獲取元素的操做將被阻塞,或者當隊列滿時,往隊列裏添加元素的操做會被阻塞。試圖從空的阻塞隊列中獲取元素的線程將會被阻塞,直到其餘的線程往空的隊列插入新的元素。一樣,試圖往已滿的阻塞隊列中添加新的元素的線程一樣會被阻塞,知道其餘的線程使得隊列從新變的空閒起來,如從隊列中溢出一個或多個元素,或者徹底狀況隊列。
舉例說明:阻塞隊列(LinkedBlockingQueue)和非阻塞隊列(ConcurrentLinkedQueue)的區別
相同點:兩者都是線程安全的 。
不一樣點:
(1)阻塞隊列:按FIFO排序元素。隊列的頭部是在隊列中時間最長的元素。隊列的尾部是在隊列中最短的元素。新元素插入隊列的尾部,而且隊列檢索操做會得到位於隊列頭部的元素。連接隊列的吞吐量一般要高於基於數組的隊列,可是在大多數併發應用程序中,其可預知性能要低。
注意:A:必需要使用take()方法獲取的時候達成阻塞結果
B:使用poll()方法產生非阻塞效果
(2)非阻塞隊列:基於連接節點的、無界的、線程安全。按FIFO排序元素。隊列的頭部是在隊列中時間最長的元素。隊列的尾部是在隊列中最短的元素。新元素插入隊列的尾部,而且隊列檢索操做會得到位於隊列頭部的元素。
當許多線程共享訪問一個公共Collection時,ConcurrentLinkedQueue是一個恰當的選擇。 此隊列不容許爲null元素。
(3)在併發編程中,通常推薦使用
阻塞隊列 ,這樣實現能夠儘可能避免程序出現意外錯誤。阻塞隊列
使用最經典的場景就是socket客戶端數據的讀取和解析 ,讀取數據的線程不斷將數據放入隊列,而後解析線程不斷從隊列取數據解析 。只要符合生產者-消費者模型的均可以使用阻塞隊列 。
(4
)使用非阻塞隊列,雖然能即時返回結果(消費結果),可是必須自行編碼解決返回爲空的狀況(以及消費重試等問題) 。
6. 反射中,Class.forName和classloader的區別
均可以用來對類進行加載。Class.forName不但將類.c
lass文件加載到jvm中以外 ,還會對類進行解釋
執行類中的static塊 。而classloader只是將.class文件加載到jvm中,不會執行static中的內容,只有在newInstance時纔會去執行static塊。
對比二者具體的執行過程:
(1)LoadClass()方法加載類及其初始化過程:
類加載---》newInstance() (連接+初始化)
newInstance():
(開始鏈接)
靜態代碼塊-->普通變量分配準備(a=0;b=0;c=null)-->(開始初始化)普通變量賦值(a=1;b=2;c='haha')-->構造方法-->初始化成功
(2)Class.forName(String className)一個參數方法加載類及其初始化過程:
類加載--->靜態代碼塊-->newInstance() (連接+初始化)
newInstance():
(開始鏈接)普通變量分配準備(a=0;b=0;c=null)-->(開始初始化)普通變量賦值(a=1;b=2;c='haha')-->構造方法-->初始化成功
JVM加載類及其初始化過程 :
(1)類加載:Boostrap Loader(啓動類加載器)-->Extened Loader(擴展類加載器)-->System Loader(系統加載器)
(2)靜態代碼塊初始化
(3)連接:A:驗證:是否符合java規範 是否有正確的內部結構 及數據是否符合JVM規範 B:準備:靜態變量默認初始值 C:解析:符號引用轉爲直接引用,解析地址
(4)初始化:A:賦值,真正的初始化,用戶給變量賦予的值 B:構造方法
7. Java七、Java8的新特性(baidu問的,好BT)
Java7的新特性:
(1)語法上:
A:二進制變量的標示,支持將整數類型用二進制來標示,用0b開頭。
B:Switch語句支持String類型
C:Try-witch-resource語句
D:Catch多個異常(catch異常類型爲final)
E:數字類型的下劃線標示,更友好的表達式
F:
泛型實例的建立能夠經過類型推斷來簡化 能夠去掉後面
new
部分的泛型類型,只用<>就能夠了。
G:在可變參數方法中傳遞非具體化參數,改進編譯警告和錯誤
H:
信息更豐富的回溯追蹤 就是上面
try
中
try
語句和裏面的語句同時拋出異常時,異常棧的信息
Java8的新特性
(1)接口的默認方法:容許給接口添加一個非抽象的方法實現,只須要使用default關鍵字便可,這個特徵又叫擴展方法。
(2)Lambda表達式
(3)函數式接口:僅僅只包含一個抽象對象的接口,每個該類型的lambda表達式都會被匹配到這個抽象方法。只需給接口添加@FunctionalInterface註釋,編譯器若是發現你標註了這個註解的接口有多於一個抽象方法的時候會報錯的。
(4)方法與構造函數引用:容許你使用::關鍵字來傳遞方法或者構造函數引用,如下代碼展現瞭如何引用一個靜態方法。
構造函數引用:
(5)lambda做用域:
在lambda表達式中訪問外層做用域和老版本的匿名對象中的方式類似,你能夠直接訪問標記了final的外層局部變量,或者實例的字段以及靜態變量。
(6)訪問局部變量
(7)訪問對象字段與靜態變量
和本地變量不一樣的是,lambda內部對於實例的字段以及靜態變量是既可讀又可寫的。
(8)訪問接口的默認方法
(9)Date API
Clock時鐘:提供了訪問當前日期和時間方法。java.time.Clock
(10)Annotation註解:支持多種註解
8. Java數組和鏈表兩種結構的操做效率,在哪些狀況下(從開頭開始,從結尾開始,從中間開始),哪些操做(插入,查找,刪除)的效率高
9. Java內存泄露的問題調查定位:jmap,jstack的使用等等
下面就來認識一下MemoryAnalyzer.exe。java內存泄漏檢查工具利器。 php
首先咱們必須對jvm的堆內存進行dump,只有拿到這個文件咱們才能分析出jvm堆內存中到底存了些什麼內容,到底在作什麼?html
MemoryAnalyzer的用戶我在這裏就不一一說明了,個人博客裏也有說明,下面就展現我測試的成功圖:java
其中深藍色的部分就爲內存泄漏的部分,java的堆內存一共只有481.5M而內存泄漏的部分獨自佔有了336.2M因此本次的內存泄漏很明顯,那麼我就來看看那個方法致使的內存泄漏: mysql
從上圖咱們能夠發現紅線圈着的方法佔用了堆內存的67.75%,若是能把這個測試結果交給開發,開發是否是應該很好定位呢。因此做爲一名高級測試工程師,咱們須要學習的東西太多。linux
雖然不肯定必定是內存泄漏,可是能夠準確的告訴開發問題出現的緣由,有必定的說服力。nginx
本人剛剛完成了雲存儲架構師的培訓學習(包括了linux的內核瞭解、 shell的高級編程、linux安全的學習重點iptables和tcp/ip等各類協議的抓包分析、linux的集羣、性能調優等接下來還有dba的課程等待着我挑戰)。程序員
10. string、stringbuilder、stringbuffer區別
可變與不可變 web
String類中使用字符數組保存字符串,以下就是,由於有「final」修飾符,因此能夠知道string對象是不可變的。 面試
private final char value[]; redis
StringBuilder與StringBuffer都繼承自AbstractStringBuilder類 ,在AbstractStringBuilder中也是使用字符數組保存字符串 ,以下就是,可知這兩種對象都是可變的。
char[] value;
2.是否多線程安全
String中的對象是不可變的,也就能夠理解爲常量,顯然線程安全 。
AbstractStringBuilder是StringBuilder與StringBuffer的公共父類,定義了一些字符串的基本操做,如expandCapacity、append、insert、indexOf等公共方法。
StringBuffer對方法加了同步鎖或者對調用的方法加了同步鎖,因此是線程安全的。
.StringBuilder與StringBuffer共同點
StringBuilder與StringBuffer有公共父類AbstractStringBuilder(抽象類 )。
抽象類與接口的其中一個區別是:抽象類中能夠定義一些子類的公共方法,子類只須要增長新的功能,不須要重複寫已經存在的方法;而接口中只是對方法的申明和常量的定義。
StringBuilder、StringBuffer的方法都會調用AbstractStringBuilder中的公共方法,如super.append(...)。只是StringBuffer會在方法上加synchronized關鍵字,進行同步。
最後,若是程序不是多線程的,那麼使用StringBuilder效率高於StringBuffer。
11. hashtable和hashmap的區別
Hashtable 和 HashMap 的比較
Hashtable
HashMap
併發操做
使用同步機制 ,
實際應用程序中,僅僅是Hashtable自己的同步並不能保證程序在併發操做下的正確性,須要高層次的併發保護。
下面的代碼試圖在key所對應的value值等於x的狀況下修改value爲x+1
{
value = hashTable.get(key);
if(value.intValue()== x){
hashTable.put(key, new Integer(value.intValue()+1));
}
}
如2個線程同時執行以上代碼,可能放入不是x+1,而是x+2.
沒有同步機制 ,須要使用者本身進行併發訪問控制
數據遍歷的方式
Iterator 和 Enumeration
Iterator
是否包含Contains方法
包含
不包含 可是改爲containskey 和containsvalue
是否接受值爲null的Key 或Value?
不接受
接受
根據hash值計算數組下標的算法
當數組長度較小,而且Key的hash值低位數值分散不均勻時,不一樣的hash值計算獲得相同下標值的概率較高
hash = key.hashCode();
index=(hash&0x7FFFFFFF) % tab.length;
優於hashtable,經過對Key的hash作移位運算和位的與運算,使其能更普遍地分散到數組的不一樣位置
hash = hash (k);
index = indexFor(hash, table.length);
static int hash(Object x) {
int h = x.hashCode();
h += ~(h << 9);
h ^= (h >>> 14);
h += (h << 4);
h ^= (h >>> 10);
return h;
}
static int indexFor(int h, int length) {
return h & (length-1);
}
Entry數組的長度
Ø 缺省初始長度爲11 ,
Ø 初始化時能夠指定initial capacity
Ø 缺省初始長度爲16 ,
Ø 長度始終保持2的n次方
Ø 初始化時能夠指定initial capacity,若不是2的次方,HashMap將選取第一個大於initial capacity 的2n次方值做爲其初始長度
LoadFactor負荷因子
0.75
負荷超過(loadFactor * 數組長度)時,內部數據的調整方式
擴展數組:2*原數組長度+1
擴展數組: 原數組長度 * 2
二者都會從新根據Key的hash值計算其在數組中的新位置,從新放置。算法類似,時間、空間效率相同
13 .異常的結構,運行時異常和非運行時異常,各舉個例子
4.運行時異常和非運行時異常
(1)運行時異常都是RuntimeException類及其子類異常,如NullPointerException、IndexOutOfBoundsException等 ,這些異常是不檢查異常,程序中能夠選擇捕獲處理,也能夠不處理。這些異常通常是由程序邏輯錯誤引發的,程序應該從邏輯角度儘量避免這類異常的發生。
當出現RuntimeException的時候,咱們能夠不處理。當出現這樣的異常時,老是由虛擬機接管 。好比:咱們歷來沒有人去處理過NullPointerException異常,它就是運行時異常,而且這種異常仍是最多見的異常之一。
出現運行時異常後,系統會把異常一直往上層拋,一直遇處處理代碼。若是沒有處理塊,到最上層,若是是多線程就由Thread.run()拋出,若是是單線程就被main()拋出。拋出以後,若是是線程,這個線程也就退出了。若是是主程序拋出的異常,那麼這整個程序也就退出了。運行時異常是Exception的子類,也有通常異常的特色,是能夠被Catch塊處理的。只不過每每咱們不對他處理罷了。也就是說,你若是不對運行時異常進行處理,那麼出現運行時異常以後,要麼是線程停止,要麼是主程序終止。
若是不想終止,則必須撲捉全部的運行時異常,決不讓這個處理線程退出。隊列裏面出現異常數據了,正常的處理應該是把異常數據捨棄,而後記錄日誌。不該該因爲異常數據而影響下面對正常數據的處理。
(2)非運行時異常是RuntimeException之外的異常,類型上都屬於Exception類及其子類。如 IOException、SQLException 等以及用戶自定義的Exception異常 。對於這種異常,JAVA編譯器強制要求咱們必需對出現的這些異常進行catch並處理,不然程序就不能編譯經過。 因此,面對這種異常無論咱們是否願意,只能本身去寫一大堆catch塊去處理可能的異常。
14. String a= 「abc」 String b = "abc" String c = new String("abc") String d = "ab" + "c" .他們之間用 == 比較的結果
15. String 類的經常使用方法
、String類經常使用方法 一、求字符串長度public int length() //返回該字符串的長度
1 String str = new String("asdfzxc");
2 int strlength = str.length();//strlength = 7
二、求字符串某一位置字符public char charAt(int index) //返回字符串中指定位置的字符;注意字符串中第一個字符索引是0,最後一個是length()-1 。
1 String str = new String("asdfzxc");
2 char ch = str.charAt(4);//ch = z
三、提取子串 用String類的substring方法能夠提取字符串中的子串,該方法有兩種經常使用參數: 1)public String substring(int beginIndex) //該方法從beginIndex位置起 ,從當前字符串中取出剩餘的字符做爲一個新的字符串返回。 2)public String substring(int beginIndex, int endIndex) //該方法從beginIndex位置起,從當前字符串中取出到endIndex-1位置的字符做爲一個新的字符串返回。
1 String str1 = new String("asdfzxc");
2 String str2 = str1.substring(2);//str2 = "dfzxc"
3 String str3 = str1.substring(2,5);//str3 = "dfz"
四、字符串比較 1)public int compareTo(String anotherString) //該方法是對字符串內容按字典順序進行大小比較,經過返回的整數值指明當前字符串與參數字符串的大小關係。若當前對象比參數大則返回正整數,反之返回負整數,相等返回0。 2)public int compareToIgnore(String anotherString) //與compareTo方法類似,但忽略大小寫。 3)public boolean equals(Object anotherObject) //比較當前字符串和參數字符串,在兩個字符串相等的時候返回true,不然返回false 。 4)public boolean equalsIgnoreCase(String anotherString) //
字符串中字符的大小寫轉換 1)public String toLowerCase() //返回將當前字符串中全部字符轉換成小寫後的新串 2)public String toUpperCase() //返回將當前字符串中全部字符轉換成大寫後的新串
1 String str = new String("asDF");
2 String str1 = str.toLowerCase();//str1 = "asdf"
3 String str2 = str.toUpperCase();//str2 = "ASDF"
八、字符串中字符的替換 1)public String replace(char oldChar, char newChar) //用字符newChar替換當前字符串中全部的oldChar字符 ,並返回一個新的字符串。
九、其餘類方法 1)String trim() //截去字符串兩端的空格,但對於中間的空格不處理。
1 String str = " a sd ";
2 String str1 = str.trim();
3 int a = str.length();//a = 6
4 int b = str1.length();//b = 4
2)boolean statWith(String prefix) 或 boolean endWith( String suffix) //用來比較當前字符串的起始字符或子字符串prefix和終止字符或子字符串suffix是否和當前字符串相同,重載方法中同時還能夠指定比較的開始位置offset。
1 String str = "asdfgh";
2 boolean a = str.statWith("as");//a = true
3 boolean b = str.endWith("gh");//b = true
3)regionMatches(boolean b, int firstStart, String other, int otherStart, int length) //從當前字符串的firstStart位置開始比較,取長度爲length的一個子字符串,other字符串從otherStart位置開始,指定另一個長度爲length的字符串,兩字符串比較,當b爲true時字符串不區分大小寫。 4)contains(String str) //判斷參數s是否被包含在字符串中 ,並返回一個布爾類型的值。
1 String str = "student";
2 str.contains("stu");//true
3 str.contains("ok");//false
5)String[] split(String str) //將str做爲分隔符進行字符串分解,分解後的字字符串在字符串數組中返回 。
1 String str = "asd!qwe|zxc#";
2 String[] str1 = str.split("!|#");//str1[0] = "asd";str1[1] = "qwe";str1[2] = "zxc";
5、字符串與基本類型的轉換 一、字符串轉換爲基本類型 java.lang包中有Byte、Short、Integer、Float、Double類的調用方法: 1)public static byte parseByte(String s) 2)public static short parseShort(String s) 3)public static short parseInt(String s) 4)public static long parseLong(String s) 5)public static float parseFloat(String s) 6)public static double parseDouble(String s) 例如:
16. Java 的引用類型有哪幾種
強引用、軟引用、弱引用、虛引用
17. 抽象類和接口的區別
抽象類和接口的對比
參數
抽象類
接口
默認的方法實現
它能夠有默認的方法實現
接口徹底是抽象的。它根本不存在方法的實現
實現
子類使用extends 關鍵字來繼承抽象類。若是子類不是抽象類的話,它須要提供抽象類中全部聲明的方法的實現。
子類使用關鍵字implements 來實現接口。它須要提供接口中全部聲明的方法的實現
構造器
抽象類能夠有構造器
接口不能有構造器
與正常Java類的區別
除了你不能實例化抽象類以外,它和普通Java類沒有任何區別
接口是徹底不一樣的類型
訪問修飾符
抽象方法能夠有public、protected和default這些修飾符
接口方法默認修飾符是public。你不能夠使用其它修飾符。
main方法
抽象方法能夠有main方法而且咱們能夠運行它
接口沒有main方法,所以咱們不能運行它。
多繼承
抽象方法能夠繼承一個類和實現多個接口
接口只能夠繼承一個或多個其它接口
速度
它比接口速度要快
接口是稍微有點慢的,由於它須要時間去尋找在類中實現的方法。
添加新方法
若是你往抽象類中添加新的方法,你能夠給它提供默認的實現。所以你不須要改變你如今的代碼。
若是你往接口中添加方法,那麼你必須改變實現該接口的類。
何時使用抽象類和接口
若是你擁有一些方法而且想讓它們中的一些有默認實現,那麼使用抽象類吧。
若是你想實現多重繼承,那麼你必須使用接口 。因爲Java不支持多繼承 ,子類不可以繼承多個類,但能夠實現多個接口。所以你就能夠使用接口來解決它。
18. java的基礎類型和字節大小。
19. Hashtable,HashMap,ConcurrentHashMap 底層實現原理與線程安全問題(建議熟悉 jdk 源碼,才能從容應答)
20. 若是不讓你用Java Jdk提供的工具,你本身實現一個Map,你怎麼作。說了很久,說了HashMap源代碼,若是我作,就會借鑑HashMap的原理,說了一通HashMap實現
21. Hash衝突怎麼辦?哪些解決散列衝突的方法?
22. HashMap衝突很厲害,最差性能,你會怎麼解決?從O(n)提高到log(n)咯,用二叉排序樹的思路說了一通
理解了hashmap的實現,聰明的人確定已經知道怎麼更加高性能的使用hashmap。不過在此以前仍是先說明下初始容量和負載因子的含義。
Hashmap的設想是在O(1)的時間複雜度存取數據,根據咱們的分析,在最壞狀況下,時間複雜度極可能是o(n),但這確定極少出現。可是某個鏈表中存在多個元素仍是有至關大的可能的。當hashmap中的元素數量越接近數組長度,這個概率就越大。爲了保證hashmap的性能,咱們對元素數量/數組長度的值作了上限,此值就是負載因子。當比值大於負載因子時,就須要對內置數組進行擴容,從而提升讀寫性能。但這也正是問題的所在,對數組擴容,代價較大,時間複雜度時O(n)。
故咱們在hashmap須要存放的元素數量能夠預估的狀況下,預先設定一個初始容量,來避免自動擴容的操做來提升性能。
最直觀的判斷就是程序中採用了二分,且二分後只運算數據的一半。但若是兩部分都運算的話,時間複雜度 就是O(nlogn)了。其實不必定是二分,只不過二分比較經常使用罷了
23. rehash
再哈希就是擴容的過程
在擴容的過程當中須要進行ReHash操做,而這是很是耗時的,在實際中應該儘可能避免
24. hashCode() 與 equals() 生成算法、方法怎麼重寫
1. 講講IO裏面的常見類,字節流、字符流、接口、實現類、方法阻塞。
字節流與字符流的區別
字節流在操做的時候自己是不會用到緩衝區(內存)的,是與文件自己直接操做的,而字符流在操做的時候是使用到緩衝區的
字節流在操做文件時,即便不關閉資源(close方法),文件也能輸出,可是若是字符流不使用close方法的話,則不會輸出任何內容,說明字符流用的是緩衝區,而且可以使用flush方法強制進行刷新緩衝區,這時才能在不close的狀況下輸出內容
那開發中究竟用字節流好仍是用字符流好呢?
在全部的硬盤上保存文件或進行傳輸的時候都是以字節的方法進行的,包括圖片也是按字節完成,而字符是隻有在內存中才會造成的,因此使用字節的操做是最多的。
若是要java程序實現一個拷貝功能,應該選用字節流進行操做(可能拷貝的是圖片),而且採用邊讀邊寫的方式(節省內存)。
2. 講講NIO。
3. String 編碼UTF-8 和GBK的區別?
iso8859-1屬於
單字節編碼 ,最多能表示的
字符範圍是0-255 ,應用於英文系列很明顯,iso8859-1編碼表示的字符範圍很窄,
沒法表示中文字符
GB2312/GBK這就是
漢子的國標碼 ,專門用來表示漢字,是
雙字節編碼,而英文字母和iso8859-1一致
unicode 這是
最統一的編碼 ,能夠用來表示全部語言的字符,並且是
定長雙字節 (也有四字節的)編碼,包括英文字母在內。因此能夠說它是
不兼容iso8859-1編碼的,也不兼容任何編碼
UTF 考慮到unicode編碼不兼容iso8859-1編碼,並且容易佔用更多的空間:由於對於英文字母,unicode也須要兩個字節來表示。因此unicode不便於傳輸和存儲。所以而產生了utf編碼 ,而
漢字使用三個字節
4. 何時使用字節流、何時使用字符流?
字節流與字符流的區別
字節流和字符流使用是很是類似的,那麼除了操做代碼的不一樣以外,還有哪些不一樣呢?
字節流在操做的時候自己是不會用到緩衝區(內存)的,是與文件自己直接操做的,而字符流在操做的時候是使用到緩衝區的
字節流在操做文件時,即便不關閉資源(close方法),文件也能輸出,可是若是字符流不使用close方法的話,則不會輸出任何內容,說明字符流用的是緩衝區 ,而且能夠使用flush方法強制進行刷新緩衝區,這時才能在不close的狀況下輸出內容
那開發中究竟用字節流好仍是用字符流好呢?
在全部的硬盤上保存文件或進行傳輸的時候都是以字節的方法進行的,包括圖片也是按字節完成,而字符是隻有在內存中才會造成的,因此使用字節的操做是最多的。
5. 遞歸讀取文件夾下的文件,代碼怎麼實現
private List<String> ergodic(File file,List<String> resultFileName){
File[] files = file.listFiles();
if(files==null)return resultFileName;// 判斷目錄下是否是空的
for (File f : files) {
if(f.isDirectory()){// 判斷是否文件夾
resultFileName.add(f.getPath());
ergodic(f,resultFileName);// 調用自身,查找子目錄
}else
resultFileName.add(f.getPath());
}
return resultFileName;
}
調用時,使用:return ergodic(new File(forderPath), resultList); 返回結果就是目錄下包括子目錄下所有的文件路徑,包括子目錄的子目錄.....
1. session和cookie的區別和聯繫,session的生命週期,多個服務部署時session管理。
1. 因爲HTTP協議是無狀態的協議,因此服務端須要記錄用戶的狀態時,就須要用某種機制來識具體的用戶,這個機制就是Session.典型的場景好比購物車,
當你點擊下單按鈕時,因爲HTTP協議無狀態,因此並不知道是哪一個用戶操做的 ,因此服務端要爲特定的用戶建立了特定的Session,用用於標識這個用戶,而且跟蹤用戶,這樣才知道購物車裏面有幾本書。這個Session是保存在服務端的,有一個惟一標識JssessionId。在服務端保存Session的方法不少,內存、數據庫、文件都有。集羣的時候也要考慮Session的轉移,在大型的網站,通常會有專門的Session服務器集羣,用來保存用戶會話,這個時候 Session 信息都是放在內存的,使用一些緩存服務好比Memcached之類的來放 Session。
2. 思考一下服務端如何識別特定的客戶?這個時候Cookie就登場了。每次HTTP請求的時候,客戶端都會發送相應的Cookie信息到服務端。實際上大多數的應用都是用 Cookie 來實現Session跟蹤的,第一次建立Session的時候,服務端會在HTTP協議中告訴客戶端,須要在 Cookie 裏面記錄一個Session ID,之後每次請求把這個會話ID發送到服務器,我就知道你是誰了。有人問,
若是客戶端的瀏覽器禁用了 Cookie 怎麼辦?通常這種狀況下,會使用一種叫作URL重寫的技術來進行會話跟蹤,即每次HTTP交互,URL後面都會被附加上一個諸如 sid=xxxxx 這樣的參數,服務端據此來識別用戶。
3. Cookie其實還能夠用在一些方便用戶的場景下,設想你某次登錄過一個網站,下次登陸的時候不想再次輸入帳號了,怎麼辦?這個信息能夠寫到Cookie裏面,訪問網站的時候,網站頁面的腳本能夠讀取這個信息,就自動幫你把用戶名給填了,可以方便一下用戶。
這也是Cookie名稱的 由來,給用戶的一點甜頭。
因此,總結一下:
Session是在服務端保存的一個數據結構,用來跟蹤用戶的狀態,這個數據能夠保存在集羣、數據庫、文件中;
Cookie是客戶端保存用戶信息的一種機制,用來記錄用戶的一些信息,也是實現Session的一種方式。
2. servlet的一些相關問題
3. webservice相關問題
3.是多個跨語言跨平臺的應用間通訊整合的方案(實際)
webservice至關於什麼? http + xml + schema
**SOAP(Simple Object Access Protocal)簡單對象訪問協議 1.是一種簡單的,基於HTTP和XML的協議,用於在WEB交換結構化(XML)的數據 2.SOAP消息:請求消息和響應消息 3.HTTP+XML片段
**如何請求一個webservice
1.根據wsdl文檔生成客戶端代碼
2.根據生成的代碼調用webservice 找到wsdl文檔中service標籤的name屬性對應的類,找到這個port標籤的name屬性 調用這個方法
4. jdbc鏈接,forname方式的步驟,怎麼聲明使用一個事務。舉例並具體代碼
5. 無框架下配置web.xml的主要配置內容
6. jsp和servlet的區別
4、JVM
1. Java的內存模型以及GC算法
2. jvm性能調優都作了什麼
JVM性能調優有不少設置,這個參考JVM參數便可.
主要調優的目的:
控制GC的行爲 .GC是一個後臺處理,可是它也是會消耗系統性能的,所以常常會根據系統運行的程序的特性來更改GC行爲
控制JVM堆棧大小 .通常來講,JVM在內存分配上不須要你修改,(舉例)可是當你的程序新生代對象在某個時間段產生的比較多的時候,就須要控制新生代的堆大小.同時,還要須要控制總的JVM大小避免內存溢出
控制JVM線程的內存分配 .若是是多線程程序,產生線程和線程運行所消耗的內存也是能夠控制的,須要經過必定時間的觀測後,配置最優結果
3. 介紹JVM中7個區域,而後把每一個區域可能形成內存的溢出的狀況說明
JVM
一、內存模型以及分區,須要詳細到每一個區放什麼。
JVM 分爲堆區和棧區,還有方法區,初始化的對象放在堆裏面,引用放在棧裏面,class類信息常量池等放在方法區
二、堆裏面的分區:Eden,survival (from+ to),老年代,各自的特色。
堆裏面分爲新生代和老生代,新生代包含Eden+Survivor區,survivor區裏面分爲from和to區,內存回收時,用的是複製算法,從from複製到to,當通過一次或者屢次GC以後,存活下來的對象會被移動到老年區,當JVM內存不夠用的時候,會觸發Full GC,清理JVM老年區
當新生區滿了以後會觸發YGC,先把存活的對象放到其中一個Survice區,而後進行垃圾清理。由於若是僅僅清理須要刪除的對象,這樣會致使內存碎片,所以通常會把Eden 進行徹底的清理,而後整理內存。那麼下次GC 的時候,就會使用下一個Survive,這樣循環使用。若是有特別大的對象,新生代放不下,就會使用老年代的擔保,直接放到老年代裏面。由於JVM 認爲,通常大對象的存活時間通常比較久遠。
三、對象建立方法,對象的內存分配,對象的訪問定位。
new 一個對象
四、GC的兩種斷定方法:
引用計數法 :指的是若是某個地方引用了這個對象就+1,若是失效了就-1,當爲0就會回收可是JVM沒有用這種方式,由於沒法斷定相互循環引用(A引用B,B引用A)的狀況
引用鏈法 : 經過一種GC ROOT的對象(方法區中靜態變量引用的對象等)來判斷,若是有一條鏈可以到達GC ROOT就說明,不能到達GC ROOT就說明能夠回收
五、GC的三種收集方法:標記清除、標記整理、複製算法的原理與特色,分別用在什麼地方,若是讓你優化收集方法,有什麼思路?
先標記,標記完畢以後再清除,效率不高,會產生碎片
複製算法:分爲8:1的Eden區和survivor區,就是上面談到的YGC
標記整理:標記完畢以後,讓全部存活的對象向一端移動 清除邊緣之外的
六、GC收集器有哪些?CMS收集器與G1收集器的特色。
CMS收集器是基於「標記—清除」 算法實現的 ,它的運做過程相對於前面幾種收集器來講更復雜一些
G1從總體來看是基於「標記—整理 」 算法實現的收集器 ,從局部(兩個Region之間)上來看是基於「複製」算法實現的
GC收集器參見http://www.jianshu.com/p/50d5c88b272d
七、Minor GC與Full GC 分別在何時發生?
新生代內存不夠用 時候發生MGC也叫YGC,JVM內存不夠的時候發生FGC
八、幾種經常使用的內存調試工具:jmap、jstack、jconsole。
jstack能夠看當前棧的狀況,jmap查看內存
九、類加載的五個過程:
加載、驗證、準備、解析、初始化 。而後是使用和卸載了
經過全限定名來加載生成class對象,而後進行驗證這個class文件,包括元數據驗證,字節碼校驗等 。準備是對這個靜態變量對象分配內存並初始化 爲0。解析是將符號引用轉化爲直接引用(指針引用),初始化就是開始執行構造器的代碼
十、雙親委派模型:Bootstrap ClassLoader、Extension ClassLoader、ApplicationClassLoader。
Bootstrap ClassLoader:啓動類加載器,負責將$ Java_Home/lib下面的類庫加載到內存中(好比rt.jar
Extension ClassLoader:標準擴展(Extension)類加載器,它負責將$Java_Home /lib/ext或者由系統變量 java.ext.dir指定位置中的類庫加載到內存中。
ApplicationClassLoader:它負責將系統類路徑(CLASSPATH)中指定的類庫加載到內存中。開發者能夠直接使用系統類加載器
十一、雙親委派模型 是某個特定的類加載器在接到加載類的請求時,首先將加載任務委託給父類加載器,依次遞歸,若是父類加載器能夠完成類加載任務,就成功返回;只有父類加載器沒法完成此加載任務時,才本身去加載 。-----例如類java.lang.Object,它存在在rt.jar中,不管哪個類加載器要加載這個類,最終都是委派給處於模型最頂端的Bootstrap ClassLoader進行加載,所以Object類在程序的各類類加載器環境中都是同一個類。相反,若是沒有雙親委派模型而是由各個類加載器自行加載的話,若是用戶編寫了一個java.lang.Object的同名類並放在ClassPath中,那系統中將會出現多個不一樣的Object類,程序將混亂
十二、分派:靜態分派(重載)與動態分派(重寫)。
1三、你知道哪些JVM性能調優
設定堆內存大小-Xms
-Xmx:堆內存最大限制。
設定新生代大小。新生代不宜過小,不然會有大量對象涌入老年代
-XX:NewSize:新生代大小
-XX:NewRatio 新生代和老生代佔比
-XX:SurvivorRatio:伊甸園空間和倖存者空間的佔比
設定垃圾回收器
年輕代用 -XX:+UseParNewGC 年老代用-XX:+UseConcMarkSweepGC
做者:itar
連接:https://www.jianshu.com/p/763ade0c7267
來源:簡書
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
4. 介紹GC 和GC Root不正常引用。
5. 本身從classload 加載方式,加載機制說開去,從程序運行時數據區,講到內存分配,講到String常量池,講到JVM垃圾回收機制,算法,hotspot。反正就是各類擴展
6. jvm 如何分配直接內存, new 對象如何不分配在堆而是棧上,常量池解析
7. 數組多大放在 JVM 老年代(不僅是設置 PretenureSizeThreshold ,問一般多大,沒作過一問便知)
8. 老年代中數組的訪問方式
9. GC 算法,永久代對象如何 GC , GC 有環怎麼處理
針對HotSpot VM的實現,它裏面的GC其實準確分類只有兩大種:
Partial GC:並不收集整個GC堆的模式
Young GC:只收集young gen的GC
Old GC:只收集old gen的GC。只有CMS的concurrent collection是這個模式
Mixed GC:收集整個young gen以及部分old gen的GC。只有G1有這個模式
Full GC:收集整個堆,包括young gen、old gen、perm gen(若是存在的話)等全部部分的模式。
Major GC一般是跟full GC是等價的,收集整個GC堆。但由於HotSpot VM發展了這麼多年,外界對各類名詞的解讀已經徹底混亂了,當有人說「major GC」的時候必定要問清楚他想要指的是上面的full GC仍是old gen。
最簡單的分代式GC策略,按HotSpot VM的serial GC的實現來看,觸發條件是:
young GC:當young gen中的eden區分配滿的時候觸發。注意young GC中有部分存活對象會晉升到old gen,因此young GC後old gen的佔用量一般會有所升高。
full GC:當準備要觸發一次young GC時,若是發現統計數聽說以前young GC的平均晉升大小比目前old gen剩餘的空間大,則不會觸發young GC而是轉爲觸發full GC(由於HotSpot VM的GC裏,除了CMS的concurrent collection以外,其它能收集old gen的GC都會同時收集整個GC堆,包括young gen,因此不須要事先觸發一次單獨的young GC);或者,若是有perm gen的話,要在perm gen分配空間但已經沒有足夠空間時,也要觸發一次full GC;或者System.gc()、heap dump帶GC,默認也是觸發full GC。
HotSpot VM裏其它非併發GC的觸發條件複雜一些,不過大體的原理與上面說的其實同樣。 固然也總有例外。Parallel Scavenge(-XX:+UseParallelGC)框架下,默認是在要觸發full GC前先執行一次young GC,而且兩次GC之間能讓應用程序稍微運行一小下,以期下降full GC的暫停時間(由於young GC會盡可能清理了young gen的死對象,減小了full GC的工做量)。這是HotSpot VM裏的奇葩嗯。
併發GC的觸發條件就不太同樣。以CMS GC爲例,它主要是定時去檢查old gen的使用量,當使用量超過了觸發比例就會啓動一次CMS GC,對old gen作併發收集。(RednaxelaFX——知乎)
Java的GC原理不是引用計數,因此即便有環,只要他是從GC Root不可達的,一樣也會被收集。
10. 誰會被 GC ,何時 GC
程序認爲的死去的對象,也就是不可達對象會被GC。
11. 若是想不被 GC 怎麼辦
不被GC,建立對象的強引用 ,並一直不釋放
12. 若是想在 GC 中生存 1 次怎麼辦
生存一次,釋放掉對象的引用,可是在對象的finalize方法中從新創建引用,可是有一此方法只會被調用一次,因此能在GC中生存一次
13.如何在JVM虛擬機掛掉的時候,作一些操做,例如發郵件通知
能夠使用Runtime裏面的addShutdownHook(Thread hook)方法,把JVM掛掉的時候所須要啓動的線程註冊到runtime中,就能夠幫你完成這個動做
1. hibernate和ibatis的區別
hibernate 是當前最流行的o/r mapping框架,它出身於sf.net,如今已經成爲jboss的一部分了。
ibatis 是另一種優秀的o/r mapping框架,目前屬於apache的一個子項目了。
相對hibernate「o/r」而言,ibatis是一種「sql mapping」的orm實現。
hibernate對數據庫結構提供了較爲完整的封裝,hibernate的o/r mapping實現了pojo 和數據庫表之間的映射,以及sql 的自動生成和執行。程序員每每只需定義好了pojo 到數據庫表的映射關係,便可經過hibernate 提供的方法完成持久層操做。程序員甚至不須要對sql 的熟練掌握, hibernate/ojb 會根據制定的存儲邏輯,自動生成對應的sql 並調用jdbc 接口加以執行。
而ibatis 的着力點,則在於pojo 與sql之間的映射關係。也就是說,ibatis並不會爲程序員在運行期自動生成sql 執行。具體的sql 須要程序員編寫,而後經過映射配置文件,將sql所需的參數,以及返回的結果字段映射到指定pojo。
使用ibatis 提供的orm機制,對業務邏輯實現人員而言,面對的是純粹的java對象。
這一層與經過hibernate 實現orm 而言基本一致,而對於具體的數據操做,hibernate會自動生成sql 語句,而ibatis 則要求開發者編寫具體的sql 語句。相對hibernate而言,ibatis 以sql開發的工做量和數據庫移植性上的讓步,爲系統設計提供了更大的自由空間。
hibernate與ibatis的對比:
1.ibatis很是簡單易學,hibernate相對較複雜,門檻較高。
2.兩者都是比較優秀的開源產品
3.當系統屬於二次開發,沒法對數據庫結構作到控制和修改,那ibatis的靈活性將比hibernate更適合
4.系統數據處理量巨大,性能要求極爲苛刻,這每每意味着咱們必須經過通過高度優化的sql語句(或存儲過程)才能達到系統性能設計指標。在這種狀況下ibatis會有更好的可控性和表現。
5.ibatis須要手寫sql語句,也能夠生成一部分,hibernate則基本上能夠自動生成,偶爾會寫一些hql。一樣的需求,ibatis的工做量比hibernate要大不少。相似的,若是涉及到數據庫字段的修改,hibernate修改的地方不多,而ibatis要把那些sql mapping的地方一一修改。
6.以數據庫字段一一對應映射獲得的po和hibernte這種對象化映射獲得的po是大相徑庭的,本質區別在於這種po是扁平化的,不像hibernate映射的po是能夠表達立體的對象繼承,聚合等等關係的,這將會直接影響到你的整個軟件系統的設計思路。
7.hibernate如今已是主流o/r mapping框架,從文檔的豐富性,產品的完善性,版本的開發速度都要強於ibatis。
2. 講講mybatis的鏈接池。
3. spring框架中須要引用哪些jar包,以及這些jar包的用途
4. springMVC的原理
5. springMVC註解的意思
6. spring中beanFactory和ApplicationContext的聯繫和區別
做用:
1. BeanFactory負責讀取bean配置文檔,管理bean的加載,實例化,維護bean之間的依賴關係,負責bean的聲明週期 。
2. ApplicationContext除了提供上述BeanFactory所能提供的功能以外,還提供了更完整的框架功能 :
a. 國際化支持
b. 資源訪問:Resource rs = ctx. getResource(「classpath:config.properties」), 「file:c:/config.properties」
c. 事件傳遞:經過實現ApplicationContextAware接口
3. 經常使用的獲取ApplicationContext的方法:
FileSystemXmlApplicationContext:從文件系統或者url指定的xml配置文件建立,參數爲配置文件名或文件名數組
ClassPathXmlApplicationContext:從classpath的xml配置文件建立,能夠從jar包中讀取配置文件
WebApplicationContextUtils:從web應用的根目錄讀取配置文件,須要先在web.xml中配置,能夠配置監聽器或者servlet來實現
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
這兩種方式都默認配置文件爲web-inf/applicationContext.xml,也可以使用context-param指定配置文件
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/myApplicationContext.xml</param-value>
</context-param>
7. spring注入的幾種方式(循環注入)
8. spring如何實現事物管理的
9. springIOC
10. spring AOP的原理
11. hibernate中的1級和2級緩存的使用方式以及區別原理(Lazy-Load的理解)
12. Hibernate的原理體系架構,五大核心接口,Hibernate對象的三種狀態轉換,事務管理。
1. Java建立線程以後,直接調用start()方法和run()的區別
2. 經常使用的線程池模式以及不一樣線程池的使用場景
3. newFixedThreadPool此種線程池若是線程數達到最大值後會怎麼辦,底層原理。
4. 多線程之間通訊的同步問題,synchronized鎖的是對象,衍伸出和synchronized相關不少的具體問題,例如同一個類不一樣方法都有synchronized鎖,一個對象是否能夠同時訪問。或者一個類的static構造方法加上synchronized以後的鎖的影響。
5. 瞭解可重入鎖的含義,以及ReentrantLock 和synchronized的區別
6. 同步的數據結構,例如concurrentHashMap的源碼理解以及內部實現原理,爲何他是同步的且效率高
7. atomicinteger和volatile等線程安全操做的關鍵字的理解和使用
8. 線程間通訊,wait和notify
3. 爲何在執行wait, notify時,必須得到該對象的鎖?
這是由於,若是沒有鎖,wait和notify有可能會產生競態條件(Race Condition)。考慮如下生產者和消費者的情景:
1.1生產者檢查條件(如緩存滿了)-> 1.2生產者必須等待
2.1消費者消費了一個單位的緩存 -> 2.2從新設置了條件(如緩存沒滿) -> 2.3調用notifyAll()喚醒生產者
咱們但願的順序是: 1.1->1.2->2.1->2.2->2.3
但在多線程狀況下,順序有多是 1.1->2.1->2.2->2.3->1.2。也就是說,在生產者還沒wait以前,消費者就已經notifyAll了,這樣的話,生產者會一直等下去。
因此,要解決這個問題,必須在wait和notifyAll的時候,得到該對象的鎖,以保證同步
9. 定時線程的使用
10. 場景:在一個主線程中,要求有大量(不少不少)子線程執行完以後,主線程才執行完成。多種方式,考慮效率。
11. 進程和線程的區別
12. 什麼叫線程安全?舉例說明
線程安全:若是你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。若是每次運行結果和單線程運行的結果是同樣的 ,並且其餘的變量的值也和預期的是同樣的,就是線程安全的。或者說:一個類或者程序所提供的接口對於線程來講是原子操做或者多個線程之間的切換不會致使該接口的執行結果存在二義性,也就是說咱們不用考慮同步的問題
13. 線程的幾種狀態
14. 併發、同步的接口或方法
1:線程池
與每次須要時都建立線程相比,線程池能夠下降建立線程的開銷,這也是由於線程池在線程執行結束後進行的是回收操做,而不是真正的
銷燬線程。
2:ReentrantLock
ReentrantLock提供了tryLock方法,tryLock調用的時候,若是鎖被其餘線程持有,那麼tryLock會當即返回,返回結果爲false,若是鎖沒有被
其餘線程持有,那麼當前調用線程會持有鎖,而且tryLock返回的結果是true,
lock.lock();
try {
//do something
} finally {
lock.unlock();
}
3:volatile
保證了同一個變量在多線程中的可見性,不能夠被緩存,由於volatile保證了只有一份主存中的數據。
4:Atomics
public class Count {
private AtomicInteger counter = new AtomicInteger();
public int increase() {
return counter.incrementAndGet();
}
public int decrease() {
return counter.decrementAndGet();
}
}
AtomicInteger內部經過JNI的方式使用了硬件支持的CAS指令。
5:CountDownLatch
它是java.util.concurrent包中的一個類,它主要提供的機制是當多個(具體數量等於初始化CountDown時的count參數的值)線程都到達了預期狀態
或完成預期工做時觸發事件,其餘線程能夠等待這個事件來出發本身後續的工做,等待的線程能夠是多個,即CountDownLatch是能夠喚醒多個等待
的線程的,到達本身預期狀態的線程會調用CountDownLatch的countDown方法,而等待的線程會調用CountDownLatch的await方法
6:CyclicBarrier
循環屏障,CyclicBarrier能夠協同多個線程,讓多個線程在這個屏障前等待,直到全部線程都到達了這個屏障時,再一塊兒繼續執行後面的動做。
CyclicBarrier和CountDownLatch都是用於多個線程間的協調的,兩者的一個很大的差異是,CountDownLatch是在多個線程都進行了latch.countDown
後纔會觸發事件,喚醒await在latch上的線程,而執行countDown的線程,執行完countDown後,會繼續本身線程的工做;
CyclicBarrier是一個柵欄,用於同步全部調用await方法的線程,而且等全部線程都到了await方法,這些線程才一塊兒返回繼續各自的工做,由於使用CyclicBarrier的線程都會阻塞在await方法上,因此在線程池中使用CyclicBarrier時要特別當心,若是線程池的線程 數過少,那麼就會發生死鎖了,
CyclicBarrier能夠循環使用,CountDownLatch不能循環使用。
7:Semaphore
是用於管理信號量的,構造的時候傳入可供管理的信號量的數值,信號量對量管理的信號就像令牌,構造時傳入個數,總數就是控制併發的數量。
semaphore.acquire();
try {
//調用遠程通訊的方法
} finally () {
semahore.release();
}
8:Exchanger
Exchanger,從名字上講就是交換,它用於在兩個線程之間進行數據交換,線程會阻塞在Exchanger的exchange方法上,直到另外一個線程也到了
同一個Exchanger的exchange方法時,兩者進行交換,而後兩個線程會繼續執行自身相關的代碼。
9:Future和FutureTask
Future<HashMap> future = getDataFromRemote2();
//do something
HashMap data = (HashMap)future.get();
private Future<HashMap> getDateFromRemote2() {
return threadPool.submit(new Callable<HashMap>() {
public HashMap call() {
return getDataFromRemote();
}
});
}
思路:調用函數後立刻返回,而後繼續向下執行,急須要數據時再來用,或者說再來等待這個數據,具體實現方式有兩種,一個是用Future,另外一個使用回調。
15. HashMap 是否線程安全,爲什麼不安全。 ConcurrentHashMap,線程安全,爲什麼安全。底層實現是怎麼樣的。
16. J.U.C下的常見類的使用。 ThreadPool的深刻考察; BlockingQueue的使用。(take,poll的區別,put,offer的區別);原子類的實現。
17. 簡單介紹下多線程的狀況,從創建一個線程開始。而後怎麼控制同步過程,多線程經常使用的方法和結構
18. volatile的理解
19. 實現多線程有幾種方式,多線程同步怎麼作,說說幾個線程裏經常使用的方法
1. http是無狀態通訊,http的請求方式有哪些,能夠本身定義新的請求方式麼。
2. socket通訊,以及長鏈接,分包,鏈接異常斷開的處理。
3. socket通訊模型的使用,AIO和NIO。
4. socket框架netty的使用,以及NIO的實現原理,爲何是異步非阻塞。
5. 同步和異步,阻塞和非阻塞。
6. OSI七層模型,包括TCP,IP的一些基本知識
7. http中,get post的區別
8. 說說http,tcp,udp之間關係和區別。
一 .TCP/IP表明傳輸控制協議/網際協議,指的是一系列協組。
可分爲四個層次:數據鏈路層、網絡層、傳輸層和應用層。
在網絡層:有IP協議、ICMP協議、ARP協議、RARP協議和BOOTP協議。
在傳輸層:中有TCP協議與UDP協議。
在應用層:有FTP、HTTP、TELNET、SMTP、DNS等協議。
TCP和UDP使用IP協議從一個網絡傳送數據包到另外一個網絡。把IP想像成一種高速公路,它容許其它協議在上面行駛並找到到其它電腦的出口。TCP和UDP是高速公路上的「卡車」,它們攜帶的貨物就是像HTTP,文件傳輸協議FTP這樣的協議等。 TCP和UDP是FTP,HTTP和SMTP之類使用的傳輸層協議。雖然TCP和UDP都是用來傳輸其餘協議的,它們卻有一個顯著的不一樣:TCP提供有保證的數據傳輸,而UDP不提供。這意味着TCP有一個特殊的機制來確保數據安全的不出錯的從一個端點傳到另外一個端點,而UDP不提供任何這樣的保證。
二.HTTP自己就是一個協議,是從Web服務器傳輸超文本到本地瀏覽器的傳送協議。
HTTP(超文本傳輸協議)是利用TCP在兩臺電腦(一般是Web服務器和客戶端)之間傳輸信息的協議。客戶端使用Web瀏覽器發起HTTP請求給Web服務器,Web服務器發送被請求的信息給客戶端。
HTTP協議是創建在請求/響應模型上的。首先由客戶創建一條與服務器的TCP連接,併發送一個請求到服務器,請求中包含請求方法、URL、協議版本以及 相關的MIME樣式的消息。服務器響應一個狀態行,包含消息的協議版本、一個成功和失敗碼以及相關的MIME式樣的消息。
HTTP/1.0爲每一次HTTP的請求/響應創建一條新的TCP連接,所以一個包含HTML內容和圖片的頁面將須要創建屢次的短時間的TCP連接。一次TCP連接的創建 將須要3次握手。
另外,爲了得到適當的傳輸速度,則須要TCP花費額外的迴路連接時間(RTT)。每一次連接的創建須要這種常常性的開銷,而其並不帶有實際有用的數據 ,只是保證連接的可靠性,所以HTTP/1.1提出了可持續連接的實現方法。HTTP/1.1將只創建一次TCP的連接而重複地使用它傳輸一系列的請求/響應消息, 所以減小了連接創建的次數和常常性的連接開銷。
雖然HTTP自己是一個協議,但其最終仍是基於TCP的。
三.SOCKET:TCP/IP網絡的API。
Socket是應用層與TCP/IP協議族通訊的中間軟件抽象層 ,它是一組接口 。在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket接口後面,對用戶來講,一組簡單的接口就是所有,讓Socket去組織數據,以符合指定的協議。
Socket 接口是TCP/IP網絡的API,Socket接口定義了許多函數或例程,用以開發TCP/IP網絡上的應用程序。
這是爲了實現以上的通訊過程而創建成來的通訊管道,其真實的表明是客戶端和服務器端的一個通訊進程,雙方進程經過socket進行通訊,而通訊的規則 採用指定的協議。socket只是一種鏈接模式,不是協議,tcp,udp,簡單的說(雖然不許確)是兩個最基本的協議,不少其它協議都是基於這兩個協議如,http 就是基於tcp的,用socket能夠建立tcp鏈接,也能夠建立udp鏈接 ,這意味着,用socket能夠建立任何協議的鏈接,由於其它協議都是基於此的。
綜上所述:須要IP協議來鏈接網絡;TCP是一種容許咱們安全傳輸數據的機制,使用TCP協議來傳輸數據的HTTP是Web服務器和客戶端使用的特殊協議。HTTP基於TCP協議,可是卻能夠使用socket去創建一個TCP鏈接。
9. 說說瀏覽器訪問www.taobao.com,經歷了怎樣的過程。
假設你用一個全新的瀏覽器(第一次啓動的那種),訪問百度(http://www.baidu.com/ ),在你敲入網址並按下回車以後,將會發生如下神奇的事情:
瀏覽器先嚐試從Host文件中獲取http://www.baidu.com/ 對應的IP地址,若是能取到固然萬事大吉你們都能嗨,若是不能,就使用DNS協議來獲取IP咯。
在DNS協議中,PC會向你的本地DNS服務器求助(通常是路由器),但願從本地DNS服務器那裏獲得百度的IP,獲得就好,得不到還得向更高層次的DNS服務器求助,最終總能獲得百度的IP。
獲得百度的IP,下一步是使用TCP協議,創建TCP鏈接。
在TCP協議中,創建TCP須要與百度服務器握手三次,你先告訴服務器你要給服務器發東西(SYN),服務器應答你並告訴你它也要給你發東西(SYN、ACK),而後你應答服務器(ACK),總共來回了3次,稱爲3次握手。
不過,創建TCP鏈接有個前提(或者說給服務器發消息有個前提):你必須能成功地把消息發到服務器上。雖然已經知道IP,但並沒有啥用(好比說,你在廣東,你知道北京的地理座標經緯度就能到北京了?你得知道有哪些路通往北京吧你得準備盤纏吧你得花時間吧)。
爲了將消息從你的PC上傳到服務器上,須要用到IP協議、ARP協議和OSPF協議。
咱們都知道,你的PC和百度服務器之間通常會有許多路由器之類的東西,IP協議指定了出發地(你的PC)和目的地(服務器);你的數據會通過一個又一個路由器,OSPF決定了會通過那些路由器(用一種叫路由算法的玩意,找出最佳路徑);從一個路由器怎麼傳給下一個路由器?這是ARP協議的JOB,ARP負責求下一個節點的地址(咱們不止是要目的地,還要中間節點的地址)。
IP協議使用的是IP地址,整個發送過程當中只涉及出發地和目的地2個IP地址,而ARP協議使用的是MAC地址,整個發送過程當中涉及到每個節點的MAP地址
如今,咱們能和服務器通訊,還創建了TCP鏈接,下一步幹嗎,固然是用HTTP協議請求網頁內容咯。
你發個HTTP請求報文給服務器,若是服務器禁止你訪問它就給你回個"Forbidden",若是它暫時掛掉了就給你回個「內部服務錯誤」,若是它正常纔給你回個「OK「並將你要的數據傳給你;若是你還須要其它的東西再去跟它要(它通常還會給你的-_-)。
你收到了服務器的回覆,是一坨HTML形式的文本。瀏覽器必需要可以理解文本的內容,並快速地渲染到屏幕上(瀏覽器通常用有限自動機來理解文本內容,渲染的話就各看本事了,之因此微軟IE卡成狗而谷歌瀏覽器很6,就是它們的渲染速度不一樣...)
渲染出來後,你就看到百度的首頁了
10. HTTP協議、 HTTPS協議,SSL協議及完整交互過程;
5. HTTP與HTTPS的區別:
1) https協議須要申請證書。
2) http是超文本傳輸協議,
3) http端口80,;https端口443。
4) http鏈接簡單無狀態;https由SSL+HTTP協議構件的可進行加密傳輸、身份驗證的網絡協議。
11. tcp的擁塞,快回傳,ip的報文丟棄
擁塞避免
從慢啓動能夠看到,cwnd能夠很快的增加上來,從而最大程度的利用網絡帶寬資源,可是cwnd不能一直這樣無限增加下去,必定須要某個限制。TCP使用了一個叫慢啓動門限(ssthresh)的變量,當cwnd超過該值後,慢啓動過程結束,進入擁塞避免階段。對於大多數TCP實現來講,ssthresh的值是65536(一樣以字節計算)。擁塞避免的主要思想是加法增大,也就是cwnd的值再也不指數級往上升,開始加法增長。此時當窗口中全部的報文段都被確認時,cwnd的大小加1,cwnd的值就隨着RTT開始線性增長,這樣就能夠避免增加過快致使網絡擁塞,慢慢的增長調整到網絡的最佳值。
快速重傳
其實TCP還有一種狀況會進行重傳:那就是收到3個相同的ACK。TCP在收到亂序到達包時就會當即發送ACK,TCP利用3個相同的ACK來斷定數據包的丟失,此時進行快速重傳,快速重傳作的事情有: 1.把ssthresh設置爲cwnd的一半 2.把cwnd再設置爲ssthresh的值+3 3.從新進入擁塞避免階段
12. https處理的一個過程,對稱加密和非對稱加密
13. head各個特色和區別
參考:
8、數據庫MySql
1. MySql的存儲引擎的不一樣
2. 單個索引、聯合索引、主鍵索引
3. Mysql怎麼分表,以及分表後若是想按條件分頁查詢怎麼辦(若是不是按分表字段來查詢的話,幾乎效率低下,無解)
1)、作mysql集羣,例如:利用mysql cluster ,mysql proxy,mysql replication,drdb等等
優勢:擴展性好,沒有多個分表後的複雜操做(php代碼)
缺點:單個表的數據量仍是沒有變,一次操做所花的時間仍是那麼多,硬件開銷大。
2)、預先估計會出現大數據量而且訪問頻繁的表,將其分爲若干個表
優勢:避免一張表出現幾百萬條數據,縮短了一條sql的執行時間
缺點:當一種規則肯定時,打破這條規則會很麻煩,上面的例子中我用的hash算法是crc32,若是我如今不想用這個算法了,改用md5後,會使同一個用戶的消息被存儲到不一樣的表中,這樣數
據亂套了。擴展性不好。
3)、利用merge存儲引擎來實現分表
優勢:擴展性好,而且程序代碼改動的不是很大
缺點:這種方法的效果比第二種要差一點
4. 分表以後想讓一個id多個表是自增的,效率實現
5. MySql的主從實時備份同步的配置,以及原理(從庫讀主庫的binlog),讀寫分離
7. 索引的數據結構,B+樹
MySQL數據庫支持多種索引類型,如BTree索引,哈希索引,全文索引等等
MySQL就廣泛使用B+Tree實現其索引結構
8. 事務的四個特性,以及各自的特色(原子、隔離)等等,項目怎麼解決這些問題
9. 數據庫的鎖:行鎖,表鎖;樂觀鎖,悲觀鎖
mysql中有一種機制是表鎖定和行鎖定,爲何要出現這種機制,是爲了保證數據的完整性
舉個例子來講吧,若是有二個sql都要修改同一張表的同一條數據,這個時候怎麼辦呢,是否是二個sql均可以同時修改這條數據呢?
很顯然mysql對這種狀況的處理是,一種是表鎖定(myisam存儲引擎),一個是行鎖定(innodb存儲引擎)。
表鎖定表示大家都不能對這張表進行操做,必須等我對錶操做完才行。行鎖定同樣
10. 數據庫事務的幾種粒度;
數據庫級、表級、記錄級(行級)和屬性級(字段級)
11. 關係型和非關係型數據庫區別
nosql和關係型數據庫比較?
優勢:
1)成本:nosql數據庫簡單易部署,基本都是開源軟件,不須要像使用oracle那樣花費大量成本購買使用,相比關係型數據庫價格便宜。
2)查詢速度:nosql數據庫將數據存儲於緩存之中,關係型數據庫將數據存儲在硬盤中,天然查詢速度遠不及nosql數據庫。
3)存儲數據的格式:nosql的存儲格式是key,value形式、文檔形式、圖片形式等等,因此能夠存儲基礎類型以及對象或者是集合等各類格式,而數據庫則只支持基礎類型。
4)擴展性:關係型數據庫有相似join這樣的多表查詢機制的限制致使擴展很艱難。
缺點:
1)維護的工具和資料有限,由於nosql是屬於新的技術,不能和關係型數據庫10幾年的技術同日而語。
2)不提供對sql的支持,若是不支持sql這樣的工業標準,將產生必定用戶的學習和使用成本。
3)不提供關係型數據庫對事物的處理。
非關係型數據庫的優點:1. 性能NOSQL是基於鍵值對的,能夠想象成表中的主鍵和值的對應關係,並且不須要通過SQL層的解析,因此性能很是高。2. 可擴展性一樣也是由於基於鍵值對,數據之間沒有耦合性,因此很是容易水平擴展。
關係型數據庫的優點:1. 複雜查詢能夠用SQL語句方便的在一個表以及多個表之間作很是複雜的數據查詢。2. 事務支持使得對於安全性能很高的數據訪問要求得以實現。對於這兩類數據庫,對方的優點就是本身的弱勢,反之亦然。
12.數據庫的隔離級別:
髒讀: 髒讀就是指當一個事務正在訪問數據,而且對數據進行了修改,而這種修改尚未提交到數據庫中,這時,另一個事務也訪問這個數據,而後使用了這個數據。
不可重複讀:是指在一個事務內,屢次讀同一數據。在這個事務尚未結束時,另一個事務也訪問該同一數據。那麼,在第一個事務中的兩次讀數據之間,因爲第二個事務的修改,那麼第一
個事務兩次讀到的的數據多是不同的。這樣就發生了在一個事務內兩次讀到的數據是不同的,所以稱爲是不可重複讀。
幻讀:第一個事務對一個表中的數據進行了修改,這種修改涉及到表中的所有數據行。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入一行新數據。那麼,之後就會發生操做第
一個事務的用戶發現表中還有沒有修改的數據行,就好象發生了幻覺同樣。
未提交讀(Read Uncommitted):容許髒讀,也就是可能讀取到其餘會話中未提交事務修改的數據
提交讀(Read Committed):只能讀取到已經提交的數據。Oracle等多數數據庫默認都是該級別 (不重複讀)
可重複讀(Repeated Read):可重複讀。在同一個事務內的查詢都是事務開始時刻一致的,InnoDB默認級別。在SQL標準中,該隔離級別消除了不可重複讀,可是還存在幻象讀
串行讀(Serializable):徹底串行化的讀,每次讀都須要得到表級共享鎖,讀寫相互都會阻塞
1. 單例模式:飽漢、餓漢。以及餓漢中的延遲加載,雙重檢查
2. 工廠模式、裝飾者模式、觀察者模式。
3. 工廠方法模式的優勢(低耦合、高內聚,開放封閉原則)
1. 使用隨機算法產生一個數,要求把1-1000W之間這些數所有生成。(考察高效率,解決產生衝突的問題)
2. 兩個有序數組的合併排序
3. 一個數組的倒序
public class T {
public static void main(String[] args) {
char[] chars={'1','3','4','5','6'};
for(int i= 0 ; i < chars.length;i++){
char top =chars[0];//把數組的第一個提取出來,放進top
for(int j=1;j<chars.length-i;j++){
chars[j-1]= chars[j];//將組數除第一個以外的其他數 向左邊挪一位
}
chars[chars.length-i-1]=top;//將top 即原來數組的第一個數 賦予到數組的最後一位
}
System.out.println(chars);
4. 計算一個正整數的正平方根
5. 說白了就是常見的那些查找、排序算法以及各自的時間複雜度
6. 二叉樹的遍歷算法
7. DFS,BFS算法
9. 比較重要的數據結構,如鏈表,隊列,棧的基本理解及大體實現。
10. 排序算法與時空複雜度(快排爲何不穩定,爲何你的項目還在用)
11. 逆波蘭計算器
12. Hoffman 編碼
13. 查找樹與紅黑樹
1. 有個每秒鐘5k個請求,查詢手機號所屬地的筆試題(記得不完整,沒列出),如何設計算法?請求再多,好比5w,如何設計整個系統?
這不是算法的問題吧,是架構設計。
一、服務器直接用數據庫鏈接池從數據庫拿數據,數據加索引,這是最原始方式,看看這個的承載量
二、1方式達不到需求就用數據緩存,好比redis,先從緩存取,取不到再從數據庫取,取出來放入緩存,記得加個緩存時效,避免內存暴增。
三、利用集羣和負載均衡,結合緩存技術,別說5k,就算5w都行
2. 高併發狀況下,咱們系統是如何支撐大量的請求的
認清系統的高併發由3個層面致使:
1. 傳輸層
大量用戶對系統請求後,將會形成網絡帶寬和Web服務器的I/O瓶頸 。
2. 計算層
接收大量用戶請求進行計算 ,將會形成業務服務器 和業務支撐服務器的瓶頸 。
3. 存儲層
傳輸層和計算層將會產生大量的數據,數據量暴增 ,將會致使數據庫和儲存上的瓶頸 。
高併發的解決方法有兩種 ,一種是使用緩存、另外一種是使用生成靜態頁面;
1.用分佈式應用設計二、分佈式緩存數據庫 三、代碼優化 。
1.不要頻繁的new對象,對於在整個應用中只須要存在一個實例的類使用單例模式 .對於String的鏈接操做,使用StringBuffer或者
StringBuilder. 對於utility類型的類經過靜態方法來訪問。
2. 避免使用錯誤的方式,如Exception能夠控制方法推出,可是Exception要保留stacktrace消耗性能,除非必要不要使用 instanceof作條件判
斷,儘可能使用比的條件判斷方式.使用JAVA中效率高的類,好比ArrayList比Vector性能好。)
三、使用靜態頁面
補充:頁面靜態化
3. 集羣如何同步會話狀態
4. 負載均衡的原理
5 .若是有一個特別大的訪問量,到數據庫上,怎麼作優化(DB設計,DBIO,SQL優化,Java優化)
表的設計具體注意的問題:
一、數據行的長度不要超過8020字節,若是超過這個長度的話在物理頁中這條數據會佔用兩行從而形成存儲碎片,下降查詢效率。 二、可以用數字類型的字段儘可能選擇數字類型而不用字符串類型的 (電話號碼),這會下降查詢和鏈接的性能,並會增長存儲開銷。這是由於引擎在處理查詢和鏈接回逐個比較字符串中每個字符,而對於數字型而言只須要比較一次就夠了 。
三、對於不可變字符類型char和可變字符類型varchar 都是8000字節,char查詢快,可是耗存儲空間,varchar查詢相對慢一些可是節省存儲空間 。在設計字段的時候能夠靈活選擇,例如用戶名、密碼等長度變化不大的字段能夠選擇CHAR,對於評論等長度變化大的字段能夠選擇VARCHAR。
四、字段的長度在最大限度的知足可能的須要的前提下 ,應該儘量的設得短一些,這樣能夠提升查詢的效率,並且在創建索引的時候也能夠減小資源的消耗。
2、查詢的優化 保證在實現功能的基礎上,儘可能減小對數據庫的訪問次數;經過搜索參數,儘可能減小對錶的訪問行數,最小化結果集,從而減輕網絡負擔;可以分開的操做盡可能分開處理,提升每次的響應速度;在數據窗口使用SQL時,儘可能把使用的索引放在選擇的首列;算法的結構儘可能簡單;在查詢時,不要過多地使用通配符如SELECT * FROM T1語句,要用到幾列就選擇幾列如:SELECT COL1,COL2 FROM T1;在可能的狀況下儘可能限制儘可能結果集行數如:SELECT TOP 300 COL1,COL2,COL3 FROM T1,由於某些狀況下用戶是不須要那麼多的數據的。 在沒有建索引的狀況下,數據庫查找某一條數據,就必須進行全表掃描了,對全部數據進行一次遍歷,查找出符合條件的記錄。在數據量比較小的狀況下,也許看不出明顯的差異,可是當數據量大的狀況下,這種狀況就是極爲糟糕的了。SQL語句在SQL SERVER中是如何執行的,他們擔憂本身所寫的SQL語句會被SQL SERVER誤解。好比: select * from table1 where name='zhangsan' and tID > 10000 和執行: select * from table1 where tID > 10000 and name='zhangsan' 一些人不知道以上兩條語句的執行效率是否同樣,由於若是簡單的從語句前後上看,這兩個語句的確是不同,若是tID是一個聚合索引,那麼後一句僅僅從表的10000條之後的記錄中查找就好了;而前一句則要先從全表中查找看有幾個name='zhangsan'的,然後再根據限制條件條件tID>10000來提出查詢結果。 事實上,這樣的擔憂是沒必要要的。SQL SERVER中有一個「查詢分析優化器」,它能夠計算出where子句中的搜索條件並肯定哪一個索引能縮小表掃描的搜索空間,也就是說,它能實現自動優化。雖然查詢優化器能夠根據where子句自動的進行查詢優化,但有時查詢優化器就會不按照您的本意進行快速查詢。 在查詢分析階段,查詢優化器查看查詢的每一個階段並決定限制須要掃描的數據量是否有用。若是一個階段能夠被用做一個掃描參數(SARG),那麼就稱之爲可優化的,而且能夠利用索引快速得到所需數據。 SARG的定義:用於限制搜索的一個操做,由於它一般是指一個特定的匹配,一個值的範圍內的匹配或者兩個以上條件的AND鏈接。形式以下: 列名 操做符 <常數 或 變量> 或 <常數 或 變量> 操做符 列名 列名能夠出如今操做符的一邊,而常數或變量出如今操做符的另外一邊。如: Name=’張三’ 價格>5000 5000<價格 Name=’張三’ and 價格>5000 若是一個表達式不能知足SARG的形式,那它就沒法限制搜索的範圍了,也就是SQL SERVER必須對每一行都判斷它是否知足WHERE子句中的全部條件。因此一個索引對於不知足SARG形式的表達式來講是無用的。 因此,優化查詢最重要的就是,儘可能使語句符合查詢優化器的規則避免全表掃描而使用索引查詢。
具體要注意的:
1.應儘可能避免在 where 子句中對字段進行 null 值判斷,不然將致使引擎放棄使用索引而進行全表掃描 ,如: select id from t where num is null 能夠在num上設置默認值0,確保表中num列沒有null值,而後這樣查詢: select id from t where num=0
2.應儘可能避免在 where 子句中使用!=或<>操做符,不然將引擎放棄使用索引而進行全表掃描 。優化器將沒法經過索引來肯定將要命中的行數,所以須要搜索該表的全部行。
3.應儘可能避免在 where 子句中使用 or 來鏈接條件,不然將致使引擎放棄使用索引而進行全表掃描 ,如: select id from t where num=10 or num=20 能夠這樣查詢: select id from t where num=10 union all select id from t where num=20
4.in 和 not in 也要慎用,由於IN會使系統沒法使用索引,而只能直接搜索表中的數據 。如: select id from t where num in(1,2,3) 對於連續的數值,能用 between 就不要用 in 了: select id from t where num between 1 and 3
5.儘可能避免在索引過的字符數據中,使用非打頭字母搜索。這也使得引擎沒法利用索引。 見以下例子: SELECT * FROM T1 WHERE NAME LIKE ‘%L%’ SELECT * FROM T1 WHERE SUBSTING(NAME,2,1)=’L’ SELECT * FROM T1 WHERE NAME LIKE ‘L%’ 即便NAME字段建有索引,前兩個查詢依然沒法利用索引完成加快操做,引擎不得不對全表全部數據逐條操做來完成任務。而第三個查詢可以使用索引來加快操做。
6.必要時強制查詢優化器使用某個索引,如在 where 子句中使用參數,也會致使全表掃描。由於SQL只有在運行時纔會解析局部變量,但優化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然而,若是在編譯時創建訪問計劃,變量的值仍是未知的,於是沒法做爲索引選擇的輸入項。以下面語句將進行全表掃描: select id from t where num=@num 能夠改成強制查詢使用索引: select id from t with(index(索引名)) where num=@num
7.應儘可能避免在 where 子句中對字段進行表達式操做,這將致使引擎放棄使用索引而進行全表掃描。如: SELECT * FROM T1 WHERE F1/2=100 應改成: SELECT * FROM T1 WHERE F1=100*2
SELECT * FROM RECORD WHERE SUBSTRING(CARD_NO,1,4)=’5378’ 應改成: SELECT * FROM RECORD WHERE CARD_NO LIKE ‘5378%’
SELECT member_number, first_name, last_name FROM members WHERE DATEDIFF(yy,datofbirth,GETDATE()) > 21 應改成: SELECT member_number, first_name, last_name FROM members WHERE dateofbirth < DATEADD(yy,-21,GETDATE()) 即:任何對列的操做都將致使表掃描,它包括數據庫函數、計算表達式等等,查詢時要儘量將操做移至等號右邊。
8.應儘可能避免在where子句中對字段進行函數操做,這將致使引擎放棄使用索引而進行全表掃描。如: select id from t where substring(name,1,3)='abc'--name以abc開頭的id select id from t where datediff(day,createdate,'2005-11-30')=0--‘2005-11-30’生成的id 應改成: select id from t where name like 'abc%' select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'
9.不要在 where 子句中的「=」左邊進行函數、算術運算或其餘表達式運算,不然系統將可能沒法正確使用索引。
10.在使用索引字段做爲條件時,若是該索引是複合索引,那麼必須使用到該索引中的第一個字段做爲條件時才能保證系統使用該索引,不然該索引將不會被使用,而且應儘量的讓字段順序與索引順序相一致。
11.不少時候用 exists是一個好的選擇: elect num from a where num in(select num from b) 用下面的語句替換: select num from a where exists(select 1 from b where num=a.num)
SELECT SUM(T1.C1)FROM T1 WHERE( (SELECT COUNT(*)FROM T2 WHERE T2.C2=T1.C2>0) SELECT SUM(T1.C1) FROM T1WHERE EXISTS( SELECT * FROM T2 WHERE T2.C2=T1.C2) 二者產生相同的結果,可是後者的效率顯然要高於前者。由於後者不會產生大量鎖定的表掃描或是索引掃描。
若是你想校驗表裏是否存在某條紀錄,不要用count(*)那樣效率很低,並且浪費服務器資源。能夠用EXISTS代替 。如: IF (SELECT COUNT(*) FROM table_name WHERE column_name = 'xxx') 能夠寫成: IF EXISTS (SELECT * FROM table_name WHERE column_name = 'xxx')
常常須要寫一個T_SQL語句比較一個父結果集和子結果集,從而找到是否存在在父結果集中有而在子結果集中沒有的記錄,如: SELECT a.hdr_key FROM hdr_tbl a---- tbl a 表示tbl用別名a代替 WHERE NOT EXISTS (SELECT * FROM dtl_tbl b WHERE a.hdr_key = b.hdr_key) SELECT a.hdr_key FROM hdr_tbl a LEFT JOIN dtl_tbl b ON a.hdr_key = b.hdr_key WHERE b.hdr_key IS NULL SELECT hdr_key FROM hdr_tbl WHERE hdr_key NOT IN (SELECT hdr_key FROM dtl_tbl) 三種寫法均可以獲得一樣正確的結果,可是效率依次下降。
12.儘可能使用表變量來代替臨時表。若是表變量包含大量數據,請注意索引很是有限(只有主鍵索引)。
13.避免頻繁建立和刪除臨時表,以減小系統表資源的消耗。
14.臨時表並非不可以使用,適當地使用它們能夠使某些例程更有效,例如,當須要重複引用大型表或經常使用表中的某個數據集時。可是,對於一次性事件,最好使用導出表。
15.在新建臨時表時,若是一次性插入數據量很大,那麼能夠使用 select into 代替 create table,避免形成大量 log ,以提升速度;若是數據量不大,爲了緩和系統表的資源,應先create table,而後insert。
16.若是使用到了臨時表,在存儲過程的最後務必將全部的臨時表顯式刪除,先 truncate table ,而後 drop table ,這樣能夠避免系統表的較長時間鎖定。 17.在全部的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF 。無需在執行存儲過程和觸發器的每一個語句後向客戶端發送 DONE_IN_PROC 消息。
18.儘可能避免大事務操做,提升系統併發能力。
19.儘可能避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。 20. 避免使用不兼容的數據類型。例如float和int、char和varchar、binary和varbinary是不兼容的 。數據類型的不兼容可能使優化器沒法執行一些原本能夠進行的優化操做。例如: SELECT name FROM employee WHERE salary > 60000 在這條語句中,如salary字段是money型的,則優化器很難對其進行優化,由於60000是個整型數。咱們應當在編程時將整型轉化成爲錢幣型,而不要等到運行時轉化。
21.充分利用鏈接條件,在某種狀況下,兩個表之間可能不僅一個的鏈接條件,這時在 WHERE 子句中將鏈接條件完整的寫上,有可能大大提升查詢速度。 例: SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO AND A.ACCOUNT_NO=B.ACCOUNT_NO 第二句將比第一句執行快得多。
2二、使用視圖加速查詢 把表的一個子集進行排序並建立視圖,有時能加速查詢。它有助於避免多重排序 操做,並且在其餘方面還能簡化優化器的工做。例如: SELECT cust.name,rcvbles.balance,……other columns FROM cust,rcvbles WHERE cust.customer_id = rcvlbes.customer_id AND rcvblls.balance>0 AND cust.postcode>「98000」 ORDER BY cust.name
若是這個查詢要被執行屢次而不止一次,能夠把全部未付款的客戶找出來放在一個視圖中,並按客戶的名字進行排序: CREATE VIEW DBO.V_CUST_RCVLBES AS SELECT cust.name,rcvbles.balance,……other columns FROM cust,rcvbles WHERE cust.customer_id = rcvlbes.customer_id AND rcvblls.balance>0 ORDER BY cust.name 而後如下面的方式在視圖中查詢: SELECT * FROM V_CUST_RCVLBES WHERE postcode>「98000」 視圖中的行要比主表中的行少,並且物理順序就是所要求的順序,減小了磁盤I/O,因此查詢工做量能夠獲得大幅減小。
2三、能用DISTINCT的就不用GROUP BY SELECT OrderID FROM Details WHERE UnitPrice > 10 GROUP BY OrderID 可改成: SELECT DISTINCT OrderID FROM Details WHERE UnitPrice > 10
24.能用UNION ALL就不要用UNION UNION ALL不執行SELECT DISTINCT函數,這樣就會減小不少沒必要要的資源 35.儘可能不要用SELECT INTO語句。 SELECT INOT 語句會致使表鎖定,阻止其餘用戶訪問該表。
上面咱們提到的是一些基本的提升查詢速度的注意事項,可是在更多的狀況下,每每須要反覆試驗比較不一樣的語句以獲得最佳方案。最好的方法固然是測試,看實現相同功能的SQL語句哪一個執行時間最少,可是數據庫中若是數據量不多,是比較不出來的,這時能夠用查看執行計劃,即:把實現相同功能的多條SQL語句考到查詢分析器,按CTRL+L看查所利用的索引,表掃描次數(這兩個對性能影響最大),整體上看詢成本百分比便可。 3、算法的優化
儘可能避免使用遊標,由於遊標的效率較差 ,若是遊標操做的數據超過1萬行,那麼就應該考慮改寫。.使用基於遊標的方法或臨時表方法以前,應先尋找基於集的解決方案來解決問題,基於集的方法一般更有效。與臨時表同樣,遊標並非不可以使用。對小型數據集使用 FAST_FORWARD 遊標一般要優於其餘逐行處理方法,尤爲是在必須引用幾個表才能得到所需的數據時。在結果集中包括「合計」的例程一般要比使用遊標執行的速度快。若是開發時間容許,基於遊標的方法和基於集的方法均可以嘗試一下,看哪種方法的效果更好。 遊標提供了對特定集合中逐行掃描的手段,通常使用遊標逐行遍歷數據,根據取出的數據不一樣條件進行不一樣的操做。尤爲對多表和大表定義的遊標(大的數據集合)循環很容易使程序進入一個漫長的等特甚至死機。 在有些場合,有時也非得使用遊標,此時也可考慮將符合條件的數據行轉入臨時表中,再對臨時表定義遊標進行操做,可時性能獲得明顯提升。 (例如:對內統計初版) 封裝存儲過程
4、創建高效的索引
建立索引通常有如下兩個目的:維護被索引列的惟一性和提供快速訪問表中數據的策略。大型數據庫有兩種索引即簇索引和非簇索引,一個沒有簇索引的表是按堆結構存儲數據,全部的數據均添加在表的尾部,而創建了簇索引的表,其數據在物理上會按照簇索引鍵的順序存儲,一個表只容許有一個簇索引,所以,根據B樹結構,能夠理解添加任何一種索引均能提升按索引列查詢的速度,但會下降插入、更新、刪除操做的性能,尤爲是當填充因子(Fill Factor)較大時。因此對索引較多的表進行頻繁的插入、更新、刪除操做,建表和索引時因設置較小的填充因子,以便在各數據頁中留下較多的自由空間,減小頁分割及從新組織的工做。
6. 若是出現大面積併發,在不增長服務器的基礎上,如何解決服務器響應不及時問題「 。
1. 提升CPU併發計算能力
多進程 & 多線程
減小進程切換
最簡單的作法就是減小進程數,儘可能使用線程並配合其它I/O模型來設計併發策略 。
減小使用沒必要要的鎖
服務器處理大量併發請求時,多個請求處理任務時存在一些資源搶佔競爭,這時通常採用「鎖」機制來控制資源的佔用,當一個任務佔用資源時,咱們鎖住資源,這時其它任務都在等待鎖的釋放 ,這個現象稱爲鎖競爭。
進程調度器會動態調整運行隊列中進程的優先級,經過top觀察進程的PR值
2. 考慮減小內存分配和釋放
例如Apache,在運行開始時一次申請大片的內存做爲內存池, 若隨後須要時就在內存池中直接獲取 ,不須要再次分配 ,避免了頻繁的內存分配和釋放引發的內存整理時間
3. 考慮使用持久鏈接
持久鏈接也爲長鏈接,它自己是TCP通訊的一種普通方式,即在一次TCP鏈接中持續發送多分數據而不斷開鏈接
4. 改進I/O 模型
2. 異步I/O
異步I/O指主動請求數據後即可以繼續處理其它任務,隨後等待I/O操做的通知,這樣進程在數據讀寫時不發生阻塞。
異步I/O是非阻塞的,當函數返回時,真正的I/O傳輸已經完成,這讓CPU處理和I/O操做達到很好的重疊。
6. 改進硬件環境
7. 假如你的項目出現性能瓶頸了,你以爲可能會是哪些方面,怎麼解決問題。
8. 如何查找 形成 性能瓶頸出現的位置,是哪一個位置照成性能瓶頸。
9. 你的項目中使用過緩存機制嗎?有沒用用戶非本地緩存
redis 緩存 hibernate 的session一級緩存
- 導航條 - 首頁 全部文章 資訊 Web 架構 基礎技術 書籍 教程 Java小組 工具資源
不少常見的面試題都會出諸如抽象類和接口有什麼區別,什麼狀況下會使用抽象類和什麼狀況你會使用接口 這樣的問題。本文咱們將仔細討論這些話題。
在討論它們之間的不一樣點以前,咱們先看看抽象類、接口各自的特性。
抽象類
抽象類是用來捕捉子類的通用特性的 。它不能被實例化,只能被用做子類的超類。抽象類是被用來建立繼承層級裏子類的模板。以JDK中的GenericServlet爲例:
1
2
3
4
5
6
7
8
9
public
abstract
class
GenericServlet
implements
Servlet, ServletConfig, Serializable {
abstract
void
service(ServletRequest req, ServletResponse res);
void
init() {
}
}
當HttpServlet 類繼承 GenericServlet 時,它提供了 service方法 的實現:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public
class
HttpServlet
extends
GenericServlet {
void
service(ServletRequest req, ServletResponse res) {
}
protected
void
doGet(HttpServletRequest req, HttpServletResponse resp) {
}
protected
void
doPost(HttpServletRequest req, HttpServletResponse resp) {
}
}
接口
接口是抽象方法的集合。若是一個類實現了某個接口,那麼它就繼承了這個接口的抽象方法。這就像契約模式,若是實現了這個接口,那麼就必須確保使用這些方法。接口只是一種形式,接口自身不能作任何事情。以Externalizable 接口爲例 :
1
2
3
4
5
6
public
interface
Externalizable
extends
Serializable {
void
writeExternal(ObjectOutput out)
throws
IOException;
void
readExternal(ObjectInput in)
throws
IOException, ClassNotFoundException;
}
當你實現這個接口時,你就須要實現上面的兩個方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public
class
Employee
implements
Externalizable {
int
employeeId;
String employeeName;
@Override
public
void
readExternal(ObjectInput in)
throws
IOException, ClassNotFoundException {
employeeId = in.readInt();
employeeName = (String) in.readObject();
}
@Override
public
void
writeExternal(ObjectOutput out)
throws
IOException {
out.writeInt(employeeId);
out.writeObject(employeeName);
}
}
抽象類和接口的對比
參數
抽象類
接口
默認的方法實現
它能夠有默認的方法實現
接口徹底是抽象的。它根本不存在方法的實現
實現
子類使用extends關鍵字來繼承抽象類。若是子類不是抽象類的話,它須要提供抽象類中全部聲明的方法的實現。
子類使用關鍵字implements來實現接口。它須要提供接口中全部聲明的方法的實現
構造器
抽象類能夠有構造器
接口不能有構造器
與正常Java類的區別
除了你不能實例化抽象類以外,它和普通Java類沒有任何區別
接口是徹底不一樣的類型
訪問修飾符
抽象方法能夠有public、protected和default這些修飾符
接口方法默認修飾符是public。你不能夠使用其它修飾符。
main方法
抽象方法能夠有main方法而且咱們能夠運行它
接口沒有main方法,所以咱們不能運行它。
多繼承
抽象方法能夠繼承一個類和實現多個接口
接口只能夠繼承一個或多個其它接口
速度
它比接口速度要快
接口是稍微有點慢的,由於它須要時間去尋找在類中實現的方法。
添加新方法
若是你往抽象類中添加新的方法,你能夠給它提供默認的實現。所以你不須要改變你如今的代碼。
若是你往接口中添加方法,那麼你必須改變實現該接口的類。
何時使用抽象類和接口
若是你擁有一些方法而且想讓它們中的一些有默認實現,那麼使用抽象類吧。
若是你想實現多重繼承,那麼你必須使用接口。因爲Java不支持多繼承 ,子類不可以繼承多個類,但能夠實現多個接口。所以你就能夠使用接口來解決它。