1. 程式人生 > >年終福利篇:2018Java面試題大集合。請查收

年終福利篇:2018Java面試題大集合。請查收

 

 

基礎篇

強引用,軟引用,弱引用,虛引用。不同的引用型別主要體現在GC上:

強引用:如果一個物件具有強引用,它就不會被垃圾回收器回收。即使當前記憶體空間不足,JVM也不會回收它,而是丟擲 OutOfMemoryError 錯誤,使程式異常終止。如果想中斷強引用和某個物件之間的關聯,可以顯式地將引用賦值為null,這樣一來的話,JVM在合適的時間就會回收該物件。

軟引用:在使用軟引用時,如果記憶體的空間足夠,軟引用就能繼續被使用,而不會被垃圾回收器回收,只有在記憶體不足時,軟引用才會被垃圾回收器回收。

弱引用:具有弱引用的物件擁有的生命週期更短暫。因為當 JVM 進行垃圾回收,一旦發現弱引用物件,無論當前記憶體空間是否充足,都會將弱引用回收。不過由於垃圾回收器是一個優先順序較低的執行緒,所以並不一定能迅速發現弱引用物件。

虛引用:顧名思義,就是形同虛設,如果一個物件僅持有虛引用,那麼它相當於沒有引用,在任何時候都可能被垃圾回收器回收。

Web篇

重定向和轉發的區別:

轉發在伺服器端完成的;重定向是在客戶端完成的

轉發的速度快;重定向速度慢

轉發的是同一次請求;重定向是兩次不同請求

轉發不會執行轉發後的程式碼;重定向會執行重定向之後的程式碼

轉發位址列沒有變化;重定向位址列有變化

轉發必須是在同一臺伺服器下完成;重定向可以在不同的伺服器下完成

jsp和servlet的區別和聯絡:

1.jsp經編譯後就變成了Servlet.

(JSP的本質就是Servlet,JVM只能識別java的類,不能識別JSP的程式碼,Web容器將JSP的程式碼編譯成JVM能夠識別的java類)

2.jsp更擅長表現於頁面顯示,servlet更擅長於邏輯控制.

3.Servlet中沒有內建物件,Jsp中的內建物件都是必須通過HttpServletRequest物件,HttpServletResponse物件以及HttpServlet物件得到.

Jsp是Servlet的一種簡化,使用Jsp只需要完成程式設計師需要輸出到客戶端的內容,Jsp中的Java指令碼如何鑲嵌到一個類中,由Jsp容器完成。

而Servlet則是個完整的Java類,這個類的Service方法用於生成對客戶端的響應。

聯絡:

JSP是Servlet技術的擴充套件,本質上就是Servlet的簡易方式。JSP編譯後是“類servlet”。

Servlet和JSP最主要的不同點在於:

Servlet的應用邏輯是在Java檔案中,並且完全從表示層中的HTML裡分離開來。

而JSP的情況是Java和HTML可以組合成一個副檔名為.jsp的檔案。

JSP側重於檢視,Servlet主要用於控制邏輯

Servlet更多的是類似於一個Controller,用來做控制。

多執行緒篇

1) 什麼是執行緒?

執行緒是作業系統能夠進行運算排程的最小單位,它被包含在程序之中,是程序中的實際運作單位。程式設計師可以通過它進行多處理器程式設計,你可以使用多執行緒對運算密集型任務提速。比如,如果一個執行緒完成一個任務要100毫秒,那麼用十個執行緒完成改任務只需10毫秒。Java在語言層面對多執行緒提供了卓越的支援,它也是一個很好的賣點。欲瞭解更多詳細資訊請點選這裡。

2) 執行緒和程序有什麼區別?

定義方面:程序是程式在某個資料集合上的一次執行活動;執行緒是程序中的一個執行路徑。(程序可以建立多個執行緒)

角色方面:在支援執行緒機制的系統中,程序是系統資源分配的單位,執行緒是CPU排程的單位。

資源共享方面:程序之間不能共享資源,而執行緒共享所在程序的地址空間和其它資源。同時執行緒還有自己的棧和棧指標,程式計數器等暫存器。

獨立性方面:程序有自己獨立的地址空間,而執行緒沒有,執行緒必須依賴於程序而存在。

開銷方面。程序切換的開銷較大。執行緒相對較小。(前面也提到過,引入執行緒也出於了開銷的考慮。)

3) 如何在Java中實現執行緒?

在語言層面有兩種方式。java.lang.Thread 類的例項就是一個執行緒但是它需要呼叫java.lang.Runnable介面來執行,由於執行緒類本身就是呼叫的Runnable介面所以你可以繼承java.lang.Thread 類或者直接呼叫Runnable介面來重寫run()方法實現執行緒。更多詳細資訊請點選這裡.

4) 用Runnable還是Thread?

這個問題是上題的後續,大家都知道我們可以通過繼承Thread類或者呼叫Runnable介面來實現執行緒,問題是,那個方法更好呢?什麼情況下使用它?這個問題很容易回答,如果你知道Java不支援類的多重繼承,但允許你呼叫多個介面。所以如果你要繼承其他類,當然是呼叫Runnable介面好了。更多詳細資訊請點選這裡。

6) Thread 類中的start() 和 run() 方法有什麼區別?

這個問題經常被問到,但還是能從此區分出面試者對Java執行緒模型的理解程度。start()方法被用來啟動新建立的執行緒,而且start()內部呼叫了run()方法,這和直接呼叫run()方法的效果不一樣。當你呼叫run()方法的時候,只會是在原來的執行緒中呼叫,沒有新的執行緒啟動,start()方法才會啟動新執行緒。更多討論請點選這裡

7) Java中Runnable和Callable有什麼不同?

Runnable和Callable都代表那些要在不同的執行緒中執行的任務。Runnable從JDK1.0開始就有了,Callable是在JDK1.5增加的。它們的主要區別是Callable的 call() 方法可以返回值和丟擲異常,而Runnable的run()方法沒有這些功能。Callable可以返回裝載有計算結果的Future物件。我的部落格有更詳細的說明。

8) Java中CyclicBarrier 和 CountDownLatch有什麼不同?

CyclicBarrier 和 CountDownLatch 都可以用來讓一組執行緒等待其它執行緒。與 CyclicBarrier 不同的是,CountdownLatch 不能重新使用。點此檢視更多資訊和示例程式碼。

9) Java記憶體模型是什麼?

Java記憶體模型規定和指引Java程式在不同的記憶體架構、CPU和作業系統間有確定性地行為。它在多執行緒的情況下尤其重要。Java記憶體模型對一個執行緒所做的變動能被其它執行緒可見提供了保證,它們之間是先行發生關係。這個關係定義了一些規則讓程式設計師在併發程式設計時思路更清晰。比如,先行發生關係確保了:

執行緒內的程式碼能夠按先後順序執行,這被稱為程式次序規則。

對於同一個鎖,一個解鎖操作一定要發生在時間上後發生的另一個鎖定操作之前,也叫做管程鎖定規則。

前一個對volatile的寫操作在後一個volatile的讀操作之前,也叫volatile變數規則。

一個執行緒內的任何操作必需在這個執行緒的start()呼叫之後,也叫作執行緒啟動規則。

一個執行緒的所有操作都會線上程終止之前,執行緒終止規則。

一個物件的終結操作必需在這個物件構造完成之後,也叫物件終結規則。

可傳遞性

我強烈建議大家閱讀《Java併發程式設計實踐》第十六章來加深對Java記憶體模型的理解。

10) Java中的volatile 變數是什麼?

