阿里歷年經典Java面試題彙總,想進BAT你還不快收藏!

FrankYou發表於2018-05-15

轉載:https://mp.weixin.qq.com/s/M8YyxloxZnMACH9QCQN7HA

 

Volatile的特徵:

A、禁止指令重排(有例外) 
B、可見性

Volatile的記憶體語義:

當寫一個volatile變數時,JMM會把執行緒對應的本地記憶體中的共享變數值重新整理到主記憶體。

當讀一個volatile變數時,JMM會把執行緒對應的本地記憶體置為無效,執行緒接下來將從主記憶體中讀取共享變數。

Volatile的重排序

1、當第二個操作為volatile寫操做時,不管第一個操作是什麼(普通讀寫或者volatile讀寫),都不能進行重排序。這個規則確保volatile寫之前的所有操作都不會被重排序到volatile之後;

2、當第一個操作為volatile讀操作時,不管第二個操作是什麼,都不能進行重排序。這個規則確保volatile讀之後的所有操作都不會被重排序到volatile之前;

3、當第一個操作是volatile寫操作時,第二個操作是volatile讀操作,不能進行重排序。

這個規則和前面兩個規則一起構成了:兩個volatile變數操作不能夠進行重排序;

除以上三種情況以外可以進行重排序。

比如:

1、第一個操作是普通變數讀/寫,第二個是volatile變數的讀; 
2、第一個操作是volatile變數的寫,第二個是普通變數的讀/寫;


記憶體屏障/記憶體柵欄

記憶體屏障(Memory Barrier,或有時叫做記憶體柵欄,Memory Fence)是一種CPU指令,用於控制特定條件下的重排序和記憶體可見性問題。Java編譯器也會根據記憶體屏障的規則禁止重排序。(也就是讓一個CPU處理單元中的記憶體狀態對其它處理單元可見的一項技術。)

記憶體屏障可以被分為以下幾種型別:

LoadLoad屏障:對於這樣的語句Load1; LoadLoad; Load2,在Load2及後續讀取操作要讀取的資料被訪問前,保證Load1要讀取的資料被讀取完畢。

StoreStore屏障:對於這樣的語句Store1; StoreStore; Store2,在Store2及後續寫入操作執行前,保證Store1的寫入操作對其它處理器可見。

LoadStore屏障:對於這樣的語句Load1; LoadStore; Store2,在Store2及後續寫入操作被刷出前,保證Load1要讀取的資料被讀取完畢。

StoreLoad屏障:對於這樣的語句Store1; StoreLoad; Load2,在Load2及後續所有讀取操作執行前,保證Store1的寫入對所有處理器可見。它的開銷是四種屏障中最大的。

在大多數處理器的實現中,這個屏障是個萬能屏障,兼具其它三種記憶體屏障的功能。

記憶體屏障阻礙了CPU採用優化技術來降低記憶體操作延遲,必須考慮因此帶來的效能損失。為了達到最佳效能,最好是把要解決的問題模組化,這樣處理器可以按單元執行任務,然後在任務單元的邊界放上所有需要的記憶體屏障。採用這個方法可以讓處理器不受限的執行一個任務單元。合理的記憶體屏障組合還有一個好處是:緩衝區在第一次被刷後開銷會減少,因為再填充改緩衝區不需要額外工作了。


happens-before原則


Java是如何實現跨平臺的?

跨平臺是怎樣實現的呢?這就要談及Java虛擬機器(Java Virtual Machine,簡稱 JVM)。

JVM也是一個軟體,不同的平臺有不同的版本。我們編寫的Java原始碼,編譯後會生成一種 .class 檔案,稱為位元組碼檔案。Java虛擬機器就是負責將位元組碼檔案翻譯成特定平臺下的機器碼然後執行。也就是說,只要在不同平臺上安裝對應的JVM,就可以執行位元組碼檔案,執行我們編寫的Java程式。

