1. 程式人生 > >Java面試題(41-55)

Java面試題(41-55)

41、Java語言如何進行異常處理,關鍵字:throws、throw、try、catch、finally分別代表什麼意義?在try塊中可以丟擲異常嗎?

  • try塊表示程式正常的業務執行程式碼。如果程式在執行try塊的程式碼時出現了“非預期”情況,JVM將會生成一個異常物件,這個異常物件將會被後面相應的catch塊捕獲。

  • catch塊表示一個異常捕獲塊。當程式執行try塊引發異常時,這個異常物件將會被後面相應的catch塊捕獲。

  • throw用於手動地丟擲異常物件。throw後面需要一個異常物件。

  • throws用於在方法簽名中宣告丟擲一個或多個異常類,throws關鍵字後可以緊跟一個或多個異常類。

  • finally塊代表異常處理流程中總會執行的程式碼塊。

對於一個完整的異常處理流程而言,try塊是必須的,try塊後可以緊跟一個或多個catch塊,最後還可以帶一個finally塊。

try塊中可以丟擲異常。

42、java 中有幾種方法可以實現一個執行緒?

java5以前,有兩種實現方法,分別使用new Thread()和new Thread(runnable)形式,

  • 第一種繼承Thread類,直接重寫thread的run方法,所以,我們往往使用Thread子類,即new SubThread()。

  • 第二種是實現Runnable介面,實現runnable的run方法。

第一種: new Thread(){}.start();這表示呼叫Thread子類物件的run方法,new Thread(){}表示一個 Thread的匿名子類的例項物件,子類加上run方法後的程式碼如下:

new Thread() {
    public void run() {}; 
}.start();

第二種: new Thread(new Runnable(){}).start();這表示呼叫Thread物件接受的Runnable物件的run 方法,new Runnable(){}表示一個實現了Runnable介面的匿名子類的例項物件,runnable的實現類加上run方法後的程式碼如下:

new Thread(new Runnable() {
@Override
    public void run() {}
}).start();

從java5開始,還有如下一些執行緒池建立多執行緒的方式:

newFixedThreadPool(int nThread)

建立一個可重用固定執行緒數的執行緒池,以共享的無界佇列方式來執行這些執行緒。

ExecutorService pool = Executors.newFixedThreadPool(3);
for(int i=0;i<10;i++) {
    pool.execute(new Runnable(){public void run(){}});
}

newCachedThreadPool()

建立一個可根據需要建立新執行緒的執行緒池,但是在以前構造的執行緒可用時將重用它們。

Executors.newCachedThreadPool().execute(new Runnable(){public void run(){}});

newSingleThreadExecutor()

建立一個使用單個 worker 執行緒的 Executor,以無界佇列方式來執行該執行緒。

Executors.newSingleThreadExecutor().execute(new Runnable(){public void run(){}});

43、用什麼關鍵字修飾同步方法?

用synchronized關鍵字修飾同步方法。

44、stop()和 suspend()方法為何不推薦使用?

stop()方法

stop()方法作為一種粗暴的執行緒終止行為,線上程終止之前沒有對其做任何的清除操作,因此具有固有的不安全性。用Thread.stop()方法來終止執行緒將會釋放該執行緒物件已經鎖定的所有監視器。如果以前受這些監視器保護的任何物件都處於不連貫狀態,那麼損壞的物件對其他執行緒可見,這有可能導致不安全的操作。 由於上述原因,因此不應該使用stop()方法,而應該在自己的Thread類中置入一個標誌,用於控制目標執行緒是活動還是停止。如果該標誌指示它要停止執行,可使其結束run()方法。如果目標執行緒等待很長時間,則應使用interrupt()方法來中斷該等待。

舉個例子

假如一個執行緒正在執行:synchronized void { x = 3; y = 4;} 由於方法是同步的,多個執行緒訪問時總能保證x,y被同時賦值,而如果一個執行緒正在執行到x = 3;時,被呼叫了 stop()方法,即使在同步塊中,它也乾脆地stop了,這樣就產生了不完整的殘廢資料。而多執行緒程式設計中最最基礎的條件要保證資料的完整性;

suspend()方法

該方法已經遭到反對,因為它具有固有的死鎖傾向。呼叫suspend()方法的時候,目標執行緒會停下來。如果目標執行緒掛起時在保護關鍵系統資源的監視器上保持有鎖,則在目標執行緒重新開始以前,其他執行緒都不能訪問該資源。除非被掛起的執行緒恢復執行。對任何其他執行緒來說,如果想恢復目標執行緒,同時又試圖使用任何一個鎖定的資源,就會造成死鎖。由於上述原因,因此不應該使用suspend()方法,而應在自己的thread類中置入一個標誌,用於控制執行緒是活動還是掛起。如果標誌指出執行緒應該掛起,那麼用wait()方法命令其進入等待狀態。如果標誌指出執行緒應當恢復,那麼用notify()方法重新啟動執行緒。