volatile是一個特殊的修飾符,只有成員變數才能使用它。在Java併發程式缺少同步類的情況下,多執行緒對成員變數的操作對其它執行緒是透明的。volatile變數可以保證下一個讀取操作會在前一個寫操作之後發生,就是上一題的volatile變數規則。點選這裡檢視更多volatile的相關內容。

11) 什麼是執行緒安全?Vector是一個執行緒安全類嗎? (詳見這裡)

如果你的程式碼所在的程序中有多個執行緒在同時執行,而這些執行緒可能會同時執行這段程式碼。如果每次執行結果和單執行緒執行的結果是一樣的,而且其他的變數的值也和預期的是一樣的,就是執行緒安全的。一個執行緒安全的計數器類的同一個例項物件在被多個執行緒使用的情況下也不會出現計算失誤。很顯然你可以將集合類分成兩組,執行緒安全和非執行緒安全的。Vector 是用同步方法來實現執行緒安全的, 而和它相似的ArrayList不是執行緒安全的。

12) Java中什麼是競態條件? 舉個例子說明。

競態條件會導致程式在併發情況下出現一些bugs。多執行緒對一些資源的競爭的時候就會產生競態條件,如果首先要執行的程式競爭失敗排到後面執行了,那麼整個程式就會出現一些不確定的bugs。這種bugs很難發現而且會重複出現,因為執行緒間的隨機競爭。一個例子就是無序處理,詳見答案。

13) Java中如何停止一個執行緒?

Java提供了很豐富的API但沒有為停止執行緒提供API。JDK 1.0本來有一些像stop(), suspend() 和 resume()的控制方法但是由於潛在的死鎖威脅因此在後續的JDK版本中他們被棄用了,之後Java API的設計者就沒有提供一個相容且執行緒安全的方法來停止一個執行緒。當run() 或者 call() 方法執行完的時候執行緒會自動結束,如果要手動結束一個執行緒,你可以用volatile 布林變數來退出run()方法的迴圈或者是取消任務來中斷執行緒。點選這裡檢視示例程式碼。

14) 一個執行緒執行時發生異常會怎樣?

這是我在一次面試中遇到的一個很刁鑽的Java面試題, 簡單的說,如果異常沒有被捕獲該執行緒將會停止執行。Thread.UncaughtExceptionHandler是用於處理未捕獲異常造成執行緒突然中斷情況的一個內嵌介面。當一個未捕獲異常將造成執行緒中斷的時候JVM會使用Thread.getUncaughtExceptionHandler()來查詢執行緒的UncaughtExceptionHandler並將執行緒和異常作為引數傳遞給handler的uncaughtException()方法進行處理。

15) 如何在兩個執行緒間共享資料?

你可以通過共享物件來實現這個目的,或者是使用像阻塞佇列這樣併發的資料結構。這篇教程《Java執行緒間通訊》(涉及到在兩個執行緒間共享物件)用wait和notify方法實現了生產者消費者模型。

16) Java中notify 和 notifyAll有什麼區別?

這又是一個刁鑽的問題,因為多執行緒可以等待單監控鎖,Java API 的設計人員提供了一些方法當等待條件改變的時候通知它們,但是這些方法沒有完全實現。notify()方法不能喚醒某個具體的執行緒,所以只有一個執行緒在等待的時候它才有用武之地。而notifyAll()喚醒所有執行緒並允許他們爭奪鎖確保了至少有一個執行緒能繼續執行。我的部落格有更詳細的資料和示例程式碼。

17) 為什麼wait, notify 和 notifyAll這些方法不在thread類裡面?

這是個設計相關的問題,它考察的是面試者對現有系統和一些普遍存在但看起來不合理的事物的看法。回答這些問題的時候,你要說明為什麼把這些方法放在Object類裡是有意義的,還有不把它放在Thread類裡的原因。一個很明顯的原因是JAVA提供的鎖是物件級的而不是執行緒級的,每個物件都有鎖,通過執行緒獲得。如果執行緒需要等待某些鎖那麼呼叫物件中的wait()方法就有意義了。如果wait()方法定義在Thread類中,執行緒正在等待的是哪個鎖就不明顯了。簡單的說,由於wait,notify和notifyAll都是鎖級別的操作,所以把他們定義在Object類中因為鎖屬於物件。你也可以檢視這篇文章瞭解更多。

18) 什麼是ThreadLocal變數?

ThreadLocal是Java裡一種特殊的變數。每個執行緒都有一個ThreadLocal就是每個執行緒都擁有了自己獨立的一個變數,競爭條件被徹底消除了。它是為建立代價高昂的物件獲取執行緒安全的好方法,比如你可以用ThreadLocal讓SimpleDateFormat變成執行緒安全的,因為那個類建立代價高昂且每次呼叫都需要建立不同的例項所以不值得在區域性範圍使用它,如果為每個執行緒提供一個自己獨有的變數拷貝,將大大提高效率。首先,通過複用減少了代價高昂的物件的建立個數。其次,你在沒有使用高代價的同步或者不變性的情況下獲得了執行緒安全。執行緒區域性變數的另一個不錯的例子是ThreadLocalRandom類,它在多執行緒環境中減少了建立代價高昂的Random物件的個數。檢視答案瞭解更多。

19) 什麼是FutureTask?

在Java併發程式中FutureTask表示一個可以取消的非同步運算。它有啟動和取消運算、查詢運算是否完成和取回運算結果等方法。只有當運算完成的時候結果才能取回,如果運算尚未完成get方法將會阻塞。一個FutureTask物件可以對呼叫了Callable和Runnable的物件進行包裝,由於FutureTask也是呼叫了Runnable介面所以它可以提交給Executor來執行。

20) Java中interrupted 和 isInterruptedd方法的區別?

interrupted() 和 isInterrupted()的主要區別是前者會將中斷狀態清除而後者不會。Java多執行緒的中斷機制是用內部標識來實現的,呼叫Thread.interrupt()來中斷一個執行緒就會設定中斷標識為true。當中斷執行緒呼叫靜態方法Thread.interrupted()來檢查中斷狀態時,中斷狀態會被清零。而非靜態方法isInterrupted()用來查詢其它執行緒的中斷狀態且不會改變中斷狀態標識。簡單的說就是任何丟擲InterruptedException異常的方法都會將中斷狀態清零。無論如何,一個執行緒的中斷狀態有有可能被其它執行緒呼叫中斷來改變。

21) 為什麼wait和notify方法要在同步塊中呼叫?

主要是因為Java API強制要求這樣做,如果你不這麼做,你的程式碼會丟擲IllegalMonitorStateException異常。還有一個原因是為了避免wait和notify之間產生競態條件。

22) 為什麼你應該在迴圈中檢查等待條件?

處於等待狀態的執行緒可能會收到錯誤警報和偽喚醒,如果不在迴圈中檢查等待條件,程式就會在沒有滿足結束條件的情況下退出。因此,當一個等待執行緒醒來時,不能認為它原來的等待狀態仍然是有效的,在notify()方法呼叫之後和等待執行緒醒來之前這段時間它可能會改變。這就是在迴圈中使用wait()方法效果更好的原因,你可以在Eclipse中建立模板呼叫wait和notify試一試。如果你想了解更多關於這個問題的內容,我推薦你閱讀《Effective Java》這本書中的執行緒和同步章節。

23) Java中的同步集合與併發集合有什麼區別?