而這個過程中,我們編寫的Java程式沒有做任何改變,僅僅是通過JVM這一”中間層“,就能在不同平臺上執行,真正實現了”一次編譯,到處執行“的目的。

JVM是一個”橋樑“,是一個”中介軟體“,是實現跨平臺的關鍵,Java程式碼首先被編譯成位元組碼檔案,再由JVM將位元組碼檔案翻譯成機器語言,從而達到執行Java程式的目的。

注意:編譯的結果不是生成機器碼,而是生成位元組碼,位元組碼不能直接執行,必須通過JVM翻譯成機器碼才能執行。不同平臺下編譯生成的位元組碼是一樣的,但是由JVM翻譯成的機器碼卻不一樣。

所以,執行Java程式必須有JVM的支援,因為編譯的結果不是機器碼,必須要經過JVM的再次翻譯才能執行。即使你將Java程式打包成可執行檔案(例如 .exe),仍然需要JVM的支援。

注意:跨平臺的是Java程式,不是JVM。JVM是用C/C++開發的,是編譯後的機器碼,不能跨平臺,不同平臺下需要安裝不同版本的JVM。


手機掃二維碼登入是怎麼實現的?

參考:http://www.jianshu.com/p/7f072ac61763


Java 執行緒有哪些狀態,這些狀態之間是如何轉化的?

 

  1. 新建(new):新建立了一個執行緒物件。

  2. 可執行(runnable):執行緒物件建立後,其他執行緒(比如main執行緒)呼叫了該物件的start()方法。該狀態的執行緒位於可執行執行緒池中,等待被執行緒排程選中,獲取cpu 的使用權 。

  3. 執行(running):可執行狀態(runnable)的執行緒獲得了cpu 時間片(timeslice) ,執行程式程式碼。

  4. 阻塞(block):阻塞狀態是指執行緒因為某種原因放棄了cpu 使用權,也即讓出了cpu timeslice,暫時停止執行。直到執行緒進入可執行(runnable)狀態,才有機會再次獲得cpu timeslice 轉到執行(running)狀態。阻塞的情況分三種:

(一). 等待阻塞:執行(running)的執行緒執行o.wait()方法,JVM會把該執行緒放入等待佇列(waitting queue)中。

(二). 同步阻塞:執行(running)的執行緒在獲取物件的同步鎖時,若該同步鎖被別的執行緒佔用,則JVM會把該執行緒放入鎖池(lock pool)中。

(三). 其他阻塞:執行(running)的執行緒執行Thread.sleep(long ms)或t.join()方法,或者發出了I/O請求時,JVM會把該執行緒置為阻塞狀態。當sleep()狀態超時、join()等待執行緒終止或者超時、或者I/O處理完畢時,執行緒重新轉入可執行(runnable)狀態。

  1. 死亡(dead):執行緒run()、main() 方法執行結束,或者因異常退出了run()方法,則該執行緒結束生命週期。死亡的執行緒不可再次復生。


List介面、Set介面和Map介面的區別

參考:

http://blog.csdn.net/zcg_java/article/details/43232251


Cookie和Session的區別?

參考:

http://blog.csdn.net/axin66ok/article/details/6175522


Java中的equals和hashCode方法詳解

參考:http://www.cnblogs.com/Qian123/p/5703507.html


Java中CAS演算法

參考:

http://www.kancloud.cn/seaboat/java-concurrent/117870


TimSort原理

參考:http://suo.im/532OHc


comparable與comparator的區別?

參考:http://www.cnblogs.com/szlbm/p/5504634.html


手寫單例模式(執行緒安全)

參考:http://www.cnblogs.com/hupp/p/4487521.html


Java執行緒間的通訊方式?

參考1:

http://www.cnblogs.com/mengdd/archive/2013/02/20/2917956.html

參考2:

http://www.jb51.net/article/84213.htm


Java8的記憶體分代改進

參考:

http://blog.csdn.net/chlu113/article/details/51890469


