1. 程式人生 > >超詳細的Java面試題總結(二)之Java基礎知識篇

超詳細的Java面試題總結(二)之Java基礎知識篇

多執行緒和Java虛擬機器

建立執行緒有幾種不同的方式?你喜歡哪一種?為什麼?

  1. 繼承Thread類
  2. 實現Runnable介面
  3. 應用程式可以使用Executor框架來建立執行緒池
  4. 實現Callable介面。

我更喜歡實現Runnable介面這種方法,當然這也是現在大多程式設計師會選用的方法。因為一個類只能繼承一個父類而可以實現多個介面。同時,執行緒池也是非常高效的,很容易實現和使用。

簡述執行緒,程式、程序的基本概念。以及他們之間關係是什麼?(參考書籍:《Java程式設計基礎》第五版)

執行緒與程序相似,但執行緒是一個比程序更小的執行單位。一個程序在其執行的過程中可以產生多個執行緒。與程序不同的是同類的多個執行緒共享同一塊記憶體空間和一組系統資源,所以系統在產生一個執行緒,或是在各個執行緒之間作切換工作時,負擔要比程序小得多,也正因為如此,執行緒也被稱為輕量級程序。

程式是含有指令和資料的檔案,被儲存在磁碟或其他的資料儲存裝置中,也就是說程式是靜態的程式碼。

程序是程式的一次執行過程,是系統執行程式的基本單位,因此程序是動態的。系統執行一個程式即是一個程序從建立,執行到消亡的過程。簡單來說,一個程序就是一個執行中的程式,它在計算機中一個指令接著一個指令地執行著,同時,每個程序還佔有某些系統資源如CPU時間,記憶體空間,檔案,檔案,輸入輸出裝置的使用權等等。換句話說,當程式在執行時,將會被作業系統載入記憶體中。 執行緒是程序劃分成的更小的執行單位。執行緒和程序最大的不同在於基本上各程序是獨立的,而各執行緒則不一定,因為同一程序中的執行緒極有可能會相互影響。從另一角度來說,程序屬於作業系統的範疇,主要是同一段時間內,可以同時執行一個以上的程式,而執行緒則是在同一程式內幾乎同時執行一個以上的程式段。

什麼是多執行緒?為什麼程式的多執行緒功能是必要的?

多執行緒就是幾乎同時執行多個執行緒(一個處理器在某一個時間點上永遠都只能是一個執行緒!即使這個處理器是多核的,除非有多個處理器才能實現多個執行緒同時執行。)。幾乎同時是因為實際上多執行緒程式中的多個執行緒實際上是一個執行緒執行一會然後其他的執行緒再執行,並不是很多書籍所謂的同時執行。這樣可以帶來以下的好處:

  1. 使用執行緒可以把佔據長時間的程式中的任務放到後臺去處理
  2. 使用者介面可以更加吸引人,這樣比如使用者點選了一個按鈕去觸發某些事件的處理,可以彈出一個進度條來顯示處理的進度
  3. 程式的執行速度可能加快
  4. 在一些等待的任務實現上如使用者輸入、檔案讀寫和網路收發資料等,執行緒就比較有用了。在這種情況下可以釋放一些珍貴的資源如記憶體佔用等等。 還有其他很多使用多執行緒的好處,這裡就不一一說明了。

多執行緒與多工的差異是什麼?(參考書籍:《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)狀態。
  5. 死亡(dead):執行緒run()、main()方法執行結束,或者因異常退出了run()方法,則該執行緒結束生命週期。死亡的執行緒不可再次復生。 執行緒的基本狀態備註: 可以用早起坐地鐵來比喻這個過程: 還沒起床:sleeping 起床收拾好了,隨時可以坐地鐵出發:Runnable 等地鐵來:Waiting 地鐵來了,但要排隊上地鐵:I/O阻塞 上了地鐵,發現暫時沒座位:synchronized阻塞 地鐵上找到座位:Running 到達目的地:Dead

什麼是執行緒的同步?程式中為什麼要實現執行緒的同步?是如何實現同步的?

當一個執行緒對共享的資料進行操作時,應使之成為一個”原子操作“,即在沒有完成相關操作之前,不允許其他執行緒打斷它,否則,就會破壞資料的完整性,必然會得到錯誤的處理結果,這就是執行緒的同步。 在多執行緒應用中,考慮不同執行緒之間的資料同步和防止死鎖。當兩個或多個執行緒之間同時等待對方釋放資源的時候就會形成執行緒之間的死鎖。為了防止死鎖的發生,需要通過同步來實現執行緒安全。

在監視器(Monitor)內部,是如何做執行緒同步的?程式應該做哪種級別的同步?