同步集合與併發集合都為多執行緒和併發提供了合適的執行緒安全的集合,不過併發集合的可擴充套件性更高。在Java1.5之前程式設計師們只有同步集合來用且在多執行緒併發的時候會導致爭用,阻礙了系統的擴充套件性。Java5介紹了併發集合像ConcurrentHashMap,不僅提供執行緒安全還用鎖分離和內部分割槽等現代技術提高了可擴充套件性。更多內容詳見答案。

24) Java中堆和棧有什麼不同?

為什麼把這個問題歸類在多執行緒和併發面試題裡?因為棧是一塊和執行緒緊密相關的記憶體區域。每個執行緒都有自己的棧記憶體,用於儲存本地變數,方法引數和棧呼叫,一個執行緒中儲存的變數對其它執行緒是不可見的。而堆是所有執行緒共享的一片公用記憶體區域。物件都在堆裡建立,為了提升效率執行緒會從堆中弄一個快取到自己的棧,如果多個執行緒使用該變數就可能引發問題,這時volatile 變數就可以發揮作用了,它要求執行緒從主存中讀取變數的值。 更多內容詳見答案。

25) 什麼是執行緒池? 為什麼要使用它?

建立執行緒要花費昂貴的資源和時間,如果任務來了才建立執行緒那麼響應時間會變長,而且一個程序能建立的執行緒數有限。為了避免這些問題,在程式啟動的時候就建立若干執行緒來響應處理,它們被稱為執行緒池,裡面的執行緒叫工作執行緒。從JDK1.5開始,Java API提供了Executor框架讓你可以建立不同的執行緒池。比如單執行緒池,每次處理一個任務;數目固定的執行緒池或者是快取執行緒池(一個適合很多生存期短的任務的程式的可擴充套件執行緒池)。更多內容詳見這篇文章。

26) 如何寫程式碼來解決生產者消費者問題?

在現實中你解決的許多執行緒問題都屬於生產者消費者模型,就是一個執行緒生產任務供其它執行緒進行消費,你必須知道怎麼進行執行緒間通訊來解決這個問題。比較低階的辦法是用wait和notify來解決這個問題,比較讚的辦法是用Semaphore 或者 BlockingQueue來實現生產者消費者模型,這篇教程有實現它。

27) 如何避免死鎖?

Java多執行緒中的死鎖 死鎖是指兩個或兩個以上的程序在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。這是一個嚴重的問題,因為死鎖會讓你的程式掛起無法完成任務,死鎖的發生必須滿足以下四個條件:

互斥條件:一個資源每次只能被一個程序使用。

請求與保持條件:一個程序因請求資源而阻塞時,對已獲得的資源保持不放。

不剝奪條件:程序已獲得的資源,在末使用完之前,不能強行剝奪。

迴圈等待條件:若干程序之間形成一種頭尾相接的迴圈等待資源關係。

避免死鎖最簡單的方法就是阻止迴圈等待條件,將系統中所有的資源設定標誌位、排序,規定所有的程序申請資源必須以一定的順序(升序或降序)做操作來避免死鎖。這篇教程有程式碼示例和避免死鎖的討論細節。

28) Java中活鎖和死鎖有什麼區別?

這是上題的擴充套件,活鎖和死鎖類似,不同之處在於處於活鎖的執行緒或程序的狀態是不斷改變的,活鎖可以認為是一種特殊的飢餓。一個現實的活鎖例子是兩個人在狹小的走廊碰到,兩個人都試著避讓對方好讓彼此通過,但是因為避讓的方向都一樣導致最後誰都不能通過走廊。簡單的說就是,活鎖和死鎖的主要區別是前者程序的狀態可以改變但是卻不能繼續執行。

29) 怎麼檢測一個執行緒是否擁有鎖?

我一直不知道我們竟然可以檢測一個執行緒是否擁有鎖,直到我參加了一次電話面試。在java.lang.Thread中有一個方法叫holdsLock(),它返回true如果當且僅當當前執行緒擁有某個具體物件的鎖。你可以檢視這篇文章瞭解更多。

30) 你如何在Java中獲取執行緒堆疊?

對於不同的作業系統,有多種方法來獲得Java程序的執行緒堆疊。當你獲取執行緒堆疊時,JVM會把所有執行緒的狀態存到日誌檔案或者輸出到控制檯。在Windows你可以使用Ctrl + Break組合鍵來獲取執行緒堆疊,Linux下用kill -3命令。你也可以用jstack這個工具來獲取,它對執行緒id進行操作,你可以用jps這個工具找到id。

31) JVM中哪個引數是用來控制執行緒的棧堆疊小的

這個問題很簡單, -Xss引數用來控制執行緒的堆疊大小。你可以檢視JVM配置列表來了解這個引數的更多資訊。

32) Java中synchronized 和 ReentrantLock 有什麼不同?

Java在過去很長一段時間只能通過synchronized關鍵字來實現互斥,它有一些缺點。比如你不能擴充套件鎖之外的方法或者塊邊界,嘗試獲取鎖時不能中途取消等。Java 5 通過Lock介面提供了更復雜的控制來解決這些問題。 ReentrantLock 類實現了 Lock,它擁有與 synchronized 相同的併發性和記憶體語義且它還具有可擴充套件性。你可以檢視這篇文章瞭解更多

33) 有三個執行緒T1,T2,T3,怎麼確保它們按順序執行?

在多執行緒中有多種方法讓執行緒按特定順序執行,你可以用執行緒類的join()方法在一個執行緒中啟動另一個執行緒,另外一個執行緒完成該執行緒繼續執行。為了確保三個執行緒的順序你應該先啟動最後一個(T3呼叫T2,T2呼叫T1),這樣T1就會先完成而T3最後完成。你可以檢視這篇文章瞭解更多。

34) Thread類中的yield方法有什麼作用?

Yield方法可以暫停當前正在執行的執行緒物件,讓其它有相同優先順序的執行緒執行。它是一個靜態方法而且只保證當前執行緒放棄CPU佔用而不能保證使其它執行緒一定能佔用CPU,執行yield()的執行緒有可能在進入到暫停狀態後馬上又被執行。點選這裡檢視更多yield方法的相關內容。

35) Java中ConcurrentHashMap的併發度是什麼?

ConcurrentHashMap把實際map劃分成若干部分來實現它的可擴充套件性和執行緒安全。這種劃分是使用併發度獲得的,它是ConcurrentHashMap類建構函式的一個可選引數,預設值為16,這樣在多執行緒情況下就能避免爭用。欲瞭解更多併發度和內部大小調整請閱讀我的文章How ConcurrentHashMap works in Java。

36) Java中Semaphore是什麼?

Java中的Semaphore是一種新的同步類,它是一個計數訊號。從概念上講,從概念上講,訊號量維護了一個許可集合。如有必要,在許可可用前會阻塞每一個 acquire(),然後再獲取該許可。每個 release()新增一個許可,從而可能釋放一個正在阻塞的獲取者。但是,不使用實際的許可物件,Semaphore只對可用許可的號碼進行計數,並採取相應的行動。訊號量常常用於多執行緒的程式碼中,比如資料庫連線池。更多詳細資訊請點選這裡。

37)如果你提交任務時,執行緒池佇列已滿。會時發會生什麼?

這個問題問得很狡猾,許多程式設計師會認為該任務會阻塞直到執行緒池佇列有空位。事實上如果一個任務不能被排程執行那麼ThreadPoolExecutor’s submit()方法將會丟擲一個RejectedExecutionException異常。

38) Java執行緒池中submit() 和 execute()方法有什麼區別?

