題目整理
Java基礎進階階段
基礎概念類
1.JDK1.8新特性?
2.面向物件和面向程序的區別?
3.什么是值傳遞和參考傳遞?
4.什么是不可變物件?
5.講講類的實體化順序?
6.java 創建物件的幾種方式
7.Java訪問修飾符的作用域
8.switch中能否使用string作為引數?
9.switch中能否作用在byte,long上?
10.什么是自動拆裝箱?
11.如何正確的退出多層嵌套回圈?
繼承
1.Java支持多繼承么?
2.父類的靜態方法能否被子類重寫?
3.繼承的好處和壞處?
介面抽象類
1.介面的意義?
2.抽象類的意義?
3.抽 象 的 (abstract) 方 法 是 否 可 同 時 是 靜 態 的 (static), 是 否 可 同 時 是 本 地 方 法(native)?
4.抽象類和介面區別?
5.Java中介面可不可以繼承一般類,為什么?
6.多載與重寫區別?
7.final有哪些用法?
多型
1.多型的好處和弊端?
2.代碼中如何實作多型?
3.Java 中實作多型的機制是什么?
內部類Lambda
1.內部類的作用?
2.一個java檔案內部可以有類?(非內部類)
3.Lambda的使用前提是什么?
4.Lambda與匿名內部類區別?
static關鍵字
1.是否可以在static環境中訪問非static變數?
2.static都有哪些用法?
3.靜態變數和實體變數的區別?
4.static特點?
資料型別
1.String s1=”ab”, String s2=”a”+”b”, String s3=”a”, String s4=”b”, s5=s3+s4請問s5==s2回傳什么?
2.3*0.1==0.3回傳值是什么?
3.基本資料型別的默認值?基本資料型別所占的位元組以及封裝他們的類?
4.String屬于那個類,以及常用的方法?
5.String, StringBuffer和StringBuilder區別?
例外類
1.error和exception有什么區別?
2.運行時例外和一般例外有何不同?
3.Java中例外處理機制的原理?
4.你平時在專案中是怎樣對例外進行處理的?
5.throw和throws有什么區別?
6.例外處理的時候,finally代碼塊的重要性是什么?
7.請列出 5 個運行時例外?
8.try catch finally,try里有return,finally還執行么?
集合
1、List、Map、Set三個介面,存取元素時,各有什么特點?
2、ArrayList和LinkedList的底層實作原理?他們為什么執行緒不安全?在多執行緒并發操作下,我們應該用什么替代?
3、HashMap和HashTable有什么區別?其底層實作是什么?CurrentHashMap的鎖機制又是如何?如果想將一個Map變為有序的,該如何實作?
4.什么是迭代器(Iterator)?
5.Arraylist 與 LinkedList 區別?
6.Arraylist 與 LinkedList 應用場景?
7.Collection 和 Collections的區別?
8.為何Map介面不繼承Collection介面?
9.當兩個物件的hashcode相同會發生什么?
10.HashMap和Hashtable有什么區別?
11.List 和 Set 區別?
12.Set和List對比?
13.當兩個物件的hashcode相同會發生什么?
14.如果兩個鍵的hashcode相同,你如何獲取值物件?
15.有沒有可能兩個不相等的物件有相同的hashcode?
16.HashMap、LinkedHashMap、TreeMap的區別?
17.HashMap、LinkedHashMap、ConcurrentHashMap、ArrayList、LinkedList的底層實作,
18.==和 equals hashCode 的區別?
19.自然排序Comparble和比較器排序Comparator的異同點?
泛型
1.為什么使用泛型?
2.泛型用在什么地方?
3.如何使用泛型類?
樹
1.什么是二叉樹?
2.什么是二叉查找樹?
3.什么是平衡二叉樹?
序列化
1.什么是 Java 序列化?
2.如何實作 Java 序列化?
3.Java 序列話中,如果有些欄位不想進行序列化怎么辦?
4.物件操作流是字符流還是位元組流?
5.如何在讀寫檔案時指定字符集?
6.字符緩沖流特有方法?
7.為什么使用物件流?
多執行緒
1.什么是執行緒?
2.執行緒和行程有什么區別?
3.如何在Java中實作執行緒?
4.用Runnable還是Thread?
5.Thread 類中的start() 和 run() 方法有什么區別?
6.Java中Runnable和Callable有什么不同?
7.Java記憶體模型是什么?
8.Java中的volatile 變數是什么?
9.什么是執行緒安全?Vector是一個執行緒安全類嗎?
10.Java中如何停止一個執行緒?
11.Java中notify 和 notifyAll有什么區別?
12. 什么是執行緒池? 為什么要使用它?
13.如何寫代碼來解決生產者消費者問題?
14.Java多執行緒中的死鎖?
15.Java中synchronized 和 ReentrantLock 有什么不同?
16.詳談Synchronized?
17.在Java中Lock介面與synchronized塊的區別是什么?
18.synchronized 的原理是什么?有什么不足?
19.關于成員變數和區域變數?
20. 如果你提交任務時,執行緒池佇列已滿,會時發會生什么?
21.volatile關鍵字的作用是?
22.守護執行緒和非守護執行緒有什么區別?
23.執行緒的生命周期?
24.wait和sleep,notify()鎖方面區別?
25.什么情況下會出現執行緒安全問題?
26.Java中規定了執行緒有哪幾種狀態?
27.什么是原子性?
28.Java中哪些操作是原子操作?
29.什么是CAS演算法?
30.synchronized和CAS的區別?
31.并發容器Hashtable和ConcurrentHashMap特點?
反射
1.Java反射機制的作用?
2.什么是反射機制?
3.哪里用到反射機制?
4.反射機制的優缺點?
5.反射中,Class.forName 和 ClassLoader 區別
6.什么是雙親委派模型?
7.為什么要有雙親委派模型?
8.怎么利用反射使用私有成員?
網路通信
1.什么是三次握手?
2.什么是四次揮手?
3.TCP通信注意事項?
web階段
jsp相關
1.jsp內置物件和EL內置物件的區別與聯系?
2.說一下 jsp 的 4 種作用域?
3.ServletContext 與application的異同?
4.jsp 有哪些內置物件?作用分別是什么?
概念相關
1.post和get區別?
2.簡單闡述相對路徑和絕對路徑?
3.Cookie和session的區別?
4.servlet四大域物件的區別?
5.什么是活化與鈍化?
6.EL內置物件有哪些?
7.如果有大量的網站訪問量,那么會產生很多的session,該怎么解決?
8.頁面傳遞物件的方法?
9.session 和 application的區別?
servlet相關
1.解釋一下什么是servlet?
2.servlet的生命周期?
3.servlet生命周期方法有哪些?
4.servlet過濾器的作用?
5.servlet監聽器的作用?
6.web.xml中組件的加載順序?
7.如何確保servlet在應用啟動之后被加載到記憶體?
8.HttpServlet為什么宣告為抽象類?
9.redirect(重定向)和forward(請求轉發)區別?
10.sevlet中的屬性域有哪些?
11.Servlet是否執行緒安全?
12.如何創建執行緒安全的servlet?(SingleThreadModel方法不算)
13.是否有必要重寫service方法?
14.servlet包裝類有什么用?
15.在servlet中能否產生類似死鎖情況?
16.Servlet API中forward()與redirect()的區別?
17.ServletContext物件和ServletConfig物件的區別?
18.PrintWriter和ServletOutPutStream類有什么區別?
19.在一個servlet能否同時獲取PrintWriter和ServletOutputStream物件?
20.Request物件的主要方法有哪些?
21.jsp和servlet的異同點以及聯系是什么?
資料庫階段
索引相關
1.什么是索引?
2.索引是個什么樣的資料結構呢?
3.在建立索引的時候,都有哪些需要考慮的因素呢?
4.關心過業務系統里面的sql耗時嗎?統計過慢查詢嗎?對慢查詢都怎么優化過?
5.區別B樹,B-,B+,B*?
6.MySQL優化策略?
7.key和index的區別?
8.怎么驗證 mysql 的索引是否滿足需求?
事務相關
1.ACID是什么?可以詳細說一下嗎?
2.同時有多個事務在進行會怎么樣呢?
3.怎么解決這些問題呢?MySQL的事務隔離級別了解嗎?
4.Innodb使用的是哪種隔離級別呢?
5.對MySQL的鎖了解嗎?
6.MySQL都有哪些鎖呢?像上面那樣子進行鎖定豈不是有點阻礙并發效率了?
7.行級鎖定的優點缺點?
8.說一下 mysql 的行鎖和表鎖?
表設計相關
1. 為什么要盡量設定一個主鍵?
2.主鍵使用自增ID還是UUID?
3. 欄位為什么要求定義為not null?
4.varchar(10)和int(10)代表什么含義?
5.建表策略?
存盤引擎相關
1. MySQL支持哪些存盤引擎?
2.InnoDB和MyISAM有什么區別?
3.什么是存盤程序?有哪些優缺點?
4.說一說三個范式?
答案整理
Java基礎進階階段
基礎概念類
1.JDK1.8新特性?
提供lambda運算式極大地減少了代碼的冗余; 在介面中可以使用default和static關鍵字來修飾介面中的普通方法; 提供新的API LocalDate | LocalTime | LocalDateTime
- Java.util.Date和SimpleDateFormatter執行緒上都不安全,而LocalDate和LocalTime和 String一樣都是不可改變類,執行緒上比較安全,還不能修改;
- Java.util.Date月份從0開始,12月是11,而java.time.LocalDate月份和星期都改成了 enum, 就不可能出錯了;
2.面向物件和面向程序的區別?
面向程序
- 優點:性能比面向物件高,因為類呼叫時需要實體化,開銷比較大,比較消耗資源,比如,單片機、嵌入式開發、Linux/Unix 等一般采用面向程序開發,性能是最重要的因素,
- 缺點:沒有面向物件易維護、易復用、易擴展,
面向物件
- 優點:易維護、易復用、易擴展,由于面向物件有封裝、繼承、多型性的特性,可以設計出低耦合的系統,使系統更加靈活、更加易于維護,
- 缺點:性能比面向程序低,
3.什么是值傳遞和參考傳遞?
- 值傳遞,是對基本型變數而言的,傳遞的是該變數的一個副本,改變副本不影響原變數,
- 參考傳遞,一般是對于物件型變數而言的,傳遞的是該物件地址的一個副本,并不是原物件本身,
一般認為,Java 內的傳遞都是值傳遞,Java 中實體物件的傳遞是參考傳遞,
4.什么是不可變物件
- 不可變物件指物件一旦被創建,狀態就不能再改變,任何修改都會創建一個新的物件,如 String、Integer及其它包裝類,
5.講講類的實體化順序?
初始化順序如下:
- 父類靜態變數
- 父類靜態代碼塊
- 子類靜態變數、
- 子類靜態代碼塊
- 父類非靜態變數(父類實體成員變數)
- 父類建構式
- 子類非靜態變數(子類實體成員變數)
- 子類建構式
6.java 創建物件的幾種方式
- 采用new
- 通過反射
- 采用clone
- 通過序列化機制
前2者都需要顯式地呼叫構造方法,造成耦合性最高的恰好是第一種,因此你發現無論什么框架,只要涉及到解耦必先減少new的使用
7.Java訪問修飾符的作用域
作用域 當前類 同包 子類 其它
- public Y Y Y Y
- protected Y Y Y N
- default Y Y N N
- private Y N N N
8.switch中能否使用string作為引數?
- 在jdk1.7之前,switch只能支持byte,short,char,int或者其他對應的封裝類以及Enum型別.jdk1.7之后開始支持String
9.switch中能否作用在byte,long上?
- 可以用在byte上,不能用在long上
10.什么是自動拆裝箱?
- 自動裝箱和拆箱,就是基本型別和參考型別之間的轉換,
- 把基本資料型別轉換成包裝類的程序就是打包裝,為裝箱,
- 把包裝類轉換成基本資料型別的程序就是拆包裝,為拆箱,
11.如何正確的退出多層嵌套回圈?
使用標號和break;
繼承
-
Java支持多繼承么?
- Java類中不支持多繼承,但是可以多實作,所以介面的擴展性比較好,實際開發中盡量避免繼承的使用
-
父類的靜態方法能否被子類重寫
- 不能,重寫只適用于實體方法,不能用于靜態方法,而子類當中含有和父類相同簽名的靜態方法,我們一般稱之為隱藏,
-
繼承的好處和壞處
- 好處:
- 子類能自動繼承父類的物件 2、創建子類的物件時,無須創建父類的物件
- 壞處:
- 破壞封裝,子類與父類之間緊密耦合,子類依賴于父類的實作,子類缺乏獨立性,
- 支持擴展,但是往往以增強系統結構的復雜度為代價
- 不支持動態繼承,在運行時,子類無法選擇不同的父類
- 子類不能改變父類的介面
- 好處:
介面抽象類
1.介面的意義
- 規范,擴展,回呼,
2.抽象類的意義
- 為其他子類提供一個公共的型別
- 封裝子類中重復定義的內容
- 定義抽象方法,子類雖然有不同的實作,但是定義時一致的
3.抽 象 的 (abstract) 方 法 是 否 可 同 時 是 靜 態 的 (static), 是 否 可 同 時 是 本 地 方 法(native)
- abstract關鍵字不能同時與static或private或final同時修飾一個方法;
4.抽象類和介面區別?
-
語法區別:
-
抽象類可以有構造方法,介面不能有構造方法
-
抽象類中可以有普通成員變數,介面中沒有普通成員變數;
-
抽象類中可以有非抽象的方法,介面中的方法都必須是抽象的;
-
抽象類中的方法可以是public,protected型別,介面中的方法只能是public型別的,切 默認為public abstract型別;
-
抽象類中可以有靜態方法,介面中不能有靜態方法;
-
抽象類中的靜態變數訪問型別可以是任意的,但介面中的靜態變數只能是public static final 型別,
-
.一個類可以實作多個介面,但一個類只能繼承一個抽象類;
-
-
應用區別:
-
介面更多是在系統架構方面發揮作用,主要用于定義模塊之間的通信契約;而抽象類在代碼方法 發揮作用,可以使用代碼塊的重用;
-
5.Java中介面可不可以繼承一般類,為什么?
不可以因為介面中只能出現3種成員:
-
公共的靜態常量
-
公共的抽象方法
-
靜態內部類
而一個類中,就算什么都不寫,也必須帶一個構造方法,在extends時就會被子類繼承,如果是介面也會 繼承這個構造方法,很明顯構造方法不在上面三項之列 而如果類中有一般的方法和成員變數,也會被子類全部繼承,這些更不能出現在介面中了,所以介面是絕 對不可能繼承一個類的
6.多載與重寫區別
override(重寫)
- 方法名、引數、回傳值相同,
- 子類方法不能縮小父類方法的訪問權限,
- 子類方法不能拋出比父類方法更多的例外(但子類方法可以不拋出例外),
- 存在于父類和子類之間,
- 被final修飾的方法,不能被重寫,
overload(多載)
- 引數型別、個數、順序至少有一個不相同,
- 不能多載只有回傳值不同的方法名,
- 存在于父類和子類、同類中,
7.final有哪些用法?
- 被final修飾的類不可以被繼承
- 被final修飾的方法不可以被重寫
- 被final修飾的變數不可以被改變,如果修飾參考,那么表示參考不可變,參考指向的內容可變,
注:修飾變數, final 資料型別 變數名=資料值; 如果該變數是基本資料型別,則值不能修改,如果該變數是參考資料型別,則地址值不能改(既只能new一次);
- 被final修飾的方法,JVM會嘗試將其行內,以提高運行效率
- 被final修飾的常量,在編譯階段會存入常量池中,
回答出編譯器對final域要遵守的兩個重排序規則更好:
- 在建構式內對一個final域的寫入,與隨后把這個被構造物件的參考賦值給一個參考變數,這兩個操作之間不能重排序,
- 初次讀一個包含final域的物件的參考,與隨后初次讀這個final域,這兩個操作之間不能重排序,
多型
1.多型的好處和弊端
許不同類物件對同一訊息做出回應,即同一訊息可以根據發送物件的不同而采用多種不同的行為方式(發送訊息就是函式呼叫),即父型別的參考指向子型別的物件,
- 優點:
- 可替換性:多型對已存在代碼具有可替換性
- 可擴充性:增加新的子類不影響已經存在的類結構
- 更加靈活
- 弊端:
- 不能使用子類的特有內容
2.代碼中如何實作多型
實作多型主要有以下三種方式:
-
介面實作
-
繼承父類重寫方法
-
同一類中進行方法多載
3.Java 中實作多型的機制是什么?
- 父類物件指向子類參考
內部類Lambda
1.內部類的作用?
- 內部類可以有多個實體,每個實體都有自己的狀態資訊,并且與其他外圍物件的資訊相互獨立.在單個外圍類當中,可以讓多個內部類以不同的方式實作同一介面,或者繼承同一個類.創建內部類物件的時刻不依賴于外部類物件的創建,
- 內部類提供了更好的封裝,除了該外圍類,其他類都不能訪問,
2.一個java檔案內部可以有類?(非內部類)
- 只能有一個public公共類,但是可以有多個default修飾的類,
3.Lambda的使用前提是什么?
- 當需要一個介面的實作類物件,且介面中有且僅有一個抽象方法的時候,可以使用lambda完成這個實作類要做的事情;(替代匿名內部類)
4.Lambda與匿名內部類區別
- lambda運算式編譯后并不會生成.class檔案,而匿名內部類編譯后會產生單獨的class檔案;
- 匿名內部類可以用在類,抽象類,介面中,而lambda運算式只能用在有且僅有一個抽象方法的介面中;
static關鍵字
1.是否可以在static環境中訪問非static變數?
- static變數在Java中是屬于類的,它在所有的實體中的值是一樣的,當類被Java虛擬機載入的時候,會對static變數進行初始化,如果你的代碼嘗試不用實體來訪問非static的變數,編譯器會報錯,因為這些變數還沒有被創建出來,還沒有跟任何實體關聯上,
2.static都有哪些用法?
- 被static所修飾的變數/方法都屬于類的靜態資源,類實體所共享.
- static也用于靜態塊,多用于初始化操作.
- 此外static也多用于修飾內部類,此時稱之為靜態內部類.
3.靜態變數和實體變數的區別?
- 靜態變數存盤在方法區,屬于類所有,實體變數存盤在堆當中,其參考存在當前執行緒堆疊,
4.static特點
- 如果修飾構造代碼塊,僅在類第一次加載的時候,執行一次;
- 如果修飾成員變數,這個變數的值屬于類;可以被所有的物件共享;
- 如果修飾成員方法,在方法中不能使用this,super;
- 靜態的內容優先于物件存在!
資料型別
1.String s1=”ab”, String s2=”a”+”b”, String s3=”a”, String s4=”b”, s5=s3+s4請問s5==s2回傳什么?
- 回傳false,在編譯程序中,編譯器會將s2直接優化為”ab”,會將其放置在常量池當中,s5則是被創建在堆區,相當于s5=new String(“ab”);
2.3*0.1==0.3回傳值是什么
- false,因為有些浮點數不能完全精確的表示出來
3.基本資料型別的默認值?基本資料型別所占的位元組以及封裝他們的類?
-
默認值
-
byte、short、int、long的默認值為0
-
float、double默認值為0.0
-
char默認值為空
-
boolean默認值為false
-
-
所占位元組
-
byte 1個位元組--Byte
-
short 2個位元組--Short
-
char 2個位元組--Character
-
int 4個位元組--Integer
-
long 8個位元組--Long
-
float 4個位元組--Float
-
double 8個位元組--Double
-
4.String屬于那個類,以及常用的方法?
-
.java.lang.string
-
substring(),indexOf(),concat(),endswith(),length(),replace()
5.String, StringBuffer和StringBuilder區別
- String的值是不可改變的,這就導致每次對String的操作都會生成新的String物件,不禁效率底下, 而且浪費大量的記憶體空間;
- StringBuilder是可變類,任何對他指向的字串的操作都不會產生新的對 象,但單執行緒不安全;
- StringBuffer底層方法使用了synchronized關鍵字,執行緒比較安全,但效率 較StringBuilder慢
例外相關
1.error和exception有什么區別
- error表示系統級的錯誤,是java運行環境內部錯誤或者硬體問題,不能指望程式來處理這樣的問題,除了退出運行外別無選擇,它是Java虛擬機拋出的,
- exception 表示程式需要捕捉、需要處理的例外,是由與程式設計的不完善而出現的問題,程式必須處理的問題
2.運行時例外和一般例外有何不同
- Java提供了兩類主要的例外:runtimeException和checkedException
- 一般例外(checkedException)主要是指IO例外、SQL例外等,對于這種例外,JVM要求我們必須對其進行cathc處理,所以,面對這種例外,不管我們是否愿意,都是要寫一大堆的catch塊去處理可能出現的例外,
- 運行時例外(runtimeException)我們一般不處理,當出現這類例外的時候程式會由虛擬機接管,比如,我們從來沒有去處理過NullPointerException,而且這個例外還是最常見的例外之一,
- 出現運行時例外的時候,程式會將例外一直向上拋,一直拋到遇到處理代碼,如果沒有catch塊進行處理,到了最上層,如果是多執行緒就有Thread.run()拋出,如果不是多執行緒那么就由main.run()拋出,拋出之后,如果是執行緒,那么該執行緒也就終止了,如果是主程式,那么該程式也就終止了,
- 其實運行時例外的也是繼承自Exception,也可以用catch塊對其處理,只是我們一般不處理罷了,也就是說,如果不對運行時例外進行catch處理,那么結果不是執行緒退出就是主程式終止,
- 如果不想終止,那么我們就必須捕獲所有可能出現的運行時例外,如果程式中出現了例外資料,但是它不影響下面的程式執行,那么我們就該在catch塊里面將例外資料舍棄,然后記錄日志,如果,它影響到了下面的程式運行,那么還是程式退出比較好些,
3.Java中例外處理機制的原理
Java通過面向物件的方式對例外進行處理,Java把例外按照不同的型別進行分類,并提供了良好的介面,當一個方法出現例外后就會拋出一個例外物件,該物件中包含有例外資訊,呼叫這個物件的方法可以捕獲到這個例外并對例外進行處理,Java的例外處理是通過5個關鍵詞來實作的:try catch throw throws finally,
一般情況下是用try來執行一段程式,如果出現例外,系統會拋出(throws),我們可以通過它的型別來捕捉它,或最后由預設處理器來處理它(finally),
- try:用來指定一塊預防所有例外的程式
- catch:緊跟在try后面,用來捕獲例外
- throw:用來明確的拋出一個例外
- throws:用來標明一個成員函式可能拋出的各種例外
- finally:確保一段代碼無論發生什么例外都會被執行的一段代碼,
4.你平時在專案中是怎樣對例外進行處理的,
- 盡量避免出現runtimeException ,例如對于可能出現空指標的代碼,帶使用物件之前一定要判斷一下該物件是否為空,必要的時候對runtimeException
也進行try catch處理,
- 進行try catch處理的時候要在catch代碼塊中對例外資訊進行記錄,通過呼叫例外類的相關方法獲取到例外的相關資訊,回傳到web端,不僅要給用戶良好的用戶體驗,也要能幫助程式員良好的定位例外出現的位置及原因,例如,以前做的一個專案,程式遇到例外頁面會顯示一個圖片告訴用戶哪些操作導致程式出現了什么例外,同時圖片上有一個按鈕用來點擊展示例外的詳細資訊給程式員看的,
5.throw和throws有什么區別?
- throw關鍵字用來在程式中明確的拋出例外,相反,throws陳述句用來表明方法不能處理的例外,每一個方法都必須要指定哪些例外不能處理,所以方法的呼叫者才能夠確保處理可能發生的例外,多個例外是用逗號分隔的,
6.例外處理的時候,finally代碼塊的重要性是什么?
- 無論是否拋出例外,finally代碼塊總是會被執行,就算是沒有catch陳述句同時又拋出例外的情況下,finally代碼塊仍然會被執行,最后要說的是,finally代碼塊主要用來釋放資源,比如:I/O緩沖區,資料庫連接,
7.請列出 5 個運行時例外?
- NullPointerException 空指標
- IndexOutOfBoundsException 索引越界
- ClassCastException 型別轉換例外
- ArrayStoreException 當你試圖將錯誤型別的物件存盤到一個物件陣列時拋出的例外
- BufferOverflowException 寫入的長度超出了允許的長度
- IllegalArgumentException 方法的引數無效
- NoClassDefFoundException - JAVA運行時系統找不到所參考的類
8.try catch finally,try里有return,finally還執行么?**
- finally陳述句總會執行即使try里包含continue,break,return,try塊結束后,finally塊也會執行
- 如果try、catch中有return陳述句,finally中沒有return,那么在finally中修改除包裝型別和靜態變數、全域變數以外的資料都不會對try、catch中回傳的變數有任何的影響(包裝型別、靜態變數會改變、全域變數)
- 盡量不要在finally中使用return陳述句,如果使用的話,會忽略try、catch中的回傳陳述句,也會忽略try、catch中的例外,屏蔽了錯誤的發生,
- finally中避免再次拋出例外,一旦finally中發生例外,代碼執行將會拋出finally中的例外資訊,try、catch中的例外將被忽略
集合部分
1、List、Map、Set三個介面,存取元素時,各有什么特點?
- Set集合的add有一個boolean型別的回傳值,當集合中沒有某個元素時,則可以成功加入該 元素,回傳結果為true;當集合中存在與某個元素equals方法相等 的元素時,則無法加入該元素, 取元素時只能用Iterator介面取得所有元素,在逐一遍歷各個元素;
- List表示有先后順序的集合,呼叫add()方法,指定當前物件在集合中的存放位置;一個物件可 以被反復存進集合中;每呼叫一次add()方法,該物件就會被插入集合中一次,其實,并不是把對 象本身存進了集合中,而是在集合中使用一個索引變數指向了該物件,當一個物件被add多次時, 即有多個索引指向了這個物件,List去元素時可以使用Iterator取出所有元素,在逐一遍歷,還可 以使用get(int index)獲取指定下表的元素;
- Map是雙列元素的集合,呼叫put(key,value),要存盤一對key/value,不能存盤重復的key, 這個是根據eauals來判斷;取元素時用get(key)來獲取key所對 應的value,另外還可以獲取 全部key,全部value
2、ArrayList和LinkedList的底層實作原理?他們為什么執行緒不安全?在多執行緒并發操作下,我們應該用什么替代?
- ArrayList底層通過陣列實作,ArrayList允許按序號索引元素,而插入元素需要對陣列進行移位等記憶體操作,所以索引快插入較慢;(擴容方式)一旦我們實體化了ArrayList 無參建構式默認陣列長度為10,add方法底層如 果增加的元素超過了10個,那么ArrayList底層會生成一個新的陣列,長度為原來陣列長度的1.5倍+1,然后將原陣列內容復制到新陣列中,并且后續加的內容都會放到新陣列中,當新陣列無法容納增加元素時,重復該程序;
- LinkedList底層通過雙向鏈表實作,取元素時需要進行前項或后項的遍歷,插入元素時只需要記錄本項的前后 項即可,所以插入快查詢慢;
- ArrayList和LinkedList底層方法都沒有加synchronized關鍵詞,多執行緒訪問時會出現多個執行緒先后更改資料造成得到的資料是臟資料;多執行緒并發操作下使用Vector來代替,Vector底層也是陣列,但底層方法都加synchronized關鍵字使執行緒安全,效率較ArrayList差;
3、HashMap和HashTable有什么區別?其底層實作是什么?CurrentHashMap的鎖機制又是如何?如果想將一個Map變為有序的,該如何實作?
- 區別:
- HashMap沒有實作synchronized執行緒非安全,HashTable實作了synchronized執行緒安全;
- HashMap允許key和value為null,而HashTable不允許
- 底層原理:陣列+鏈表實作
- ConcurrentHashMap鎖分段技術:HashTable效率低下的原因,是因為所訪問HashTable的執行緒都必須競爭同一把鎖,那假如容器中有多把鎖,每一把鎖用于鎖住容器中的一部分資料,那么當多執行緒訪問容器中不同的資料時,執行緒間就不會存在鎖競爭,從而提高并發訪問率;ConcurrentHashMap使用的就是鎖分段技術,首先將資料分成一段一段的存盤,然后給每一段資料配一把鎖,當一個執行緒占用鎖訪問其中一個資料時,其他段的資料也能被其他執行緒訪問;
- 實作TreeMap
4.什么是迭代器(Iterator)?
- Iterator介面提供了很多對集合元素進行迭代的方法,每一個集合類都包含了可以回傳迭代器實體的迭代方法,迭代器可以在迭代的程序中洗掉底層集合的元素,但是不可以直接呼叫集合的remove(Object Obj)洗掉,可以通過迭代器的remove()方法洗掉
5.Arraylist 與 LinkedList 區別
- Arraylist:
- 優點:ArrayList是實作了基于動態陣列的資料結構,因為地址連續,一旦資料存盤好了,查詢操作效率會比較高(在記憶體里是連著放的),
- 缺點:因為地址連續, ArrayList要移動資料,所以插入和洗掉操作效率比較低,
- LinkedList:
- 優點:LinkedList基于鏈表的資料結構,地址是任意的,所以在開辟記憶體空間的時候不需要等一個連續的地址,對于新增和洗掉操作add和remove,LinedList比較占優勢,LinkedList 適用于要頭尾操作或插入指定位置的場景
- 缺點:因為LinkedList要移動指標,所以查詢操作性能比較低,
6.Arraylist 與 LinkedList 應用場景?
- 當需要對資料進行對此訪問的情況下選用ArrayList,當需要對資料進行多次增加洗掉修改時采用LinkedList,
7.Collection 和 Collections的區別
- Collection是集合類的上級介面,繼承與他的介面主要有Set 和List.Collections是針對集合類的一個幫助類,他提供一系列靜態方法實作對各種集合的搜索、排序、執行緒安全化等操作(帶s的基本都是工具類,如Arrays)
8.為何Map介面不繼承Collection介面?
- 盡管Map介面和它的實作也是集合框架的一部分,但Map不是集合,集合也不是Map,因此,Map繼承Collection毫無意義,反之亦然,
- 如果Map繼承Collection介面,那么元素去哪兒?Map包含key-value對,它提供抽取key或value串列集合的方法,但是它不適合“一組物件”規范,
10.HashMap和Hashtable有什么區別?
- HashMap是非執行緒安全的,HashTable是執行緒安全的,
- HashMap的鍵和值都允許有null值存在,而HashTable則不行,
- 因為執行緒安全的問題,HashMap效率比HashTable的要高,
- Hashtable是同步的,而HashMap不是,因此,HashMap更適合于單執行緒環境,而Hashtable適合于多執行緒環境,
一般現在不建議用HashTable
- 是HashTable是遺留類,內部實作很多沒優化和冗余
- 即使在多執行緒環境下,現在也有同步的ConcurrentHashMap替代,沒有必要因為是多執行緒而用HashTable,
11.List 和 Set 區別?
List,Set都是繼承自Collection介面
- List特點:
- 元素有放入順序
- 元素可重復
- Set特點:
- 元素無放入順序
- 元素不可重復
- 重復元素會覆寫掉
(注意:元素雖然無放入順序,但是元素在set中的位置是有該元素的HashCode決定的,其位置其實是固定的,加入Set 的Object必須定義equals()方法 ,另外list支持for回圈,也就是通過下標來遍歷,也可以用迭代器,但是set只能用迭代,因為他無序,無法用下標來取得想要的值,)
12.Set和List對比?
- Set:檢索元素效率低下,洗掉和插入效率高,插入和洗掉不會引起元素位置改變,
- List:和陣列類似,List可以動態增長,查找元素效率高,插入洗掉元素效率低,因為會引起其他元素位置改變,
13.當兩個物件的hashcode相同會發生什么?
- 因為hashcde相同,所以它們的bucket位置相同,‘碰撞’會發生,因為HashMap使用鏈表存盤物件,這個Entry(包含有鍵值對的Map.Entry物件)會存盤在鏈表中,
14.如果兩個鍵的hashcode相同,你如何獲取值物件?
- 當我們呼叫get()方法,HashMap會使用鍵物件的hashcode找到bucket位置,然后會呼叫keys.equals()方法去找到鏈表中正確的節點,最終找到要找的值物件,
15.有沒有可能兩個不相等的物件有相同的hashcode?
- 有可能,(通話,重地)兩個不相等的物件可能會有相同的 hashcode 值,這就是為什么在 hashmap 中會有沖突,如果兩個物件相等,必須有相同的hashcode 值,反之不成立,
16.HashMap、LinkedHashMap、TreeMap的區別?
- HashMap是根據鍵的hashcode值存盤資料,根據鍵可以直接獲取它的值,具有很快的訪問速度,取得的資料完全是隨機的
- LinkedHashMap保存了記錄的插入順序,在使用Iterator進行遍歷的時候,先得到的肯定是先插入的資料,可以在構造時帶引數,按照應用次數來進行排序
- TreeMap實作SortMap介面,能夠把它保存的記錄根據鍵排序,默認的是升序排序,也可以指定排序的比較器,進行遍歷的時候得到的是排序過的記錄,
17.HashMap、LinkedHashMap、ConcurrentHashMap、ArrayList、LinkedList的底層實作,**
- HashMap是java資料結構中兩大結構陣列和鏈表的組合,HashMap底層陣列,陣列中的每一項又是一個鏈表,程式會先根據key的hashcode()方法回傳值決定該Entry在陣列中的
- 存盤位置,如果該位置上沒有元素,就會將元素放置在此位置上,如果兩個Entry的key相同,會呼叫equals,回傳值是true則覆寫原來的value值,回傳false則會形成Entry鏈,位于頭部,
- ArrrayList的底層實作是陣列,在執行add操作時,會先檢查陣列 大小是否可以容納新的元素,如果不夠就會進行擴容,然后會將原來的資料拷貝到新的陣列中,
- LinkedList底層是一個鏈表,其實作增刪改查和資料結構中的操作完全相同,而且插入是有序的,
- LinkedHashMap的底層結構式是雙鏈表,其他的邏輯處理與HashMap一致,同樣沒有鎖保護,多執行緒使用時存在風險,
- ConcurrentHashMap是segment陣列結構和HashEntry陣列結構組成的,segment在ConcurrentHashMap中充當鎖的角色,HashEntry用于存盤鍵值對資料,segment的結構是陣列和鏈表,一個segment中有一個HashEntry,每個HashEntry是一個鏈表結構的元素,對HashEntry中的資料進行修改時,需要先獲得它所對應的segment鎖,每個ConcurrentHashMap默認有16個segment,
18.==和 equals hashCode 的區別?
- 基本資料型別: ==比較的是內容 參考資料型別: ==比的是地址值,equals默認比地址值,重寫按照規則比較,hashCode
19.自然排序Comparble和比較器排序Comparator的異同點?
相同點:
回傳值的規則:
-
如果回傳值為負數,表示當前存入的元素是較小值,存左邊
-
如果回傳值為0,表示當前存入的元素跟集合中元素重復了,不存
-
如果回傳值為正數,表示當前存入的元素是較大值,存右邊
不同點:
1.用到的介面不同
-
自然排序: 自定義類實作Comparable介面,重寫compareTo方法,根據回傳值進行排序
-
比較器排序: 創建TreeSet物件的時候傳遞Comparator的實作類物件,重寫compare方法,根據回傳值進行排序
2.使用場景不同
-
自然排序能滿足大部分情況
-
存盤沒有修改權限的類時可以使用
20.Iterator 和 ListIterator 有什么區別?
-
Iterator可用來遍歷Set和List集合,但是ListIterator只能用來遍歷List,
-
Iterator對集合只能是前向遍歷,ListIterator既可以前向也可以后向,
-
ListIterator實作了Iterator介面,并包含其他的功能,比如:增加元素,替換元素,獲取前一個和后一個元素的索引,等等,
泛型
1.為什么使用泛型?
- 它提供了編譯時型別安全檢測機制,把運行時期的問題提前到了編譯期間
- 避免了強制型別轉換
2.泛型用在什么地方?
- 類,方法,介面
3.如何使用泛型類?
- 創建泛型類物件時,必須要給這個泛型確定具體的資料型別
樹
1.什么是二叉樹?
- 任意節點的子節點不超過2
2.什么是二叉查找樹?
- 每個節點最多有兩個子節點,左邊比當前節點小,右邊比當前節點大
3.什么是平衡二叉樹?
- 二叉樹左右子樹的樹高差不超過1,任意節點的左右子樹都是平衡二叉樹
- 通過左旋右旋保持樹的平衡
序列化
1.什么是 Java 序列化?
- 序列化就是一種用來處理物件流的機制,所謂物件流也就是將物件的內容進行流化,
- 可以對流化后的物件進行讀寫操作,也可將流化后的物件傳輸于網路之間,
- 序列化是為了解決在對物件流進行讀寫操作時所引發的問題,
- 反序列化的程序,則是和序列化相反的程序,
- 另外,我們不能將序列化局限在 Java 物件轉換成二進制陣列,例如說,我們將一個 Java 物件,轉換成 JSON 字串,或者 XML 字串,這也可以理解為是序列化,
2.如何實作 Java 序列化?
將需要被序列化的類,實作 Serializable 介面,該介面沒有需要實作的方法,implements Serializable 只是為了標注該物件是可被序列化的,
序列化
- 然后,使用一個輸出流(如:FileOutputStream)來構造一個 ObjectOutputStream(物件流)物件,接著,使用 ObjectOutputStream 物件的 #writeObject(Object obj) 方法,就可以將引數為 obj 的物件寫出(即保存其狀態),
反序列化
- 要恢復的話則用輸入流,
3.Java 序列話中,如果有些欄位不想進行序列化怎么辦?
- 對于不想進行序列化的變數,使用 transient 關鍵字修飾,
- 當物件被序列化時,阻止實體中那些用此關鍵字修飾的的變數序列化,
- 當物件被反序列化時,被 transient 修飾的變數值不會被持久化和恢復,
- transient 只能修飾變數,不能修飾類和方法,
4.物件操作流是字符流還是位元組流?
- 位元組流
5.如何在讀寫檔案時指定字符集?
jdk11之前:
- 使用轉換流InputStreamReader(輸入轉換流)位元組轉換字符橋梁/OutputStreamWriter(輸出轉換流)字符轉位元組橋梁
jdk11之后
- 直接使用FileReader指定
6.字符緩沖流特有方法?
- readLine():讀取一整行,到達尾處為null
- newLine():跨平臺換行
7.為什么使用物件流?
- 在開發中,經常需要將物件的資訊保存到磁盤中,如果使用前面所學的知識來實作,會非常的繁瑣,使用物件流就非常的方便
- 物件操作流可以將物件以位元組的形式寫到本地檔案中,直接打開是看不懂的,需要時可以再次用物件操作流讀到記憶體中
多執行緒
1.什么是執行緒?
- 執行緒是作業系統能夠進行運算調度的最小單位,它被包含在行程之中,是行程中的實際運作單位,執行緒是行程的一部分,是行程中的單個控制流,是一條執行路徑
2.執行緒和行程有什么區別?
- 執行緒是行程的子集,一個行程可以有很多執行緒,每條執行緒并行執行不同的任務,不同的行程使用不同的記憶體空間,而所有的執行緒共享一片相同的記憶體空間,
3.如何在Java中實作執行緒?
- 繼承Thread:
- 可以直接呼叫Thread中的方法
- 實作Runnable介面:
- 實作Runnable介面,將實作類作為引數傳遞給Thread物件
- 實作Callable介面:
- 實作Callabale介面,創建FutureTask物件,將Callable作為引數傳遞給FutureTask物件,再將FutureTask物件傳遞給Thread類
4.用Runnable還是Thread?
Java不支持類的多重繼承,但允許你呼叫多個介面,所以如果你要繼承其他類,當然是呼叫Runnable介面好了,
- Thread:
- 實際中用的相對較少,擴展性太差
- Runnable,Callable:
- 擴展性比較強,優先使用Runnable介面,需要執行完有回傳值可以選擇Callable介面
5.Thread 類中的start() 和 run() 方法有什么區別?
- start()方法被用來啟動新創建的執行緒,而且start()內部呼叫了run()方法,這和直接呼叫run()方法的效果不一樣,
當你呼叫run()方法的時候,只會是在原來的執行緒中呼叫,沒有新的執行緒啟動,start()方法才會啟動新執行緒,
6.Java中Runnable和Callable有什么不同?
- Runnable和Callable都代表那些要在不同的執行緒中執行的任務,Runnable從JDK1.0開始就有了,Callable是在JDK1.5增加的,它們的主要區別是Callable的 call() 方法可以回傳值和拋出例外,而Runnable的run()方法沒有這些功能,Callable可以回傳裝載有計算結果的Future物件,
7.Java記憶體模型是什么?
Java記憶體模型規定和指引Java程式在不同的記憶體架構、CPU和作業系統間有確定性地行為,它在多執行緒的情況下尤其重要,Java記憶體模型對一個執行緒所做的變動能被其它執行緒可見提供了保證,它們之間是先行發生關系,這個關系定義了一些規則讓程式員在并發編程時思路更清晰,比如,先行發生關系確保了:
-
執行緒內的代碼能夠按先后順序執行,這被稱為程式次序規則,
-
對于同一個鎖,一個解鎖操作一定要發生在時間上后發生的另一個鎖定操作之前,也叫做管程鎖定規則,
-
前一個對volatile的寫操作在后一個volatile的讀操作之前,也叫volatile變數規則,
-
一個執行緒內的任何操作必需在這個執行緒的start()呼叫之后,也叫作執行緒啟動規則,
-
一個執行緒的所有操作都會在執行緒終止之前,執行緒終止規則,
-
一個物件的終結操作必需在這個物件構造完成之后,也叫物件終結規則,
-
可傳遞性
8.Java中的volatile 變數是什么?
- volatile是一個特殊的修飾符,只有成員變數才能使用它,在Java并發程式缺少同步類的情況下,多執行緒對成員變數的操作對其它執行緒是透明的,volatile變數可以保證下一個讀取操作會在前一個寫操作之后發生,就是上一題的volatile變數規則,
9.什么是執行緒安全?Vector是一個執行緒安全類嗎?
- 多個執行緒可能會同時運行同一段代碼,如果每次運行結果和單執行緒運行的結果是一樣的,而且其他的變數的值也和預期的是一樣的,就是執行緒安全的,一個執行緒安全的計數器類的同一個實體物件在被多個執行緒使用的情況下也不會出現計算失誤,很顯然你可以將集合類分成兩組,執行緒安全和非執行緒安全的,Vector 是用同步方法來實作執行緒安全的, 而和它相似的ArrayList不是執行緒安全的,
10.Java中如何停止一個執行緒?
- 當run() 或者 call() 方法執行完的時候執行緒會自動結束,如果要手動結束一個執行緒,你可以用volatile 布爾變數或設定某個變數達到一定值的時候,來退出run()方法的回圈或者是取消任務來中斷執行緒,
11.Java中notify 和 notifyAll有什么區別?
- notify()方法不能喚醒某個具體的執行緒,所以只有一個執行緒在等待的時候它才有用武之地,
- notifyAll()喚醒所有執行緒并允許他們爭奪鎖確保了至少有一個執行緒能繼續運行
12. 什么是執行緒池? 為什么要使用它?
- 創建執行緒要花費昂貴的資源和時間,如果任務來了才創建執行緒那么回應時間會變長,而且一個行程能創建的執行緒數有限,為了避免這些問題,在程式啟動的時候就創建若干執行緒來回應處理,它們被稱為執行緒池,里面的執行緒叫作業執行緒,從JDK1.5開始,Java API提供了Executor框架讓你可以創建不同的執行緒池,比如單執行緒池,每次處理一個任務;數目固定的執行緒池或者是快取執行緒池(一個適合很多生存期短的任務的程式的可擴展執行緒池)
13.如何寫代碼來解決生產者消費者問題?
- 在現實中你解決的許多執行緒問題都屬于生產者消費者模型,就是一個執行緒生產任務供其它執行緒進行消費,你必須知道怎么進行執行緒間通信來解決這個問題,比較低級的辦法是用wait和notify來解決這個問題,比較贊的辦法是用Semaphore 或者 BlockingQueue來實作生產者消費者模型
14.Java多執行緒中的死鎖
死鎖是指兩個或兩個以上的行程在執行程序中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去,這是一個嚴重的問題,因為死鎖會讓你的程式掛起無法完成任務,死鎖的發生必須滿足以下四個條件:
-
互斥條件:一個資源每次只能被一個行程使用,
-
請求與保持條件:一個行程因請求資源而阻塞時,對已獲得的資源保持不放,
-
不剝奪條件:行程已獲得的資源,在末使用完之前,不能強行剝奪,
-
回圈等待條件:若干行程之間形成一種頭尾相接的回圈等待資源關系,
避免死鎖最簡單的方法就是阻止回圈等待條件,將系統中所有的資源設定標志位、排序,規定所有的行程申請資源必須以一定的順序(升序或降序)做操作來避免死鎖,
15.Java中synchronized 和 ReentrantLock 有什么不同?
- 這兩種方式最大區別就是對于Synchronized來說,它是java語言的關鍵字,是原生語法層面的互斥,需要jvm實作,而ReentrantLock它是JDK 1.5之后提供的API層面的互斥鎖,需要lock()和unlock()方法配合try/finally陳述句塊來完成,
16.詳談Synchronized
當Synchronized關鍵字修飾一個方法的時候,該方法叫做同步方法:java中的每個物件都有一個鎖(lock)或者叫做監視器(monitor),當訪問某個物件的synchronized方法的時候,表示將物件上鎖,此時其它任何執行緒都無法再去訪問synchronized方法了,直到之前的那個執行緒執行方法完畢后(或者是拋出了例外),那么將該物件的鎖釋放掉,其他執行緒才有可能再去訪問該synchronized方法,
- 注意1:
- 如果一個物件有多個synchronized方法,某一個時刻某個執行緒已經進入到了某個synchronized方法,那么在該方法沒有執行完畢前,其它執行緒是無法訪問該物件的任何synchronzed方法的,
- 注意2:
- 如果某個Synchronized方法是static的,那么當執行緒訪問該方法時,它鎖的并不是Synchronized方法所在的物件,而是Synchronized方法所在的物件所物件的Class物件,因為java中無論一個類有多少個物件,這些物件會對應唯一一個class物件,因此當執行緒分別訪問同一個類的兩個物件的兩個static Synchronized方法的時候,他們執行的順序也是順序的,也就是說一個執行緒先去執行方法,執行完畢后另一個執行緒才開始執行,
- 注意3:
- jdk1.6之后對synchronized(偏向鎖(根本就不加鎖)、輕量級鎖(CAS),重量級鎖(悲觀鎖))進行了大量的優化
17.在Java中Lock介面與synchronized塊的區別是什么?
- 用法不一樣,synchronized既可以加在方法上,也可以加載特定的代碼塊上,括號中表示需要鎖的物件,而Lock需要顯示地指定起始位置和終止位置,synchronzied是托管給jvm執行的,Lock鎖定是通過代碼實作的,
- 在性能上來說,如果競爭資源不激烈,兩者的性能是差不多的,而當競爭資源非常激烈時(即有大量執行緒同時競爭),此時Lock的性能要遠遠優于synchronized,所以說,在具體使用時要根據適當情況選擇,
- 鎖的機制不一樣,synchronized獲得鎖和釋放的方式都是在塊結構中,而且是自動釋放鎖,而Lock則需要開發人員手動去釋放,并且必須在finally塊中釋放,否則會引起死鎖問題的發生,
- Lock是一個介面,而synchronized是Java中的關鍵字,synchronized是內置的語言實作;
- synchronized在發生例外時,會自動釋放執行緒占有的鎖,因此不會導致死鎖現象發生;而Lock在發生例外時,如果沒有主動通過unLock()去釋放鎖,則很可能造成死鎖現象,因此使用Lock時需要在finally塊中釋放鎖
18.synchronized 的原理是什么?有什么不足?
- 原理:
- synchronized是 Java 內置的關鍵字,它提供了一種獨占的加鎖方式,
- synchronized的獲取和釋放鎖由JVM實作,用戶不需要顯示的釋放鎖,非常方便,
- 不足:
- 當執行緒嘗試獲取鎖的時候,如果獲取不到鎖會一直阻塞,
- 如果獲取鎖的執行緒進入休眠或者阻塞,除非當前執行緒例外,否則其他執行緒嘗試獲取鎖必須一直等待,
19.關于成員變數和區域變數
- 如果一個變數是成員變數,那么多個執行緒對同一個物件的成員變數進行操作的時候,他們對該成員變數是彼此影響的,也就是說一個執行緒對成員變數的改變會影響到另外一個執行緒;如果一個變數是區域變數,那么每個執行緒都會有一個該區域變數的拷貝,一個執行緒對該區域變數的改變不會影響到其它的執行緒,
20. 如果你提交任務時,執行緒池佇列已滿,會時發會生什么?
- 如果一個任務不能被調度執行那么ThreadPoolExecutor’s submit()方法將會拋出一個RejectedExecutionException例外,
21.volatile關鍵字的作用是?
- 保證變數的可見性,
- 在java記憶體結構中,每個執行緒都是有自己獨立的記憶體空間(此處指的執行緒堆疊),當需要對一個共享變數操作時,執行緒會將這個資料從主存空間復制到自己的獨立空間內進行操作,然后在某個時刻將修改后的值重繪到主存空間,這個中間時間就會發生許多奇奇怪怪的執行緒安全問題了,volatile就出來了,它保證讀取資料時只從主存空間讀取,修改資料直接修改到主存空間中去,這樣就保證了這個變數對多個操作執行緒的可見性了,換句話說,被volatile修飾的變數,能保證該變數的 單次讀或者單次寫 操作是原子的,
- 但是執行緒安全是兩方面需要的 原子性(指的是多條操作)和可見性,volatile只能保證可見性,synchronized是兩個均保證的,
- volatile輕量級,只能修飾變數;synchronized重量級,還可修飾方法,
- volatile不會造成執行緒的阻塞,而synchronized可能會造成執行緒的阻塞,
22.守護執行緒和非守護執行緒有什么區別?
- 程式運行完畢,JVM 會等待非守護執行緒完成后關閉,但是 JVM 不會等待守護執行緒
23.執行緒的生命周期?
執行緒的生命周期包含5個階段,包括:新建、就緒、運行、阻塞、銷毀,
-
新建:就是剛使用new方法,new出來的執行緒;
-
就緒:就是呼叫的執行緒的start()方法后,這時候執行緒處于等待CPU分配資源階段,誰先搶的CPU資源,誰開始執行;
-
運行:當就緒的執行緒被調度并獲得CPU資源時,便進入運行狀態,run方法定義了執行緒的操作和功能;
-
阻塞:在運行狀態的時候,可能因為某些原因導致運行狀態的執行緒變成了阻塞狀態,比如sleep()、wait()之后執行緒就處于了阻塞狀態,這個時候需要其他機制將處于阻塞狀態的執行緒喚醒,比如呼叫notify或者notifyAll()方法,喚醒的執行緒不會立刻執行run方法,它們要再次等待CPU分配資源進入運行狀態;
-
銷毀:如果執行緒正常執行完畢后或執行緒被提前強制性的終止或出現例外導致結束,那么執行緒就要被銷毀,釋放資源;
24.wait和sleep,notify()鎖方面區別?
- wait:讓執行緒等待,同時立即釋放鎖
- sleep():讓執行緒休眠,但是不會釋放鎖
- notify()或notifyAll(): 喚醒等待的執行緒,但是不會立即釋放鎖
25.什么情況下會出現執行緒安全問題?
- 多執行緒環境
- 有共享資料
- 有對共享資料的操作
26.Java中規定了執行緒有哪幾種狀態?
- 新建、就緒、阻塞、等待、計時等待、死亡
27.什么是原子性?
- 所謂的原子性就是完成功能的所有操作要么都執行,要么都不執行
28.Java中哪些操作是原子操作?
- 除了long和double之外的所有原始型別的賦值
- 所有volatile變數的賦值
- java.concurrent.Atomic *類的所有操作
29.什么是CAS演算法?
- 當預期值E==主記憶體中的值V,此時可以進行修改,將V改成新值
- 當預期值E!=主記憶體中的值V時,將主記憶體中的已經改變的值更新到自己的作業記憶體中,再次嘗試比較,直到預期值E等于主記憶體中的值V,才可以修改,這個程序稱為自旋
30.synchronized和CAS的區別?
- 相同點:
- 在多執行緒情況下,都可以保證共享資料的安全性,
- 在多執行緒情況下,都可以保證共享資料的安全性,
- 不同點:
- synchronized總是從最壞的角度出發,認為每次獲取資料的時候,別人都有可能修改,所以在每 次操作共享資料之前,都會上鎖,(悲觀鎖)
- CAS是從樂觀的角度出發,假設每次獲取資料別人都不會修改,所以不會上鎖,只不過在修改共享資料的時候,會檢查一下,別人有沒有修改過這個資料,如果別人修改過,那么我再次獲取現在最新的值,如果別人沒有修改過,那么我現在直接修改共享資料的值.(樂觀鎖)
- synchronized總是從最壞的角度出發,認為每次獲取資料的時候,別人都有可能修改,所以在每 次操作共享資料之前,都會上鎖,(悲觀鎖)
31.并發容器Hashtable和ConcurrentHashMap特點?
- Hashtable:
-
Hashtable采取悲觀鎖synchronized的形式保證資料的安全性
-
只要有執行緒訪問,會將整張表全部鎖起來,所以Hashtable效率低下
-
- ConcurrentHashMap:
-
采用sychronized+cas
-
執行緒安全,效率比Hashtable高,比HashMap低
-
反射類加載器
1.Java反射機制的作用?
- 在運行時判斷任意一個物件所屬的類,
- 在運行時判斷任意一個類所具有的成員變數和方法,
- 在運行時任意呼叫一個物件的方法
- 在運行時構造任意一個類的物件
2.什么是反射機制?
- 簡單說,反射機制值得是程式在運行時能夠獲取自身的資訊,在java中,只要給定類的名字,那么就可以通過反射機制來獲得類的所有資訊,
3.哪里用到反射機制?
- Spring 框架的 IoC 基于反射創建物件和設定依賴屬性,
- Spring MVC 的請求呼叫對應方法,也是通過反射,
- JDBC 的 Class#forName(String className) 方法,也是使用反射,
4.反射機制的優缺點?
- 靜態編譯:
- 在編譯時確定型別,系結物件,即通過
- 動態編譯:
- 運行時確定型別,系結物件,動態編譯最大限度的發揮了java的靈活性,體現了多型的應用,有利于降低類之間的耦合性,一句話,反射機制的優點就是可以實作動態創建物件和編譯,體現出很大的靈活性,特別是在J2EE的開發中它的靈活性就表現的十分明顯,比如,一個大型的軟體,不可能一次就把把它設計的很完美,當這個程式編譯后,發布了,當發現需要更新某些功能時,我們不可能要用戶把以前的卸載,再重新安裝新的版本,假如這樣的話,這個軟體肯定是沒有多少人用的,采用靜態的話,需要把整個程式重新編譯一次才可以實作功能的更新,而采用反射機制的話,它就可以不用卸載,只需要在運行時才動態的創建和編譯,就可以實作該功能,它的缺點是對性能有影響,使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什么并且它滿足我們的要求,這類操作總是慢于只直接執行相同的操作
5.反射中,Class.forName 和 ClassLoader 區別
- java中class.forName()和classLoader都可用來對類進行加載,
- class.forName()前者除了將類的.class檔案加載到jvm中之外,還會對類進行解釋,執行類中的static塊,
- 而classLoader只干一件事情,就是將.class檔案加載到jvm中,不會執行static中的內容,只有在newInstance才會去執行static塊,
6.什么是雙親委派模型?
- 如果一個類加載器收到了類加載請求,它并不會自己先去加載,而是把這個請求委托給父類的加載器去執行,如果父類加載器還存在其父類加載器,則進一步向上委托,依次遞回,請求最終將到達頂層的啟動類加載器,如果父類加載器可以完成類加載任務,就成功回傳,倘若父類加載器無法完成此加載任務,子加載器才會嘗試自己去加載,這就是雙親委派模式
7.為什么要有雙親委派模型?
- 為了保證類的全域唯一性,如果自定義類與Java核心類別庫中的類重名了,會被編譯但不會不執行
8.怎么利用反射使用私有成員?
- setAccessible(boolean flag)
網路通信
1.什么是三次握手?
-
客戶端向服務器發出取消連接請求
-
服務器向客戶端回傳一個回應,告訴客戶端收到了請求
-
客戶端向服務器端再次發出確認資訊建立連接
2.什么是四次揮手?
-
客戶端向服務器發出取消連接請求
-
服務器向客戶端回傳一個回應,表示收到客戶端取消請求
-
服務器向客戶端發出確認資訊
-
客戶端再次發送確認資訊,連接取消
3.TCP通信注意事項?
-
accept方法是阻塞的,作用就是等待客戶端連接
-
客戶端創建物件并連接服務器,此時是通過三次握手協議,保證跟服務器之間的連接
-
針對客戶端來講,是往外寫的,所以是輸出流 針對服務器來講,是往里讀的,所以是輸入流
-
read方法也是阻塞的
-
客戶端在關流的時候,還多了一個往服務器寫結束標記的動作
-
最后一步斷開連接,通過四次揮手協議保證連接終止
web階段
jsp相關
1.jsp內置物件和EL內置物件的區別與聯系
jsp內置物件:
-
jsp內可以在<%%>中直接使用的物件9個
EL運算式內置物件:
-
jsp呢可以在${}中直接使用的物件11個
pageContext物件是二者唯一相同的物件,其他都是各自獨立的物件
2.說一下 jsp 的 4 種作用域?
JSP中的四種作用域包括page、request、session和application,具體來說:
-
page代表與一個頁面相關的物件和屬性,
-
request代表與Web客戶機發出的一個請求相關的物件和屬性,一個請求可能跨越多個頁面,涉及多個Web組件;需要在頁面顯示的臨時資料可以置于此作用域,
-
session代表與某個用戶與服務器建立的一次會話相關的物件和屬性,跟某個用戶相關的資料應該放在用戶自己的session中,
-
application代表與整個Web應用程式相關的物件和屬性,它實質上是跨越整個Web應用程式,包括多個頁面、請求和會話的一個全域作用域,
3.ServletContext 與application的異同
- 相同:
- 其實servletContext和application 是一樣的,就相當于一個類創建了兩個不同名稱的變數,在 servlet中ServletContext就是application物件,大家只要打開jsp編譯過后生成的Servlet中 jspService()方法就可以看到如下的宣告: ServletContextapplication = null;application= pageContext.getServletContext();
- 不同:
- 兩者的區別就是application用在jsp中,servletContext用在servlet中,application和page requestsession 都是JSP中的內置物件,在后臺用ServletContext存盤的屬性資料可以用 application物件獲得, 而且application的作用域是整個Tomcat啟動的程序, 例如:ServletContext.setAttribute("username",username); 則在JSP網頁中可以使用 application.getAttribute("username"); 來得到這個用戶名,
4.jsp 有哪些內置物件?作用分別是什么?
JSP有9個內置物件:
-
request:封裝客戶端的請求,其中包含來自GET或POST請求的引數;
-
response:封裝服務器對客戶端的回應;
-
pageContext:通過該物件可以獲取其他物件;
-
session:封裝用戶會話的物件;
-
application:封裝服務器運行環境的物件;
-
out:輸出服務器回應的輸出流物件;
-
config:Web應用的配置物件;
-
page:JSP頁面本身(相當于Java程式中的this);
-
exception:封裝頁面拋出例外的物件,
概念相關
1.post和get區別?
- post:
- 資料不會顯示在地址欄
-
-
安全
-
大小無限制
-
可以提交二進制檔案
-
-
get:
-
資料顯示在地址欄
-
不安全
-
get方式提交有大小限制(約4kb)
-
2.相對路徑和絕對路徑?
-
相對路徑
概念:
-
不以"/"開頭,而是根據資源的相對位置關系的道德路徑
寫法:
-
從路徑不一樣的位置開始寫 例如:bbb/bbb ..bbb/b.html (../表示退一級)
-
-
絕對路徑
概念:
-
以"/"為開頭的路徑就是絕對路徑.該路徑不會隨著位置變化而變化
寫法:
-
當前資源在瀏覽器中的"被訪問路徑",并省略"http://localhost:8080"
-
3.Cookie和session的區別?
session是基于cookie
多次請求之間共享資料
- cookie:
-
資料存盤于客戶端--不安全
-
只能存字串
-
大小有限制
-
- session:
-
資料存盤于服務器端--安全
-
型別無限制
-
大小無限制
-
4.servlet四大域物件的區別?
-
pageContext:當前jsp頁面內共享資料
-
request:一次請求內共享資料,例如:請求轉發和包含都是一次請求,可以使用request傳遞資料
-
session:一次會話范圍內共享資料
-
servletContext:整個應用共享資料