對Java記憶體模型的理解以及其在併發當中的作用?

參考:http://www.cnblogs.com/_popc/p/6096517.html


Arrays和Collections 對於sort的不同實現原理?

1、Arrays.sort() 
該演算法是一個經過調優的快速排序,此演算法在很多資料集上提供N*log(N)的效能,這導致其他快速排序會降低二次型效能。

2、Collections.sort() 
該演算法是一個經過修改的合併排序演算法(其中,如果低子列表中的最高元素效益高子列表中的最低元素,則忽略合併)。此演算法可提供保證的N*log(N)的效能,此實現將指定列表轉儲到一個陣列中,然後再對陣列進行排序,在重置陣列中相應位置處每個元素的列表上進行迭代。


Java中object常用方法

1、clone() 
2、equals() 
3、finalize() 
4、getclass() 
5、hashcode() 
6、notify() 
7、notifyAll() 
8、toString()


對於Java中多型的理解

所謂多型就是指程式中定義的引用變數所指向的具體型別和通過該引用變數發出的方法呼叫在程式設計時並不確定,而是在程式執行期間才確定,即一個引用變數到底會指向哪個類的例項物件,該引用變數發出的方法呼叫到底是哪個類中實現的方法,必須在由程式執行期間才能決定。

因為在程式執行時才確定具體的類,這樣,不用修改源程式程式碼,就可以讓引用變數繫結到各種不同的類實現上,從而導致該引用呼叫的具體方法隨之改變,即不修改程式程式碼就可以改變程式執行時所繫結的具體程式碼,讓程式可以選擇多個執行狀態,這就是多型性。

多型的定義:指允許不同類的物件對同一訊息做出響應。即同一訊息可以根據傳送物件的不同而採用多種不同的行為方式。(傳送訊息就是函式呼叫)

Java實現多型有三個必要條件:繼承、重寫、父類引用指向子類物件。

繼承:在多型中必須存在有繼承關係的子類和父類。

重寫:子類對父類中某些方法進行重新定義,在呼叫這些方法時就會呼叫子類的方法。

父類引用指向子類物件:在多型中需要將子類的引用賦給父類物件,只有這樣該引用才能夠具備技能呼叫父類的方法和子類的方法。

實現多型的技術稱為:動態繫結(dynamic binding),是指在執行期間判斷所引用物件的實際型別,根據其實際的型別呼叫其相應的方法。

多型的作用:消除型別之間的耦合關係。


Session機制?

參考 :http://justsee.iteye.com/blog/1570652


Java序列化與反序列化是什麼?為什麼需要序列化與反序列化?如何實現Java序列化與反序列化?

參考 :

http://blog.csdn.net/wangloveall/article/details/7992448/


Spring AOP 實現原理?

參考:

http://blog.csdn.net/moreevan/article/details/11977115/


Servlet 工作原理?

參考:

http://www.ibm.com/developerworks/cn/java/j-lo-servlet/


Java NIO和IO的區別?

參考:http://www.jb51.net/article/50621.htm


Java中堆記憶體和棧記憶體區別?

參考:

http://www.cnblogs.com/whgw/archive/2011/09/29/2194997.html


反射講一講,主要是概念,都在哪需要反射機制,反射的效能,如何優化?

反射機制的定義:

是在執行狀態中,對於任意的一個類,都能夠知道這個類的所有屬性和方法,對任意一個物件都能夠通過反射機制呼叫一個類的任意方法,這種動態獲取類資訊及動態呼叫類物件方法的功能稱為java的反射機制。

反射的作用:

1、動態地建立類的例項,將類繫結到現有的物件中,或從現有的物件中獲取型別。

2、應用程式需要在執行時從某個特定的程式集中載入一個特定的類。


如何保證RESTful API安全性 ?

參考:

http://blog.csdn.net/ywk253100/article/details/25654101


如何預防Mysql注入?

參考:http://www.jb51.net/article/87948.htm

相關文章