在 java 虛擬機器中, 每個物件( Object 和 class )通過某種邏輯關聯監視器,每個監視器和一個物件引用相關聯, 為了實現監視器的互斥功能, 每個物件都關聯著一把鎖. 一旦方法或者程式碼塊被synchronized 修飾, 那麼這個部分就放入了監視器的監視區域, 確保一次只能有一個執行緒執行該部分的程式碼, 執行緒在獲取鎖之前不允許執行該部分的程式碼 另外 java 還提供了顯式監視器( Lock )和隱式監視器( synchronized )兩種鎖方案

什麼是死鎖(deadlock)?

360百科

死鎖 :是指兩個或兩個以上的程序在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去 。 產生原因:

  • 因為系統資源不足。
  • 程序執行推進順序不合適。
  • 資源分配不當等。
  • 佔用資源的程式崩潰等。

如果系統資源充足,程序的資源請求都能夠得到滿足,死鎖出現的可能性就很低,否則就會因爭奪有限的資源而陷入死鎖。其次,程序執行推進順序與速度不同,也可能產生死鎖。

下面四個條件是死鎖的必要條件,只要系統發生死鎖,這些條件必然成立,而只要下列條件之一不滿足,就不會發生死鎖。

  • 互斥條件:一個資源每次只能被一個程序使用。
  • 請求與保持條件:一個程序因請求資源而阻塞時,對已獲得的資源保持不放。
  • 不剝奪條件:程序已獲得的資源,在末使用完之前,不能強行剝奪。
  • 迴圈等待條件:若干程序之間形成一種頭尾相接的迴圈等待資源關係。 死鎖的解除與預防:

理解了死鎖的原因,尤其是產生死鎖的四個必要條件,就可以最大可能地避免、預防和 解除死鎖。所以,在系統設計、程序排程等方面注意如何不讓這四個必要條件成立,如何確 定資源的合理分配演算法,避免程序永久佔據系統資源。此外,也要防止程序在處於等待狀態的情況下佔用資源。因此,對資源的分配要給予合理的規劃。

如何確保N個執行緒可以訪問N個資源同時又不導致死鎖?

上面一題我們知道了發生死鎖的四個必要條件。我們只要使其中一個不成立就行了。一種非常簡單的避免死鎖的方式就是:指定獲取鎖的順序,並強制執行緒按照指定的順序獲取鎖。因此,如果所有的執行緒都是以同樣的順序加鎖和釋放鎖,就不會出現死鎖了。這也就是破壞了第四個條件迴圈等待條件。

Java中垃圾回收有什麼目的?什麼時候進行垃圾回收?

垃圾回收是在記憶體中存在沒有引用的物件或超過作用域的物件時進行。

垃圾回收的目的是識別並且丟棄應用不再使用的物件來釋放和重用資源。

finalize()方法什麼時候被呼叫?解構函式(finalization)的目的是什麼?

1)垃圾回收器(garbage colector)決定回收某物件時,就會執行該物件的finalize()方法; finalize是Object類的一個方法,該方法在Object類中的宣告protected void finalize() throws Throwable { } 在垃圾回收器執行時會呼叫被回收物件的finalize()方法,可以覆蓋此方法來實現對其資源的回收。注意:一旦垃圾回收器準備釋放物件佔用的記憶體,將首先呼叫該物件的finalize()方法,並且下一次垃圾回收動作發生時,才真正回收物件佔用的記憶體空間

2)GC本來就是記憶體回收了,應用還需要在finalization做什麼呢? 答案是大部分時候,什麼都不用做(也就是不需要過載)。只有在某些很特殊的情況下,比如你呼叫了一些native的方法(一般是C寫的),可以要在finaliztion裡去呼叫C的釋放函式。

如果物件的引用被置為null,垃圾收集器是否會立即釋放物件佔用的記憶體?

不會,在下一個垃圾回收週期中,這個物件將是可被回收的。

Java中堆和棧的區別

Java中堆和棧的區別

堆記憶體用來存放由new建立的物件和陣列。 在堆中分配的記憶體,由Java虛擬機器的自動垃圾回收器來管理。 棧中一般存放的是區域性變數(方法中的變數或某程式碼段裡(比如for迴圈))

Java堆的結構是什麼樣子的?什麼是堆中的永久代(Perm Gen space)?

Java堆的結構是什麼樣子的?什麼是堆中的永久代

Java集合框架

List,Set,Map三者的區別及總結

ArrayList 與 Vector 區別(為什麼要用Arraylist取代Vector呢?)

List,Set,Map三者的區別及總結

HashMap 和 Hashtable 的區別

HashSet 和 HashMap 區別

HashMap 和 ConcurrentHashMap 的區別

HashSet如何檢查重複

comparable 和 comparator的區別?

如何對Object的list排序?

如何實現陣列與List的相互轉換?

如何求ArrayList集合的交集 並集 差集 去重複並集?

HashMap 的工作原理及程式碼實現

ConcurrentHashMap 的工作原理及程式碼實現

集合框架底層資料結構總結

集合的選用