5.什么是活化與鈍化?
服務器自動完成(注意使用本地Tomcat才行)
- 鈍化:
-
概念:序列化,把長時間不用,但還不到過期時間的 HttpSession 進行序列化,寫到磁盤上
- 時機:當訪問量很大時,服務器會根據 getLastAccessTime 來進行排序,對長時間不用,但是還沒到過期時間的 HttpSession 進行序列化,
-
- 活化:
-
概念:相反的狀態,從磁盤讀取到記憶體
-
時機:tomcat重新啟動時會將會話加載到記憶體
-
6.EL內置物件有哪些?
- 作用: 只能在EL 中使用,讓EL 更加簡單

注意:EL 運算式內置物件和,JSP 內置物件不是一回事,el運算式中想要使用jsp 中的物件需要使用pageContext 獲取
7.如果有大量的網站訪問量,那么會產生很多的session,該怎么解決?
session默認保存在記憶體中,記憶體資源寶貴,session資料量大導致記憶體利用率高,以下方案解決session記憶體存盤問題:
- 可以設定session超時時間,達到超時時間session自動清空
<session-config>
<session-timeout>20</session-timeout>
</session-config>
- 將session中的資料序列化到硬碟中
- 不使用session,使用cookie(此方法存在安全性問題)
8.頁面傳遞物件的方法?
- Request、session、application、cookie等
9.session 和 application的區別?
- 兩者的作用范圍不同:
- Session物件是用戶級的,而Application是應用程式級別的
- 一個用戶一個session物件,每個用戶的session物件不同,在用戶所訪問的網站多個頁面之間共享同一個session物件
- 一個Web應用程式一個application物件,每個Web應用程式的application物件不同,但一個Web應用程式的多個用戶之間共享同一個application物件,
- 兩者的生命周期不同:
- session物件的生命周期:用戶首次訪問網站創建,用戶離開該網站 (不一定要關閉瀏覽器) 消亡,
- application物件的生命周期:啟動Web服務器創建,關閉Web服務器銷毀,
Servlet相關
1.解釋一下什么是servlet
- Servlet有良好的生存期的定義,包括加載和實體化、初始化、處理請求以及服務結束,這個生存期由javax.servlet.Servlet 介面的init,service 和destroy方法表達,
- Web容器加載Servlet,Servlet被服務器實體化后,生命周期開始,通過呼叫servlet的init()方法進行servlet的初始化,通過呼叫service()方法實作,根據請求的不同呼叫不同的doXXX方法(doGet,doPost)方法,結束服務,web容器呼叫servlet的destroy()方法,
2.servlet的生命周期?
servlet容器負責管理servlet的生命周期,servlet生命周期如下:
- 加載和實體化 Servlet 容器裝載和實體化一個 Servlet,創建出該 Servlet 類的一個實體,
- 初始化 在 Servlet 實體化完成之后,容器負責呼叫該 Servlet 實體的 init() 方法,在處理用戶請求之前,來做一些額外的初始化作業,
- 處理請求 當 Servlet 容器接收到一個 Servlet 請求時,便運行與之對應的 Servlet 實體的 service() 方法,service() 方法再派遣運行與請求相對應的 doXX(doGet,doPost) 方法來處理用戶請求,
- 銷毀 當 Servlet 容器決定將一個 Servlet 從服務器中移除時 ( 如 Servlet 檔案被更新 ),便呼叫該 Servlet 實體的 destroy() 方法,在銷毀該 Servlet 實體之前, 來做一些其他的作業,
加載實體化,初始化,銷毀,在整個生命周期中只會執行一次
補充:
-
Servlet實體化有兩種:
-
第一次請求時,實體化servlet
-
在web.XML檔案中的<Servlet></Servlet>之間添加<loadon-startup>1</loadon-startup>,tomcat啟動時就會實體化servlet物件
-
3.servlet生命周期方法有哪些?
共有3個方法:
- public void init(ServletConfig config):
- 這個方法是由servlet容器呼叫用來初始化servlet的,這個方法在servlet生命周期中僅被呼叫一次,
- public void service(ServletRequest request, ServletResponse response):
- servlet容器為每個客戶端創建執行緒,然后都會執行service方法,但執行此方法前init方法必須已經被執行了,
- public void destroy():
- servlet從servlet容器中被移除時會呼叫此方法,僅被呼叫一次,
4.servlet過濾器的作用?
- 列印一些請求引數到日志中
- 授權請求訪問資源
- 在將請求提交給servlet之前,對request請求頭或請求體進行一些格式化的處理
- 將回應資料進行壓縮再回傳給瀏覽器,
- 解決亂碼問題,
5.servlet監聽器的作用?
- 監聽客戶端的請求,服務器端的操作等 ,通過監聽器,可以自動激發一些操作,比如監聽在線的用戶數量( 當增加一個HttpSession時,就自動觸發sessionCreated(HttpSessionEvent se)方法,在這個方法中就可以統計在線人數了 ),另外還可以用來初始化一些資源,比如資料庫連接池等(web.xml中配置的context-param只能是字串不能使物件,這時就得使用ServletContextListener了,注意,有讀者可能說ServletConext的setAttribute不是可以設定物件嗎?但是這是在servlet創建之后才能呼叫的方法,如果希望web應用一啟動就產生初始引數必須使用監聽器),
6.web.xml中組件的加載順序?
- context-param -> listener -> filter -> servlet
- 而同個型別之間的實際程式呼叫的時候的順序是根據對應的 mapping 的順序進行呼叫的
7.如何確保servlet在應用啟動之后被加載到記憶體?
- 通常情況下都是客戶端請求一個servlet,這個servlet才會被加載到記憶體,但對于某些很大加載很耗時的servlet我們希望應用啟動時就加載它們,這時我們可以在web.xml檔案中配置或者使用webServlet注解(servlet3.0)告訴容器系統一啟動就加載:
<servlet>
<servlet-name>foo</servlet-name>
<servlet-class>com.foo.servlets.Foo</servlet-class>
<load-on-startup>5</load-on-startup>
</servlet>
- load-on-startup節點中必須配置一個整數,整數代表應用一啟動就會被加載,負數表示當客戶端請求之后才加載,正數的值越小,說明越先被加載,
8.HttpServlet為什么宣告為抽象類?
- httpServlet類雖然是抽象類但卻沒有抽象方法,之所以這樣設計,是因為doget,dopost等方法并沒有業務邏輯,開發者至少應該重寫一個service中的方法,這就是我們不能實體化HttpServlet的原因,
9.redirect(重定向)和forward(請求轉發)區別?
重定向:
-
兩次請求
-
地址欄發生變化
-
不可以使用request域的共享資料
-
不可以訪問/WEB_INF下的資源
轉發:
-
一次請求
-
地址欄不發生變化
-
可以使用request域的共享資料
-
可以訪問/WEB_INF下的資源
補充:
servlet中怎么定義forward 和redirect?
- 轉發:request.getRequestDispatcher (“demo.jsp"). forward(request, response);
- 重定向:response.sendRedirect(“demo.jsp");
10.sevlet中的屬性域有哪些?
servlet提供了一些域物件方便內部servlet之間的通信,我們可以通過set/get方法為web應用設定或取出屬性值,servlet提供3個域(和jsp區分開來):
- request scope
- session scope
- application scope
分別由ServletRequest,HttpSession,ServletContext物件提供對應的set/get/remove方法去操作者三個域,
注:這跟web.xml中為servletConfig(針對單個servlet)和servletContext(針對web應用)定義的初始化引數不一樣,
11.Servlet是否執行緒安全?
- HttpServlet的init和destroy方法在servlet宣告周期中僅 呼叫一次,所以不用擔心它們的執行緒安全,但是service方法以及doget,dopost等方法是存在執行緒安全問題的,因為servlet容器為每一個客戶端請求都創建一個執行緒,這些執行緒在同一時刻可能訪問同一個servlet的service方法,所以我們在使用這些方法時務必小心,
12.如何創建執行緒安全的servlet?(SingleThreadModel方法不算)
- 盡量使用區域變數,減少全域變數的使用,
- 對于共享變數,加上關鍵字synchronized,
注:servlet中常見執行緒安全與不安全的物件
- 執行緒安全:ServletRequest,ServletResponse
- 執行緒不安全:ServletContext,HttpSession,
對于 ServletContext,我們應盡量減少該物件中屬性的修改,
而HttpSession物件在用戶會話期間存在,只能在處理屬于同一個Session的請求的執行緒中被訪問,因此Session物件的屬性訪問理論上是執行緒安全的,但是當用戶打開多個同屬于一個行程的瀏覽器視窗,在這些視窗的訪問屬于同一個Session,會出現多次請求,需要多個作業執行緒來處理請求,可能造成同時多執行緒讀寫屬性
13.是否有必要重寫service方法?
- 一般情況下是沒有必要的,因為service方法會根據請求的型別(get、post等)將請求分發給doxxx方法去執行,即使我們需要在處理請求之前需要做一些額外的事,我們也可以通過過濾器或監聽器完成,
14.servlet包裝類有什么用?
- servletAPI提供了兩個包裝類:HttpServletRequestWrapper類和HttpServletResponseWrapper類,這些包裝類幫助開發者給出request和response的一般實作,我們可以繼承它們并選擇我們需要復寫的方法進行復寫(包裝設計模式),而不用復寫所有的方法,
15.在servlet中能否產生類似死鎖情況?
- 可以的,你在doPost方法中呼叫doGet方法,在doGet方法中呼叫doPost方法,將產生死鎖(最侄訓拋出stackoverflow例外),
16.Servlet API中forward()與redirect()的區別?
- forward 是服務器轉發,一次請求和回應,瀏覽器地址欄不會顯示出轉發后的地址;forward比較高效,而且有助于隱藏實際地址,
- eg: getServletContext().getRequest Dispatcher(“/servlet/secondservlet”).forward(request, response);
- redirect 是重定向,兩次請求和回應,瀏覽器會得到跳轉地址,對新地址重新發送請求,
- eg: response.sendRedirect("http://www.baidu.com/");
17.ServletContext物件和ServletConfig物件的區別?
- 每個servlet都會有自己獨有的servletConfig物件而servletContext物件是整個web應用共享的,
- servletConfig提供servlet的初始化引數(init-param),僅該servlet可以訪問,而servletContext提供的初始化引數整個web應用的所有servlet都可以訪問,
- servletContext物件提供了setAttribute方法設定共享引數,而servletConfig并沒有對應的set方法,
18.PrintWriter和ServletOutPutStream類有什么區別?
- PrintWriter是字符流,ServletOutputStream是位元組流,可以通過 PrintWriter向瀏覽器輸出字符陣列或者是字串,也可以通過ServletOutPutStream向瀏覽器端輸出位元組陣列,
- PrintWriter物件在servlet中可以通過response.getWriter()方法獲取
- ServletOutputStream物件通過response.getOutputStream方法獲取,
19.在一個servlet能否同時獲取PrintWriter和ServletOutputStream物件?
- 不可以,如果同時獲取,將會拋出java.lang.IllegalStateException例外,
20.Request物件的主要方法有哪些?
- setAttribute(String name,Object):設定名字為name的request 的引數值
- getAttribute(String name):回傳由name指定的屬性值
- getAttributeNames():回傳request物件所有屬性的名字集合,結果是一個列舉的實體
- getCookies():回傳客戶端的所有Cookie物件,結果是一個Cookie陣列
- getCharacterEncoding():回傳請求中的字符編碼方式
- getContentLength():回傳請求的Body的長度
- getHeader(String name):獲得HTTP協議定義的檔案頭資訊
- getHeaders(String name):回傳指定名字的request Header的所有值,結果是一個列舉的實體
- getHeaderNames():回傳所以request Header的名字,結果是一個列舉的實體
- getInputStream():回傳請求的輸入流,用于獲得請求中的資料
- getMethod():獲得客戶端向服務器端傳送資料的方法
- getParameter(String name):獲得客戶端傳送給服務器端的有name指定的引數值
- getParameterNames():獲得客戶端傳送給服務器端的所有引數的名字,結果是一個列舉的實體
- getParametervalues(String name):獲得有name指定的引數的所有值
- getProtocol():獲取客戶端向服務器端傳送資料所依據的協議名稱
- getQueryString():獲得查詢字串
- getRequestURI():獲取發出請求字串的客戶端地址
- getRemoteAddr():獲取客戶端的IP 地址
- getRemoteHost():獲取客戶端的名字
- getSession([Boolean create]):回傳和請求相關Session
- getServerName():獲取服務器的名字
- getServletPath():獲取客戶端所請求的腳本檔案的路徑
- getServerPort():獲取服務器的埠號
- removeAttribute(String name):洗掉請求中的一個屬性
21.jsp和servlet的異同點以及聯系是什么?
-
jsp經編譯后就變成了servlet(jsp本質就是servlet,jvm只能識別java的類,不能識別jsp代碼,web容器將jsp的代碼編譯成jvm能夠識別的java類)
-
jsp更擅長表現于頁面顯示,servlet更擅長于邏輯控制
-
setvlet中沒有內置物件,jsp中的內置物件都是必須通過HttpServletRequest物件,HttpServletResponse物件及HttpServlet物件得到
-
jsp是servlet的一種簡化,使用jsp只需要完成程式員需用輸出到客戶端的內容,jsp中的java腳本如何鑲嵌到一個類中,由jsp容器完成,而servlet則是個完整的java類,這個類的service方法用于生成對客戶端的回應
資料庫階段
索引相關
1.什么是索引?
- 索引是一種資料結構,可以幫助我們快速的進行資料的查找
2.索引是個什么樣的資料結構呢?
- 索引的資料結構和具體存盤引擎的實作有關, 在MySQL中使用較多的索引有Hash索引,B+樹索引等,而我們經常使用的InnoDB存盤引擎的默認索引實作為:B+樹索引.
3.在建立索引的時候,都有哪些需要考慮的因素呢?
- 建立索引的時候一般要考慮到欄位的使用頻率,經常作為條件進行查詢的欄位比較適合.如果需要建立聯合索引的話,還需要考慮聯合索引中的順序.此外也要考慮其他方面,比如防止過多的所有對表造成太大的壓力.這些都和實際的表結構以及查詢方式有關.
4.關心過業務系統里面的sql耗時嗎?統計過慢查詢嗎?對慢查詢都怎么優化過?
在業務系統中,除了使用主鍵進行的查詢,其他的我都會在測驗庫上測驗其耗時,慢查詢的統計主要由運維在做,會定期將業務中的慢查詢反饋給我們.
慢查詢的優化首先要搞明白慢的原因是什么? 是查詢條件沒有命中索引?是load了不需要的資料列?還是資料量太大?
所以優化也是針對這三個方向來的,
-
首先分析陳述句,看看是否load了額外的資料,可能是查詢了多余的行并且拋棄掉了,可能是加載了許多結果中并不需要的列,對陳述句進行分析以及重寫.
-
分析陳述句的執行計劃,然后獲得其使用索引的情況,之后修改陳述句或者修改索引,使得陳述句可以盡可能的命中索引.
-
如果對陳述句的優化已經無法進行,可以考慮表中的資料量是否太大,如果是的話可以進行橫向或者縱向的分表.
5.區別B樹,B-,B+,B*?
- B樹:二叉樹,每個結點只存盤一個關鍵字,等于則命中,小于走左結點,大于走右結點;
- B-樹:多路搜索樹,每個結點存盤M/2到M個關鍵字,非葉子結點存盤指向關鍵字范圍的子結點; 所有關鍵字在整顆樹中出現,且只出現一次,非葉子結點可以命中;
- B+樹:在B-樹基礎上,為葉子結點增加鏈表指標,所有關鍵字都在葉子結點中出現,非葉子結點作為葉子結點的索引;B+樹總是到葉子結點才命中;
- B*樹:在B+樹基礎上,為非葉子結點也增加鏈表指標,將結點的最低利用率從1/2提高到2/3;
6.MySQL優化策略?
- 開啟查詢快取,優化查詢
- explain你的select查詢,這可以幫你分析你的查詢陳述句或是表結構的性能瓶頸,EXPLAIN 的查詢結果還會告訴你你的索引主鍵被如何利用的,你的資料表是如何被搜索和排序的
- 當只要一行資料時使用limit 1,MySQL資料庫引擎會在找到一條資料后停止搜索,而不是繼續往后查少下一條符合記錄的資料
- 為搜索欄位建索引
- 使用 ENUM 而不是 VARCHAR,如果你有一個欄位,比如“性別”,“國家”,“民族”,“狀態”或“部門”,你知道這些欄位的取值是有限而且固定的,那么,你應該使用 ENUM 而不是VARCHAR,
- Prepared StatementsPrepared Statements很像存盤程序,是一種運行在后臺的SQL陳述句集合,我們可以從使用 prepared statements 獲得很多好處,無論是性能問題還是安全問題,Prepared Statements 可以檢查一些你系結好的變數,這樣可以保護你的程式不會受到“SQL注入式”攻擊
- 垂直分表
- 選擇正確的存盤引擎
7.key和index的區別?
- key 是資料庫的物理結構,它包含兩層意義和作用,一是約束(偏重于約束和規范資料庫的結構完整性),二是索引(輔助查詢用的),包括primary key, unique key, foreign key 等
- index是資料庫的物理結構,它只是輔助查詢的,它創建時會在另外的表空間(mysql中的innodb表空間)以一個類似目錄的結構存盤,索引要分類的話,分為前綴索引、全文本索引等;
8.怎么驗證 mysql 的索引是否滿足需求?
- 使用 explain 查看 SQL 是如何執行查詢陳述句的,從而分析你的索引是否滿足需求,
- explain 語法:explain select * from table where type=1,
事務相關
1.ACID是什么?可以詳細說一下嗎?
- A=Atomicity
- 原子性,就是上面說的,要么全部成功,要么全部失敗.不可能只執行一部分操作.
- C=Consistency
- 系統(資料庫)總是從一個一致性的狀態轉移到另一個一致性的狀態,不會存在中間狀態.
- I=Isolation
- 隔離性: 通常來說:一個事務在完全提交之前,對其他事務是不可見的.注意前面的通常來說加了紅色,意味著有例外情況.
- D=Durability
- 持久性,一旦事務提交,那么就永遠是這樣子了,哪怕系統崩潰也不會影響到這個事務的結果.
2.同時有多個事務在進行會怎么樣呢?
多事務的并發進行一般會造成以下幾個問題:
-
臟讀: A事務讀取到了B事務未提交的內容,而B事務后面進行了回滾.
-
不可重復讀: 當設定A事務只能讀取B事務已經提交的部分,會造成在A事務內的兩次查詢,結果竟然不一樣,因為在此期間B事務進行了提交操作.
-
幻讀: A事務讀取了一個范圍的內容,而同時B事務在此期間插入了一條資料.造成"幻覺".
3.怎么解決這些問題呢?MySQL的事務隔離級別了解嗎?
MySQL的四種隔離級別如下:
- READ UNCOMMITTED(未提交讀)
-
- 這就是上面所說的例外情況了,這個隔離級別下,其他事務可以看到本事務沒有提交的部分修改.因此會造成臟讀的問題(讀取到了其他事務未提交的部分,而之后該事務進行了回滾).
- 這個級別的性能沒有足夠大的優勢,但是又有很多的問題,因此很少使用.
-
READ COMMITTED(已提交讀)
- 其他事務只能讀取到本事務已經提交的部分.這個隔離級別有 不可重復讀的問題,在同一個事務內的兩次讀取,拿到的結果竟然不一樣,因為另外一個事務對資料進行了修改.
-
REPEATABLE READ(可重復讀)
- 可重復讀隔離級別解決了上面不可重復讀的問題(看名字也知道),但是仍然有一個新問題,就是 幻讀,當你讀取id> 10 的資料行時,對涉及到的所有行加上了讀鎖,此時例外一個事務新插入了一條id=11的資料,因為是新插入的,所以不會觸發上面的鎖的排斥,那么進行本事務進行下一次的查詢時會發現有一條id=11的資料,而上次的查詢操作并沒有獲取到,再進行插入就會有主鍵沖突的問題.
-
SERIALIZABLE(可串行化)
- 這是最高的隔離級別,可以解決上面提到的所有問題,因為他強制將所以的操作串行執行,這會導致并發性能極速下降,因此也不是很常用.
4.Innodb使用的是哪種隔離級別呢?
- InnoDB默認使用的是可重復讀隔離級別.
5.對MySQL的鎖了解嗎?
- 當資料庫有并發事務的時候,可能會產生資料的不一致,這時候需要一些機制來保證訪問的次序,鎖機制就是這樣的一個機制.
6.MySQL都有哪些鎖呢?像上面那樣子進行鎖定豈不是有點阻礙并發效率了?
從鎖的類別上來講,有共享鎖和排他鎖.
-
共享鎖: 又叫做讀鎖. 當用戶要進行資料的讀取時,對資料加上共享鎖.共享鎖可以同時加上多個.
-
排他鎖: 又叫做寫鎖. 當用戶要進行資料的寫入時,對資料加上排他鎖.排他鎖只可以加一個,他和其他的排他鎖,共享鎖都相斥.
用上面的例子來說就是用戶的行為有兩種,一種是來看房,多個用戶一起看房是可以接受的. 一種是真正的入住一晚,在這期間,無論是想入住的還是想看房的都不可以.
鎖的粒度取決于具體的存盤引擎,InnoDB實作了行級鎖,頁級鎖,表級鎖.
他們的加鎖開銷從大到小,并發能力也是從大到小.
7.行級鎖定的優點缺點?
- 優點:
-
當在許多執行緒中訪問不同的行時只存在少量鎖定沖突,
-
回滾時只有少量的更改
-
可以長時間鎖定單一的行,
-
缺點:
-
-
比頁級或表級鎖定占用更多的記憶體,
-
當在表的大部分中使用時,比頁級或表級鎖定速度慢,因為你必須獲取更多的鎖,
-
如果你在大部分資料上經常進行GROUP BY操作或者必須經常掃描整個表,比其它鎖定明顯慢很多,
-
用高級別鎖定,通過支持不同的型別鎖定,你也可以很容易地調節應用程式,因為其鎖成本小于行級鎖定,
-
8.說一下 mysql 的行鎖和表鎖?
- MyISAM 只支持表鎖,InnoDB 支持表鎖和行鎖,默認為行鎖,
-
表級鎖:開銷小,加鎖快,不會出現死鎖,鎖定粒度大,發生鎖沖突的概率最高,并發量最低,
-
行級鎖:開銷大,加鎖慢,會出現死鎖,鎖力度小,發生鎖沖突的概率小,并發度最高,
-
表設計相關
1. 為什么要盡量設定一個主鍵?
- 主鍵是資料庫確保資料行在整張表唯一性的保障,即使業務上本張表沒有主鍵,也建議添加一個自增長的ID列作為主鍵.設定了主鍵之后,在后續的刪改查的時候可能更加快速以及確保操作資料范圍安全.
2.主鍵使用自增ID還是UUID?
- 推薦使用自增ID,不要使用UUID.
- 因為在InnoDB存盤引擎中,主鍵索引是作為聚簇索引存在的,也就是說,主鍵索引的B+樹葉子節點上存盤了主鍵索引以及全部的資料(按照順序),如果主鍵索引是自增ID,那么只需要不斷向后排列即可,如果是UUID,由于到來的ID與原來的大小不確定,會造成非常多的資料插入,資料移動,然后導致產生很多的記憶體碎片,進而造成插入性能的下降.
補充:
- 關于主鍵是聚簇索引,如果沒有主鍵,InnoDB會選擇一個唯一鍵來作為聚簇索引,如果沒有唯一鍵,會生成一個隱式的主鍵.
3. 欄位為什么要求定義為not null?
- null值會占用更多的位元組,且會在程式中造成很多與預期不符的情況.
4.varchar(10)和int(10)代表什么含義?
- varchar的10代表了申請的空間長度,也是可以存盤的資料的最大長度,而int的10只是代表了展示的長度,不足10位以0填充.也就是說,int(1)和int(10)所能存盤的數字大小以及占用的空間都是相同的,只是在展示時按照長度展示.
5.建表策略?
-
對于大資料欄位,獨立表進行存盤,以便提高性能(例如:簡介欄位);
-
使用varchar型別代替char,因為varchar會動態分配長度,char指定長度是固定的;
-
給表創建主鍵,對于沒有主鍵的表,在查詢和索引定義上有一定的影響;
-
避免表欄位運行為null,建議設定默認值(例如:int型別設定默認值為0)在索引查詢上,效率立顯;
-
建立索引,最好建立在唯一和非空的欄位上,建立太多的索引對后期插入、更新都存在一定的影響(考慮實際情況來創建);
存盤引擎相關
1. MySQL支持哪些存盤引擎?
- MySQL支持多種存盤引擎,比如InnoDB,MyISAM,Memory,Archive等等.在大多數的情況下,直接選擇使用InnoDB引擎都是最合適的,InnoDB也是MySQL的默認存盤引擎.
2.InnoDB和MyISAM有什么區別?
-
InnoDB支持事物,而MyISAM不支持事物
-
InnoDB支持行級鎖,而MyISAM支持表級鎖
-
InnoDB支持MVCC, 而MyISAM不支持
-
InnoDB支持外鍵,而MyISAM不支持
-
InnoDB不支持全文索引,而MyISAM支持,
3.什么是存盤程序?有哪些優缺點?
存盤程序是一些預編譯的SQL陳述句,1、更加直白的理解:存盤程序可以說是一個記錄集,它是由一些T-SQL陳述句組成的代碼塊,這些T-SQL陳述句代碼像一個方法一樣實作一些功能(對單表或多表的增刪改查),然后再給這個代碼塊取一個名字,在用到這個功能的時候呼叫他就行了,2、存盤程序是一個預編譯的代碼塊,執行效率比較高,一個存盤程序替代大量T_SQL陳述句 ,可以降低網路通信量,提高通信速率,可以一定程度上確保資料安全
但是,在互聯網專案中,其實是不太推薦存盤程序的,比較出名的就是阿里的《Java開發手冊》中禁止使用存盤程序,我個人的理解是,在互聯網專案中,迭代太快,專案的生命周期也比較短,人員流動相比于傳統的專案也更加頻繁,在這樣的情況下,存盤程序的管理確實是沒有那么方便,同時,復用性也沒有寫在服務層那么好.
4.說一說三個范式?
- 第一范式: 每個列都不可以再拆分.
- 第二范式: 非主鍵列完全依賴于主鍵,而不能是依賴于主鍵的一部分.
- 第三范式: 非主鍵列只依賴于主鍵,不依賴于其他非主鍵.
在設計資料庫結構的時候,要盡量遵守三范式,如果不遵守,必須有足夠的理由.比如性能. 事實上我們經常會為了性能而妥協資料庫的設計.
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/263634.html
標籤:Java
上一篇:JVM排查問題實戰