45、sleep() 和 wait() 有什麼區別?

  • sleep 就是正在執行的執行緒主動讓出 cpu,cpu 去執行其他執行緒,在 sleep 指定的時間過後,cpu 才會回到這個執行緒上繼續往下執行,如果當前執行緒進入了同步鎖,sleep 方法並不會釋放鎖,即使當前執行緒使用 sleep 方法讓出了 cpu,但其他被同步鎖擋住了的執行緒也無法得到執行。

  • wait 是指在一個已經進入了同步鎖的執行緒內,讓自己暫時讓出同步鎖,以便其他正在等待此鎖的執行緒可以得到同步鎖並執行,只有其他執行緒呼叫了 notify 方法(notify 並不釋放鎖,只是告訴呼叫過 wait 方法的執行緒可以去參與獲得鎖的競爭了,但不是馬上得到鎖,因為鎖還在別人手裡,別人還沒釋放。),呼叫 wait 方法的執行緒就會解除 wait 狀態和程式可以再次得到鎖後繼續向下執行。對於 wait 的講解一定要配合例子程式碼來說明,才顯得自己真明白。

46、同步和非同步有何異同,在什麼情況下分別使用他們?舉例說明。

如果資料將線上程間共享。例如正在寫的資料以後可能被另一個執行緒讀到,或者正在讀的資料可能已經被另一個執行緒寫過了,那麼這些資料就是共享資料,必須進行同步存取。

當應用程式在物件上呼叫了一個需要花費很長時間來執行的方法,並且不希望讓程式等待方法的返回時,就應該使用非同步程式設計,在很多情況下采用非同步途徑往往更有效率。

47、多執行緒有幾種實現方法?同步有幾種實現方法?

多執行緒有兩種實現方法,分別是繼承 Thread 類與實現 Runnable 介面

同步的方式

  • 同步方法 :即有synchronized關鍵字修飾的方法。 synchronized關鍵字也可以修飾靜態方法,此時如果呼叫該靜態方法,將會鎖住整個類

  • 同步程式碼塊 :即有synchronized關鍵字修飾的語句塊。被該關鍵字修飾的語句塊會自動被加上內建鎖,從而實現同步

  • 使用特殊域變數(volatile)實現執行緒同步

  • 使用重入鎖實現執行緒同步

48、啟動一個執行緒是用 run()還是 start()?

啟動一個執行緒是呼叫 start()方法,使執行緒就緒狀態,以後可以被排程為執行狀態,一個執行緒必須關聯一些具體的執行程式碼,run()方法是該執行緒所關聯的執行程式碼。

49、當一個執行緒進入一個物件的一個 synchronized 方法後,其它執行緒是否可進入此物件的其它方法?

  • 其他方法前是否加了synchronized關鍵字,如果沒加,則能。

  • 如果這個方法內部呼叫了wait,則可以進入其他synchronized方法。

  • 如果其他個方法都加了synchronized關鍵字,並且內部沒有呼叫wait,則不能。

  • 如果其他方法是static,它用的同步鎖是當前類的位元組碼,與非靜態的方法不能同步,因為非靜態的方法用的是this。

50、執行緒的基本概念、執行緒的基本狀態以及狀態之間的關係

執行緒:是程序中的一個執行控制單元,執行路徑

  • 一個程序中至少有一個執行緒在負責控制程式的執行;

  • 一個程序中如果只有一個執行路徑,這個程式稱為單執行緒;

  • 一個程序中有多個執行路徑時,這個程式成為多執行緒;

一個執行緒是程序的一個順序執行流。同類的多個執行緒共享一塊記憶體空間和一組系統資源,執行緒本身有一個供程式執行時的堆疊。執行緒在切換時負荷小,因此,執行緒也被稱為輕負荷程序。一個程序中可以包含多個執行緒。

一個程序有一個或多個執行緒。執行緒更細化於程序,使得多執行緒程式的併發性高。程序在執行過程中擁有獨立的記憶體單元,而多個執行緒共享記憶體,從而極大地提高了程式的執行效率。

執行緒在執行過程中與程序的區別在於每個獨立的執行緒有一個程式執行的入口、順序執行序列和程式的出口。但是執行緒不能夠獨立執行,必須依存在應用程式中,由應用程式提供多個執行緒執行控制。

從邏輯角度來看,多執行緒的意義在於一個應用程式中,有多個執行部分可以同時執行。但作業系統並沒有將多個執行緒看做多個獨立的應用來實現程序的排程和管理以及資源分配。

多個執行緒或程序”同時”執行只是我們感官上的一種表現。事實上程序和執行緒是併發執行的,OS的執行緒排程機制將時間劃分為很多時間片段(時間片),儘可能均勻分配給正在執行的程式,獲取CPU時間片的執行緒或程序得以被執行,其他則等待。而CPU則在這些程序或執行緒上來回切換執行。微觀上所有程序和執行緒是走走停停的,巨集觀上都在執行,這種都執行的現象叫併發,但是不是絕對意義上的“同時發生。