兩個方法都可以向執行緒池提交任務,execute()方法的返回型別是void,它定義在Executor介面中, 而submit()方法可以返回持有計算結果的Future物件,它定義在ExecutorService介面中,它擴充套件了Executor介面,其它執行緒池類像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有這些方法。更多詳細資訊請點選這裡。

39) 什麼是阻塞式方法?

阻塞式方法是指程式會一直等待該方法完成期間不做其他事情,ServerSocket的accept()方法就是一直等待客戶端連線。這裡的阻塞是指呼叫結果返回之前,當前執行緒會被掛起,直到得到結果之後才會返回。此外,還有非同步和非阻塞式方法在任務完成前就返回。更多詳細資訊請點選這裡。

40) Swing是執行緒安全的嗎? 為什麼?

你可以很肯定的給出回答,Swing不是執行緒安全的,但是你應該解釋這麼回答的原因即便面試官沒有問你為什麼。當我們說swing不是執行緒安全的常常提到它的元件,這些元件不能在多執行緒中進行修改,所有對GUI元件的更新都要在AWT執行緒中完成,而Swing提供了同步和非同步兩種回撥方法來進行更新。點選這裡檢視更多swing和執行緒安全的相關內容。

41) Java中invokeAndWait 和 invokeLater有什麼區別?

這兩個方法是Swing API 提供給Java開發者用來從當前執行緒而不是事件派發執行緒更新GUI元件用的。InvokeAndWait()同步更新GUI元件,比如一個進度條,一旦進度更新了,進度條也要做出相應改變。如果進度被多個執行緒跟蹤,那麼就呼叫invokeAndWait()方法請求事件派發執行緒對元件進行相應更新。而invokeLater()方法是非同步呼叫更新元件的。更多詳細資訊請點選這裡。

42) Swing API中那些方法是執行緒安全的?

這個問題又提到了swing和執行緒安全,雖然元件不是執行緒安全的但是有一些方法是可以被多執行緒安全呼叫的,比如repaint(), revalidate()。 JTextComponent的setText()方法和JTextArea的insert() 和 append() 方法也是執行緒安全的。

43) 如何在Java中建立Immutable物件?

這個問題看起來和多執行緒沒什麼關係, 但不變性有助於簡化已經很複雜的併發程式。Immutable物件可以在沒有同步的情況下共享,降低了對該物件進行併發訪問時的同步化開銷。可是Java沒有@Immutable這個註解符,要建立不可變類,要實現下面幾個步驟:通過構造方法初始化所有成員、對變數不要提供setter方法、將所有的成員宣告為私有的,這樣就不允許直接訪問這些成員、在getter方法中,不要直接返回物件本身,而是克隆物件,並返回物件的拷貝。我的文章how to make an object Immutable in Java有詳細的教程,看完你可以充滿自信。

44) Java中的ReadWriteLock是什麼?

一般而言,讀寫鎖是用來提升併發程式效能的鎖分離技術的成果。Java中的ReadWriteLock是Java 5 中新增的一個介面,一個ReadWriteLock維護一對關聯的鎖,一個用於只讀操作一個用於寫。在沒有寫執行緒的情況下一個讀鎖可能會同時被多個讀執行緒持有。寫鎖是獨佔的,你可以使用JDK中的ReentrantReadWriteLock來實現這個規則,它最多支援65535個寫鎖和65535個讀鎖。

45) 多執行緒中的忙迴圈是什麼?

忙迴圈就是程式設計師用迴圈讓一個執行緒等待,不像傳統方法wait(), sleep() 或 yield() 它們都放棄了CPU控制,而忙迴圈不會放棄CPU,它就是在執行一個空迴圈。這麼做的目的是為了保留CPU快取,在多核系統中,一個等待執行緒醒來的時候可能會在另一個核心執行,這樣會重建快取。為了避免重建快取和減少等待重建的時間就可以使用它了。你可以檢視這篇文章獲得更多資訊。

46)volatile 變數和 atomic 變數有什麼不同?

這是個有趣的問題。首先,volatile 變數和 atomic 變數看起來很像,但功能卻不一樣。Volatile變數可以確保先行關係,即寫操作會發生在後續的讀操作之前, 但它並不能保證原子性。例如用volatile修飾count變數那麼 count++ 操作就不是原子性的。而AtomicInteger類提供的atomic方法可以讓這種操作具有原子性如getAndIncrement()方法會原子性的進行增量操作把當前值加一,其它資料型別和引用變數也可以進行相似操作。

47) 如果同步塊內的執行緒丟擲異常會發生什麼?

這個問題坑了很多Java程式設計師,若你能想到鎖是否釋放這條線索來回答還有點希望答對。無論你的同步塊是正常還是異常退出的,裡面的執行緒都會釋放鎖,所以對比鎖介面我更喜歡同步塊,因為它不用我花費精力去釋放鎖,該功能可以在finally block裡釋放鎖實現。

48) 單例模式的雙檢鎖是什麼?

這個問題在Java面試中經常被問到,但是面試官對回答此問題的滿意度僅為50%。一半的人寫不出雙檢鎖還有一半的人說不出它的隱患和Java1.5是如何對它修正的。它其實是一個用來建立執行緒安全的單例的老方法,當單例例項第一次被建立時它試圖用單個鎖進行效能優化,但是由於太過於複雜在JDK1.4中它是失敗的,我個人也不喜歡它。無論如何,即便你也不喜歡它但是還是要了解一下,因為它經常被問到。你可以檢視how double checked locking on Singleton works這篇文章獲得更多資訊。

49) 如何在Java中建立執行緒安全的Singleton?

這是上面那個問題的後續,如果你不喜歡雙檢鎖而面試官問了建立Singleton類的替代方法,你可以利用JVM的類載入和靜態變數初始化特徵來建立Singleton例項,或者是利用列舉型別來建立Singleton,我很喜歡用這種方法。你可以檢視這篇文章獲得更多資訊。

50) 寫出3條你遵循的多執行緒最佳實踐

這種問題我最喜歡了,我相信你在寫併發程式碼來提升效能的時候也會遵循某些最佳實踐。以下三條最佳實踐我覺得大多數Java程式設計師都應該遵循:

給你的執行緒起個有意義的名字。 這樣可以方便找bug或追蹤。OrderProcessor, QuoteProcessor or TradeProcessor 這種名字比 Thread-1. Thread-2 and Thread-3 好多了,給執行緒起一個和它要完成的任務相關的名字,所有的主要框架甚至JDK都遵循這個最佳實踐。

避免鎖定和縮小同步的範圍 鎖花費的代價高昂且上下文切換更耗費時間空間,試試最低限度的使用同步和鎖,縮小臨界區。因此相對於同步方法我更喜歡同步塊,它給我擁有對鎖的絕對控制權。

多用同步類少用wait 和 notify 首先,CountDownLatch, Semaphore, CyclicBarrier 和 Exchanger 這些同步類簡化了編碼操作,而用wait和notify很難實現對複雜控制流的控制。其次,這些類是由最好的企業編寫和維護在後續的JDK中它們還會不斷優化和完善,使用這些更高等級的同步工具你的程式可以不費吹灰之力獲得優化。

多用併發集合少用同步集合 這是另外一個容易遵循且受益巨大的最佳實踐,併發集合比同步集合的可擴充套件性更好,所以在併發程式設計時使用併發集合效果更好。如果下一次你需要用到map,你應該首先想到用ConcurrentHashMap。我的文章Java併發集合有更詳細的說明。

51) 如何強制啟動一個執行緒?