執行緒狀態


這裡寫圖片描述
  • 新建:用new語句建立的執行緒物件處於新建狀態,此時它和其他java物件一樣,僅被分配了記憶體。

  • 等待:當執行緒在new之後,並且在呼叫start方法前,執行緒處於等待狀態。

  • 就緒:當一個執行緒物件建立後,其他執行緒呼叫它的start()方法,該執行緒就進入就緒狀態。處於這個狀態的執行緒位於Java虛擬機器的可執行池中,等待cpu的使用權。

  • 執行狀態:處於這個狀態的執行緒佔用CPU,執行程式程式碼。在併發執行環境中,如果計算機只有一個CPU,那麼任何時刻只會有一個執行緒處於這個狀態。只有處於就緒狀態的執行緒才有機會轉到執行狀態。

  • 阻塞狀態:阻塞狀態是指執行緒因為某些原因放棄CPU,暫時停止執行。當執行緒處於阻塞狀態時,Java虛擬機器不會給執行緒分配CPU,直到執行緒重新進入就緒狀態,它才會有機會獲得執行狀態。

  • 死亡狀態:當執行緒執行完run()方法中的程式碼,或者遇到了未捕獲的異常,就會退出run()方法,此時就進入死亡狀態,該執行緒結束生命週期。

阻塞狀態分為三種:

  • 等待阻塞:執行的執行緒執行wait()方法,JVM會把該執行緒放入等待池中。

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

  • 其他阻塞:執行的執行緒執行Sleep()方法,或者發出I/O請求時,JVM會把執行緒設為阻塞狀態。當Sleep()狀態超時、或者I/O處理完畢時,執行緒重新轉入就緒狀態。

51、簡述 synchronized 和 java.util.concurrent.locks.Lock 的異同 ?

  • 主要相同點:Lock 能完成 synchronized 所實現的所有功能

  • 主要不同點:Lock 有比 synchronized 更精確的執行緒語義和更好的效能。synchronized 會自動釋放鎖,而 Lock 一定要求程式設計師手工釋放,並且最好在 finally塊句中釋放。Lock還有更強大的功能,例如,它的 tryLock 方法可以非阻塞方式去拿鎖。

52、介紹 Collection 框架的結構


這裡寫圖片描述


這裡寫圖片描述

53、ArrayList 和 Vector 的區別

這兩個類都實現了 List 介面(List 介面繼承了 Collection 介面),他們都是有序集合——即儲存在這兩個集合中的元素的位置都是有順序的,相當於一種動態的陣列。我們以後可以按位置索引號取出某個元素,並且其中的資料是允許重複的。

  • Vector 是執行緒安全的,也就是說是它的方法之間是執行緒同步的,而 ArrayList 是執行緒序不安全的,它的方法之間是執行緒不同步的。如果只有一個執行緒會訪問到集合,那最好是使用ArrayList,因為它不考慮執行緒安全,效率會高些;如果有多個執行緒會訪問到集合,那最好是使用 Vector,因為不需要我們自己再去考慮和編寫執行緒安全的程式碼。

  • ArrayList 與 Vector 都有一個初始的容量大小,當儲存進它們裡面的元素的個數超過了容量時,就需要增加 ArrayList 與 Vector 的儲存空間,每次要增加儲存空間時,不是隻增加一個儲存單元,而是增加多個儲存單元,每次增加的儲存單元的個數在記憶體空間利用與程式效率之間要取得一定的平衡。Vector 預設增長1倍,ArrayList 增加原來的 0.5 倍。

  • ArrayList 與 Vector 都可以設定初始的空間大小,Vector 還可以設定增長的空間大小,而 ArrayList 沒有提供設定增長空間的方法。

54、HashMap 和 Hashtable 的區別

  • 繼承的父類不同:HashMap是繼承自AbstractMap類,而HashTable是繼承自Dictionary類。不過它們都實現了同時實現了map、Cloneable(可複製)、Serializable(可序列化)這三個介面Dictionary類是一個已經被廢棄的類(見其原始碼中的註釋)。父類都被廢棄,自然而然也沒人用它的子類Hashtable了。

  • 對Null key和Null value的支援不同:Hashtable既不支援Null key也不支援Null value,HashMap 允許將 null 作為一個 entry 的 key 或者 value;

  • HashMap 把Hashtable 的contains 方法去掉了,改成containsValue 和containsKey。因為contains方法容易讓人引起誤解。

  • Hashtable 的方法是 Synchronize 的,而 HashMap 不是,在多個執行緒訪問Hashtable 時,不需要自己為它的方法實現同步,而 HashMap 就必須為之提供外同步。

55、List 和 Map的區別?

  • List:是儲存單列資料的集合,儲存的資料是有序並且是可以重複的

  • Map:儲存雙列資料