這個問題就像是如何強制進行Java垃圾回收,目前還沒有覺得方法,雖然你可以使用System.gc()來進行垃圾回收,但是不保證能成功。在Java裡面沒有辦法強制啟動一個執行緒,它是被執行緒排程器控制著且Java沒有公佈相關的API。

52) Java中的fork join框架是什麼?

fork join框架是JDK7中出現的一款高效的工具,Java開發人員可以通過它充分利用現代伺服器上的多處理器。它是專門為了那些可以遞迴劃分成許多子模組設計的,目的是將所有可用的處理能力用來提升程式的效能。fork join框架一個巨大的優勢是它使用了工作竊取演算法,可以完成更多工的工作執行緒可以從其它執行緒中竊取任務來執行。你可以檢視這篇文章獲得更多資訊。

53) Java多執行緒中呼叫wait() 和 sleep()方法有什麼不同?

Java程式中wait 和 sleep都會造成某種形式的暫停,它們可以滿足不同的需要。wait()方法用於執行緒間通訊,如果等待條件為真且其它執行緒被喚醒時它會釋放鎖,而sleep()方法僅僅釋放CPU資源或者讓當前執行緒停止執行一段時間,但不會釋放鎖。

集合篇

在迭代一個集合的時候,如何避免ConcurrentModificationException?

在遍歷一個集合的時候,我們可以使用併發集合類來避免ConcurrentModificationException,比如使用CopyOnWriteArrayList,而不是ArrayList。

fail-fast與fail-safe有什麼區別?

每次我們嘗試獲取下一個元素的時候,Iterator fail-fast屬性檢查當前集合結構裡的任何改動。如果發現任何改動,它丟擲ConcurrentModificationException。Collection中所有Iterator的實現都是按fail-fast來設計的(ConcurrentHashMap和CopyOnWriteArrayList這類併發集合類除外)。

Iterater和ListIterator之間有什麼區別?

(1)我們可以使用Iterator來遍歷Set和List集合,而ListIterator只能遍歷List。

(2)Iterator只可以向前遍歷,而LIstIterator可以雙向遍歷。

(3)ListIterator從Iterator介面繼承,然後添加了一些額外的功能,比如新增一個元素、替換一個元素、獲取前面或後面元素的索引位置。

HashSet和TreeSet有什麼區別?

HashSet是由一個雜湊表來實現的,元素無,add(),remove(),contains()方法的時間複雜度是O(1)。

另一方面,TreeSet是由一個樹形結構(平衡二叉排序樹)來實現的,它裡面的元素是有序的。因此,add(),remove(),contains()方法的時間複雜度是O(logn)。

Enumeration介面和Iterator介面的區別有哪些?

Enumeration速度是Iterator的2倍,同時佔用更少的記憶體。

但是,Iterator遠遠比Enumeration安全,因為其他執行緒不能夠修改正在被iterator遍歷的集合裡面的物件。同時,Iterator允許呼叫者刪除底層集合裡面的元素,這對Enumeration來說是不可能的。

ArrayList和LinkedList有什麼區別?

兩者都實現了List介面,他們有以下不同點:

資料結構上:

ArrayList是基於索引的陣列形式,可隨機訪問元素, 時間複雜度O(1);

LinkedList是元素列表的形式儲存它的資料,每一個元素都和它的前一個和後一個元素連結在一起,在這種情況下,查詢某個元素的時間複雜度是O(n)。

操作上:

ArrayList新增,刪除操作比較慢,重新計算大小或者是更新索引。

LinkedList的插入,新增,刪除操作速度更快,不需要更新索引。

記憶體上:

LinkedList比ArrayList更佔記憶體,因為LinkedList為每一個節點儲存了兩個引用,一個指向前一個元素,一個指向下一個元素。

Collection 和 Collections的區別:

Collections是個java.util下的類,是針對集合類的一個工具類,提供一系列靜態方法,實現對集合的查詢、排序、替換、執行緒安全化(將非同步的集合轉換成同步的)等操作。

Collection是個java.util下的介面,它是各種集合結構的父介面,繼承於它的介面主要有Set和List,提供了關於集合的一些操作,如插入、刪除、判斷一個元素是否其成員、遍歷等。

Map介面

|–Hashtable:底層是雜湊散列表資料結構,執行緒同步。不可以儲存null鍵,null值。不可序列化,使用bucket結構體表示單個元素,使用雙重雜湊法(閉雜湊法)解決衝突(二度雜湊,size>length時要進行模運算)。

|–HashMap:底層是雜湊表資料結構(鏈地址法解決衝突),執行緒不同步。可存一個null鍵和多個null值。替代了Hashtable. 但可通過Map m = Collections.synchronizeMap(hashMap)實現同步;

|–LinkedHashMap,採用雙向連結串列資料結構連線起來所有的entry,保證了存入和取出順序一致,即連結串列有序;執行緒不同步。

|–TreeMap:底層是二叉樹結構(平衡二叉排序樹),可以對map集合中的鍵進行指定順序的排序

TreeSet集合排序有兩種方式,Comparable和Comparator區別:

1:讓元素自身具備比較性,需要元素物件實現Comparable介面,覆蓋compareTo方法。

2:讓集合自身具備比較性,需要定義一個實現了Comparator介面的比較器,並覆蓋compare方法,並將該類物件作為實際引數傳遞給TreeSet集合的建構函式。第二種方式較為靈活。

ArrayList,LinkedList,Vector的區別

List:有序(元素存入集合的順序和取出的順序一致)元素都有索引。元素可以重複。(有序可重複)

|–ArrayList:底層的資料結構是陣列,執行緒不同步,ArrayList替代了Vector,查詢元素的速度非常快。預設大小10,1.5倍長度擴容。

|–LinkedList:底層的資料結構是連結串列,執行緒不同步,增刪元素的速度非常快。

|–Vector:底層的資料結構就是陣列,執行緒同步,Vector無論查詢和增刪都巨慢。預設大 小10,2倍長度擴容

集合和陣列的區別:

1:陣列是固定長度的;集合可變長度的。

2:陣列可以儲存基本資料型別,也可以儲存引用資料型別;集合只能儲存引用資料型別。

3:陣列儲存的元素必須是同一個資料型別;集合儲存的物件可以是不同資料型別。

ArrayList 和 LinkedList 有什麼區別。

ArrayList和LinkedList都實現了List介面,有以下的不同點:

1、ArrayList是基於索引的資料介面,它的底層是陣列。它可以以O(1)時間複雜度對元素進行隨機訪問。與此對應,LinkedList是以元素列表的形式儲存它的資料,每一個元素都和它的前一個和後一個元素連結在一起,在這種情況下,查詢某個元素的時間複雜度是O(n)。

2、相對於ArrayList,LinkedList的插入,新增,刪除操作速度更快,因為當元素被新增到集合任意位置的時候,不需要像陣列那樣重新計算大小或者是更新索引。

3、LinkedList比ArrayList更佔記憶體,因為LinkedList為每一個節點儲存了兩個引用,一個指向前一個元素,一個指向下一個元素

多執行緒篇

透徹理解 Java synchronized 物件鎖和類鎖的區別

Hibernate

1、什麼是Hibernate的併發機制?怎麼去處理併發問題?

Hibernate併發機制:

a、Hibernate的Session物件是非執行緒安全的,對於單個請求,單個會話,單個的工作單元(即單個事務,單個執行緒),它通常只使用一次, 然後就丟棄。

如果一個Session 例項允許共享的話,那些支援併發執行的,例如Http request,session beans將會導致出現資源爭用。

如果在Http Session中有hibernate的Session的話,就可能會出現同步訪問Http Session。只要使用者足夠快的點選瀏覽器的“重新整理”, 就會導致兩個併發執行的執行緒使用同一個Session。

b、多個事務併發訪問同一塊資源,可能會引發第一類丟失更新,髒讀,幻讀,不可重複讀,第二類丟失更新一系列的問題。

解決方案:設定事務隔離級別。

Serializable:序列化。隔離級別最高

Repeatable Read:可重複讀

Read Committed:已提交資料讀

Read Uncommitted:未提交資料讀。隔離級別最差

設定鎖:樂觀鎖和悲觀鎖。

樂觀鎖:使用版本號或時間戳來檢測更新丟失,在的對映中設定 optimistic-lock=”all”可以在沒有版本或者時間戳屬性對映的情況下實現 版本檢查,此時Hibernate將比較一行記錄的每個欄位的狀態 行級悲觀鎖:Hibernate總是使用資料庫的鎖定機制,從不在記憶體中鎖定物件!只要為JDBC連線指定一下隔 離級別,然後讓資料庫去搞定一切就夠了。類LockMode 定義了Hibernate所需的不同的鎖定級別:LockMode.UPGRADE,LockMode.UPGRADE_NOWAIT,LockMode.READ;

2、update和saveOrUpdate的區別?

update()和saveOrUpdate()是用來對跨Session的PO進行狀態管理的。

update()方法操作的物件必須是持久化了的物件。也就是說,如果此物件在資料庫中不存在的話,就不能使用update()方法。

saveOrUpdate()方法操作的物件既可以使持久化了的,也可以使沒有持久化的物件。如果是持久化了的物件呼叫saveOrUpdate()則會 更新資料庫中的物件;如果是未持久化的物件使用此方法,則save到資料庫中。

3、hibernate的三種狀態之間如何轉換

當物件由瞬時狀態(Transient)一save()時,就變成了持久化狀態;

當我們在Session裡儲存物件的時候,實際是在Session的Map裡存了一份, 也就是它的快取裡放了一份,然後,又到資料庫裡存了一份,在快取裡這一份叫持久物件(Persistent)。 Session 一 Close()了,它的快取也都關閉了,整個Session也就失效了,這個時候,這個物件變成了遊離狀態(Detached),但資料庫中還是存在的。

當遊離狀態(Detached)update()時,又變為了持久狀態(Persistent)。

當持久狀態(Persistent)delete()時,又變為了瞬時狀態(Transient), 此時,資料庫中沒有與之對應的記錄。

4、比較hibernate的三種檢索策略優缺點

1立即檢索;

優點: 對應用程式完全透明,不管物件處於持久化狀態,還是遊離狀態,應用程式都可以方便的從一個物件導航到與它關聯的物件;

缺點: 1.select語句太多;2.可能會載入應用程式不需要訪問的物件白白浪費許多記憶體空間;

2延遲檢索:

優點: 由應用程式決定需要載入哪些物件,可以避免可執行多餘的select語句,以及避免載入應用程式不需要訪問的物件。因此能提高檢索效能,並且能節省記憶體空間;

缺點: 應用程式如果希望訪問遊離狀態代理類例項,必須保證他在持久化狀態時已經被初始化;

3 迫切左外連線檢索

優點: 1對應用程式完全透明,不管物件處於持久化狀態,還是遊離狀態,應用程式都可以方便地衝一個物件導航到與它關聯的物件。2使用了外連線,select語句數目少;

缺點: 1 可能會載入應用程式不需要訪問的物件,白白浪費許多記憶體空間;2複雜的資料庫表連線也會影響檢索效能;

5、如何在控制檯看到hibernate生成並執行的sql

在定義資料庫和資料庫屬性的檔案applicationConfig.xml裡面,把hibernate.show_sql 設定為true

這樣生成的SQL就會在控制檯出現了

注意:這樣做會加重系統的負擔,不利於效能調優

6、hibernate都支援哪些快取策略

Read-only: 這種策略適用於那些頻繁讀取卻不會更新的資料,這是目前為止最簡單和最有效的快取策略

Read/write:這種策略適用於需要被更新的資料,比read-only更耗費資源,在非JTA環境下,每個事務需要在session.close和session.disconnect()被呼叫

Nonstrict read/write: 這種策略不保障兩個同時進行的事務會修改同一塊資料,這種策略適用於那些經常讀取但是極少更新的資料

Transactional: 這種策略是完全事務化得快取策略,可以用在JTA環境下

7、hibernate裡面的sorted collection 和ordered collection有什麼區別

sorted collection是在記憶體中通過Java比較器進行排序的

ordered collection是在資料庫中通過order by進行排序的

8、Hibernate工作原理及為什麼要用?

1.讀取並解析配置檔案

2.讀取並解析對映資訊,建立SessionFactory

3.開啟Sesssion

4.建立事務Transation

5.持久化操作

6.提交事務

7.關閉Session

8.關閉SesstionFactory

為什麼要用:

對JDBC訪問資料庫的程式碼做了封裝,大大簡化了資料訪問層繁瑣的重複性程式碼。

Hibernate是一個基於JDBC的主流持久化框架,是一個優秀的ORM實現。他很大程度的簡化DAO層的編碼工作

hibernate使用Java反射機制,而不是位元組碼增強程式來實現透明性。

hibernate的效能非常好,因為它是個輕量級框架。對映的靈活性很出色。它支援各種關係資料庫,從一對一到多對多的各種複雜關係。

10、Hibernate是如何延遲載入?

當Hibernate在查詢資料的時候,資料並沒有存在與記憶體中,當程式真正對資料的操作時,物件才存在與記憶體中,就實現了延遲載入,他節省了伺服器的記憶體開銷,從而提高了伺服器的效能。

11、Hibernate中怎樣實現類之間的關係?(如:一對多、多對多的關係)

類與類之間的關係主要體現在表與表之間的關係進行操作,它們都是對物件進行操作,我們程式中把所有的表與類都對映在一起,它們通過配置檔案中的many-to-one、one-to-many、many-to-many、

12、說下Hibernate的快取機制

內部快取存在Hibernate中又叫一級快取,屬於應用事物級快取

二級快取:

a) 應用及快取

b) 分散式快取

條件:資料不會被第三方修改、資料大小在可接受範圍、資料更新頻率低、同一資料被系統頻繁使用、非關鍵資料

c) 第三方快取的實現

13、Hibernate的查詢方式

Sql、Criteria,objectcomposition

Hql:

1、 屬性查詢

2、 引數查詢、命名引數查詢

3、 關聯查詢

4、 分頁查詢

5、 統計函式

14、如何優化Hibernate?

1.使用雙向一對多關聯,不使用單向一對多

2.靈活使用單向一對多關聯

3.不用一對一,用多對一取代

4.配置物件快取,不使用集合快取

5.一對多集合使用Bag,多對多集合使用Set

繼承類使用顯式多型

表字段要少,表關聯不要怕多,有二級快取撐腰

15、Hibernate有哪幾種查詢資料的方式

3種:hql、條件查詢QBC(QueryBy Criteria)、原生sql (通過createSQLQuery建立)

16、談談Hibernate中inverse的作用

inverse屬性預設是false,就是說關係的兩端都來維護關係。

比如Student和Teacher是多對多關係,用一箇中間表TeacherStudent維護。Gp)i

如果Student這邊inverse=”true”, 那麼關係由另一端Teacher維護,就是說當插入Student時,不會操作TeacherStudent表(中間表)。只有Teacher插入或刪除時才會觸發對中間表的操作。所以兩邊都inverse=”true”是不對的,會導致任何操作都不觸發對中間表的影響;當兩邊都inverse=”false”或預設時,會導致在中間表中插入兩次關係。

17、Detached Object(遊離物件)有什麼好處

Detached Object(遊離物件)可以傳遞到任何層直到表現層而不是用任何DTO(DataTransfer Objects). 然後你還可以重新把遊離物件賦給另外一個Session.

18、JDBC hibernate 和 ibatis 的區別

jdbc:手動

手動寫sql

delete、insert、update要將物件的值一個一個取出傳到sql中,不能直接傳入一個物件。

select:返回的是一個resultset,要從ResultSet中一行一行、一個欄位一個欄位的取出,然後封裝到一個物件中,不直接返回一個物件。

ibatis的特點:半自動化

sql要手動寫

delete、insert、update:直接傳入一個物件

select:直接返回一個物件

hibernate:全自動

不寫sql,自動封裝

delete、insert、update:直接傳入一個物件

select:直接返回一個物件

19、在資料庫中條件查詢速度很慢的時候,如何優化?

1.建索引

2.減少表之間的關聯

3.優化sql,儘量讓sql很快定位資料,不要讓sql做全表查詢,應該走索引,把資料量大的表排在前面

4.簡化查詢欄位,沒用的欄位不要,已經對返回結果的控制,儘量返回少量資料

20、什麼是SessionFactory,她是執行緒安全麼?

SessionFactory 是Hibrenate單例資料儲存和執行緒安全的,以至於可以多執行緒同時訪問。一個SessionFactory 在啟動的時候只能建立一次。SessionFactory應該包裝各種單例以至於它能很簡單的在一個應用程式碼中儲存.

21、Hibernate的五個核心介面

Configuration 介面:配置Hibernate,根據其啟動hibernate,建立

SessionFactory 物件;

SessionFactory 介面:初始化Hibernate,充當資料儲存源的代理,建立

session 物件,sessionFactory 是執行緒安全的,意味著它的同一個例項可以被應

用的多個執行緒共享,是重量級、二級快取;

Session 介面:負責儲存、更新、刪除、載入和查詢物件,是執行緒不安全的,

避免多個執行緒共享同一個session,是輕量級、一級快取;

Transaction 介面:管理事務;

Query 和Criteria 介面:執行資料庫的查詢

22.Hibernate的查詢方式有哪些?

本地SQL查詢、Criteria、Hql

5.如何優化Hibernate?

1.使用雙向一對多關聯,不使用單向一對多

2.靈活使用單向一對多關聯

3.不用一對一,用多對一取代

4.配置物件快取,不使用集合快取

5.一對多集合使用Bag,多對多集合使用Set

繼承類使用顯式多型

表字段要少,表關聯不要怕多,有二級快取撐腰

23.Hibernate中GET和LOAD的區別?

請注意如果沒有匹配的資料庫記錄,load()方法可能丟擲無法恢復的異常(unrecoverable exception)。 如果類的對映使用了代理(proxy),load()方法會返回一個未初始化的代理,直到你呼叫該代理的某方法時才會去訪問資料庫。若你希望在某物件中建立一個指向另一個物件的關聯,又不想在從資料庫中裝載該物件時同時裝載相關聯的那個物件,那麼這種操作方式就用得上的了。 如果為相應類對映關係設定了batch-size, 那麼使用這種操作方式允許多個物件被一批裝載(因為返回的是代理,無需從資料庫中抓取所有物件的資料)。 如果你不確定是否有匹配的行存在,應該使用 get()方法,它會立刻訪問資料庫,如果沒有對應的行,會返回null。

session.get 方法, 查詢立即執行 , 返回Customer類物件

session.load 方法,預設採用延遲載入資料方式,不會立即查詢,返回 Customer類子類物件 (動態生成代理物件)

如果 PO類使用final修飾,load無法建立代理物件,返回目標物件本身 (load效果和 get效果 相同 )

24.說說在 hibernate中使用Integer做對映和使用int做對映之間有什麼差別?

Integer code和int code的區別:

Integer是物件. code=null; 物件可以為空.

int 是普通型別, 不可能=null.

根據你的資料庫code是可以空的,故應該對映成Integer.

你沒理由hbm.xml裡寫 Integer,類裡卻寫int

.25SQL和HQL有什麼區別?

sql 面向資料庫表查詢

hql 面向物件查詢

hql:from 後面跟的 類名+類物件 where 後 用 物件的屬性做條件

sql:from 後面跟的是表名 where 後 用表中欄位做條件

查詢

在Hibernate中使用查詢時,一般使用Hql查詢語句。

HQL(Hibernate Query Language),即Hibernate的查詢語言跟SQL非常相像。不過HQL與SQL的最根本的區別,就是它是面向物件的。

使用HQL時需要注意以下幾點:

1.大小寫敏感

因為HQL是面向物件的,而物件類的名稱和屬性都是大小寫敏感的,所以HQL是大小寫敏感的。

HQL語句:from Cat as cat where cat.id > 1;與from Cat as cat where cat.ID > 1;是不一樣的,這點與SQL不同。

2.from子句

from Cat,該句返回Cat物件例項,開發人員也可以給其加上別名,eg. from Cat as cat,對於多表查詢的情況,可參考如下:

from Cat as cat, Dog as dog

其它方面都與SQL類似,在此不再贅述。

.26Hibernate的分頁查詢

例如:從資料庫中的第20000條資料開始查後面100條記錄

Query q = session.createQuery(“from Cat as c”);;

q.setMaxResults(100);;

List l = q.list();;

q.setFirstResult(20000);

27.Hibernate中Java物件的狀態以及對應的特徵有哪些?

持久化物件的三種狀態

持久化物件PO和OID

PO=POJO + hbm對映配置

編寫規則

①必須提供無引數public構造器

②所有屬性private,提供public的getter和setter方法

③必須提供標識屬性,與資料表中主鍵對應,例如Customer類 id屬性

④PO類屬性應儘量使用基本資料型別的包裝型別(區分空值) 例如int—Integer long—Long

⑤不要用final修飾(將無法生成代理物件進行優化)

OID 指與資料表中主鍵對應 PO類中屬性,例如 Customer類 id屬性

Hibernate框架使用OID來區分不同PO物件

* 例如記憶體中有兩個PO物件,只要具有相同 OID, Hibernate認為同一個物件

Hibernate 不允許快取同樣OID的兩個不同物件

①瞬時態(臨時態、自由態):不存在持久化標識OID,尚未與Hibernate Session關聯物件,被認為處於瞬時態,失去引用將被JVM回收

②持久態:存在持久化標識OID,與當前session有關聯,並且相關聯的session沒有關閉 ,並且事務未提交

③脫管態(離線態、遊離態):存在持久化標識OID,但沒有與當前session關聯,脫管狀態改變hibernate不能檢測到

區分三種狀態:判斷物件是否有OID,判斷物件是否與session關聯(被一級快取引用)

// 獲得Session

Session session =HibernateUtils.openSession();

// 開啟事務

Transaction transaction = session.beginTransaction();

Book book =newBook();// 瞬時態(沒有OID,未與Session關聯)

book.setName(“hibernate精通”);

book.setPrice(56d);

session.save(book);// 持久態(具有OID,與Session關聯)

// 提交事務,關閉Session

transaction.commit();

session.close();

System.out.println(book.getId());// 脫管態(具有 OID,與Session斷開關聯)

持久化物件狀態轉換

①瞬時態物件:通過new獲得

瞬時—–>持久 save、saveOrUpdate(都是session)

瞬時—–>脫管 book.setId(1) 為瞬時物件設定OID

②持久態物件:通過get/load 、Query查詢獲得

持久—–>瞬時 delete (被刪除持久化物件 不建議再次使用 )

持久—–>脫管 evict(清除一級快取中某一個物件)、close(關閉Session,清除一級快取)、clear(清除一級快取所有物件 )

③脫管態物件 無法直接獲得

脫管—–>瞬時 book.setId(null); 刪除物件OID

脫管—–>持久 update、saveOrUpdate、 lock(過時

Struts

Spring

SQL

資料庫建立索引的原則

1,確定針對該表的操作是大量的查詢操作還是大量的增刪改操作。

2,嘗試建立索引來幫助特定的查詢。檢查自己的sql語句,為那些頻繁在where子句中出現的欄位建立索引。

3,嘗試建立複合索引來進一步提高系統性能。修改複合索引將消耗更長時間,同時,複合索引也佔磁碟空間。

4,對於小型的表,建立索引可能會影響效能

5,應該避免對具有較少值的欄位進行索引。

6,避免選擇大型資料型別的列作為索引。

索引建立的原則

索引查詢是資料庫中重要的記錄查詢方法,要不要進入索引以及在那些欄位上建立索引都要和實際資料庫系統的查詢要求結合來考慮,下面給出實際中的一些通用的原則:

在經常用作過濾器的欄位上建立索引;

在SQL語句中經常進行GROUP BY、ORDER BY的欄位上建立索引;

在不同值較少的欄位上不必要建立索引,如性別欄位;

對於經常存取的列避免建立索引;

用於聯接的列(主健/外健)上建立索引;

在經常存取的多個列上建立複合索引,但要注意複合索引的建立順序要按照使用的頻度來確定;

預設情況下建立的是非簇集索引,但在以下情況下最好考慮簇集索引,如:含有有限數目(不是很少)唯一的列;進行大範圍的查詢;充分的利用索引可以減少表掃描I/0的次數,有效的避免對整表的搜尋。當然合理的索引要建立在對各種查詢的分析和預測中,也取決於DBA的所設計的資料庫結構。

異常

請列出 5 個執行時異常。

我們比較熟悉的Checked異常有

Java.lang.ClassNotFoundException

Java.lang.NoSuchMetodException

java.io.IOException

我們比較熟悉的RumtimeException類的子類有

Java.lang.ArithmeticException

Java.lang.ArrayStoreExcetpion

Java.lang.ClassCastException

Java.lang.IndexOutOfBoundsException

Java.lang.NullPointerException

反射

基礎

什麼是JDK?什麼是JRE?

JDK:java development kit:java開發工具包,是開發人員所需要安裝的環境

JRE:java runtime environment:java執行環境,java程式執行所需要安裝的環境

Java的資料結構有那些

線性表(ArrayList)

連結串列(LinkedList)

棧(Stack)

佇列(Queue)

圖(Map)

樹(Tree)

Static關鍵字有什麼作用?

Static可以修飾內部類、方法、變數、程式碼塊

Static修飾的類是靜態內部類

Static修飾的方法是靜態方法,表示該方法屬於當前類的,而不屬於某個物件的,靜態方法也不能被重寫,可以直接使用類名來呼叫。在static方法中不能使用this或者super關鍵字。

Static修飾變數是靜態變數或者叫類變數,靜態變數被所有例項所共享,不會依賴於物件。靜態變數在記憶體中只有一份拷貝,在JVM載入類的時候,只為靜態分配一次記憶體。

Static修飾的程式碼塊叫靜態程式碼塊,通常用來做程式優化的。靜態程式碼塊中的程式碼在整個類載入的時候只會執行一次。靜態程式碼塊可以有多個,如果有多個,按照先後順序依次執行

內部類與靜態內部類的區別?

靜態內部類相對與外部類是獨立存在的,在靜態內部類中無法直接訪問外部類中變數、方法。如果要訪問的話,必須要new一個外部類的物件,使用new出來的物件來訪問。但是可以直接訪問靜態的變數、呼叫靜態的方法;

普通內部類作為外部類一個成員而存在,在普通內部類中可以直接訪問外部類屬性,呼叫外部類的方法。

如果外部類要訪問內部類的屬性或者呼叫內部類的方法,必須要建立一個內部類的物件,使用該物件訪問屬性或者呼叫方法。

如果其他的類要訪問普通內部類的屬性或者呼叫普通內部類的方法,必須要在外部類中建立一個普通內部類的物件作為一個屬性,外同類可以通過該屬性呼叫普通內部類的方法或者訪問普通內部類的屬性

如果其他的類要訪問靜態內部類的屬性或者呼叫靜態內部類的方法,直接建立一個靜態內部類物件即可。

String, Stringbuffer, StringBuilder 的區別。

String 字串常量(final修飾,不可被繼承),String是常量,當建立之後即不能更改。(可以通過StringBuffer和StringBuilder建立String物件(常用的兩個字串操作類)。)

StringBuffer 字串變數(執行緒安全),其也是final類別的,不允許被繼承,其中的絕大多數方法都進行了同步處理,包括常用的Append方法也做了同步處理(synchronized修飾)。其自jdk1.0起就已經出現。其toString方法會進行物件快取,以減少元素複製開銷。

public synchronized String toString() {

if (toStringCache == null) {

toStringCache = Arrays.copyOfRange(value, 0, count);

}

return new String(toStringCache, true);

}

StringBuilder 字串變數(非執行緒安全)其自jdk1.5起開始出現。與StringBuffer一樣都繼承和實現了同樣的介面和類,方法除了沒使用synch修飾以外基本一致,不同之處在於最後toString的時候,會直接返回一個新物件。

public String toString() {

// Create a copy, don’t share the array

return new String(value, 0, count);

}

抽象類和介面的區別,類可以繼承多個類麼,介面可以繼承多個介面麼,類可以實現多個介面麼。

1、抽象類和介面都不能直接例項化,如果要例項化,抽象類變數必須指向實現所有抽象方法的子類物件,介面變數必須指向實現所有介面方法的類物件。

2、抽象類要被子類繼承,介面要被類實現。

3、介面只能做方法申明,抽象類中可以做方法申明,也可以做方法實現

4、接口裡定義的變數只能是公共的靜態的常量,抽象類中的變數是普通變數。

5、抽象類裡的抽象方法必須全部被子類所實現,如果子類不能全部實現父類抽象方法,那麼該子類只能是抽象類。同樣,一個實現介面的時候,如不能全部實現介面方法,那麼該類也只能為抽象類。

6、抽象方法只能申明,不能實現。abstract void abc();不能寫成abstract void abc(){}。

7、抽象類裡可以沒有抽象方法

8、如果一個類裡有抽象方法,那麼這個類只能是抽象類

9、抽象方法要被實現,所以不能是靜態的,也不能是私有的。

10、介面可繼承介面,並可多繼承介面,但類只能單根繼承。

繼承和聚合的區別在哪。

繼承指的是一個類(稱為子類、子介面)繼承另外的一個類(稱為父類、父介面)的功能,並可以增加它自己的新功能的能力,繼承是類與類或者介面與介面之間最常見的關係;在Java中此類關係通過關鍵字extends明確標識,在設計時一般沒有爭議性;

聚合是關聯關係的一種特例,他體現的是整體與部分、擁有的關係,即has-a的關係,此時整體與部分之間是可分離的,他們可以具有各自的生命週期,部分可以屬於多個整體物件,也可以為多個整體物件共享;比如計