Java程式員面試中的多線程問題

來源:互聯網
上載者:User

標籤:style   blog   http   color   java   使用   io   strong   

很多核心Java面試題來源於多線程(Multi-Threading)和集合架構(Collections Framework),理解核心線程概念時,嫻熟的實際經驗是必需的。這篇文章收集了Java線程方面一些典型的問題,這些問題經常被進階工程師所問到。

0、Java中多線程同步是什嗎?

在多線程程式下,同步能控制對共用資源的訪問。如果沒有同步,當一個Java線程在修改一個共用變數時,另外一個線程正在使用或者更新同一個變數,這樣容易導致程式出現錯誤的結果。

1、解釋實現多線程的幾種方法?

一Java線程可以實現Runnable介面或者繼承Thread類來實現,當你打算多重繼承時,優先選擇實現Runnable。

2、Thread.start()與Thread.run()有什麼區別?

Thread.start()方法(native)啟動線程,使之進入就緒狀態,當cpu分配時間該線程時,由JVM調度執行run()方法。

3、為什麼需要run()和start()方法,我們可以只用run()方法來完成任務嗎?

我們需要run()&start()這兩個方法是因為JVM建立一個單獨的線程不同於普通方法的調用, 所以這項工作由線程的start方法來完成,start由本地方法實現,需要顯示地被調用,使用這倆個方法的另外一個好處是任何一個對象都可以作為線程運 行,只要實現了Runnable介面,這就避免因繼承了Thread類而造成的Java的多繼承問題。

4、什麼是ThreadLocal類,怎麼使用它?

ThreadLocal是一個線程層級的局部變數,並非“本地線程”。ThreadLocal為每個使用該變數的線程提供了一個獨立的變數副本,每個線程修改副本時不影響其它線程對象的副本(譯者注)。

下面是線程局部變數(ThreadLocal variables)的關鍵點:

一個線程局部變數(ThreadLocal variables)為每個線程方便地提供了一個單獨的變數。

ThreadLocal執行個體通常作為靜態私人的(private static)欄位出現在一個類中,這個類用來關聯一個線程。

當多個線程訪問ThreadLocal執行個體時,每個線程維護ThreadLocal提供的獨立的變數副本。

常用的使用可在DAO模式中見到,當DAO類作為一個單例類時,資料庫連結(connection)被每一個線程獨立的維護,互不影響。(基於線程的單例)

5、什麼時候拋出InvalidMonitorStateException異常,為什嗎?

調用wait()/notify()/notifyAll()中的任何一個方法時,如果當前線程沒有獲得該對象的鎖,那麼就會拋出IllegalMonitorStateException的異常(也就是說程式在沒有執行對象的任何同步塊或者同步方法時,仍然嘗試 調用wait()/notify()/notifyAll()時)。由於該異常是RuntimeExcpetion的子類,所以該異常不一定要捕獲(儘管 你可以捕獲只要你願意).作為RuntimeException,此類異常不會在wait(),notify(),notifyAll()的方法簽名提 及。

6、Sleep()、suspend()和wait()之間有什麼區別?

Thread.sleep()使當前線程在指定的時間處於“非運行”(Not Runnable)狀態。線程一直持有對象的監視器。比如一個線程當前在一個同步塊或同步方法中,其它線程不能進入該塊或方法中。如果另一線程調用了 interrupt()方法,它將喚醒那個“睡眠的”線程。

注意:sleep()是一個靜態方法。這意味著只對當前線程有效,一個常見的錯誤是調用t.sleep(),(這裡的t是一個不同於當前線程的線 程)。即便是執行t.sleep(),也是當前線程進入睡眠,而不是t線程。t.suspend()是過時的方法,使用suspend()導致線程進入停 滯狀態,該線程會一直持有對象的監視器,suspend()容易引起死結問題。

object.wait()使當前線程出於“不可運行”狀態,和sleep()不同的是wait是object的方法而不是thread。調用 object.wait()時,線程先要擷取這個對象的對象鎖,當前線程必須在鎖對象保持同步,把當前線程添加到等待隊列中,隨後另一線程可以同步同一個 對象鎖來調用object.notify(),這樣將喚醒原來等待中的線程,然後釋放該鎖。基本上wait()/notify()與sleep() /interrupt()類似,只是前者需要擷取對象鎖。

7、在靜態方法上使用同步時會發生什麼事?

同步靜態方法時會擷取該類的“Class”對象,所以當一個線程進入同步的靜態方法中時,線程監視器擷取類本身的對象鎖,其它線程不能進入這個類的任何靜態同步方法。它不像執行個體方法,因為多個線程可以同時訪問不同執行個體同步執行個體方法。

8、當一個同步方法已經執行,線程能夠調用對象上的非同步執行個體方法嗎?

可以,一個非同步方法總是可以被調用而不會有任何問題。實際上,Java沒有為非同步方法做任何檢查,鎖對象僅僅在同步方法或者同步代碼塊中檢查。如果一個方法沒有聲明為同步,即使你在使用共用資料Java照樣會調用,而不會做檢查是否安全,所以在這種情況下要特別小心。一個方法是否聲明為同步取決於臨界區訪問(critial section access),如果方法不訪問臨界區(共用資源或者資料結構)就沒必要聲明為同步的。

9、 在一個對象上兩個線程可以調用兩個不同的同步執行個體方法嗎?

不能,因為一個對象已經同步了執行個體方法,線程擷取了對象的對象鎖。所以只有執行完該方法釋放對象鎖後才能執行其它同步方法。

10、 什麼是死結

死結就是兩個或兩個以上的線程被無限的阻塞,線程之間相互等待所需資源。這種情況可能發生在當兩個線程嘗試擷取其它資源的鎖,而每個線程又陷入無限等待其它資源鎖的釋放,除非一個使用者進程被終止。就JavaAPI而言,線程死結可能發生在一下情況。

●當兩個線程相互調用Thread.join()

●當兩個線程使用嵌套的同步塊,一個線程佔用了另外一個線程必需的鎖,互相等待時被阻塞就有可能出現死結。

11、什麼是線程餓死,什麼是活鎖?

線程餓死和活鎖雖然不想是死結一樣的常見問題,但是對於並發編程的設計者來說就像一次邂逅一樣。

當所有線程阻塞,或者由於需要的資源無效而不能處理,不存在非阻塞線程使資源可用。JavaAPI中線程活鎖可能發生在以下情形:

●當所有線程在程式中執行Object.wait(0),參數為0的wait方法。程式將發生活鎖直到在相應的對象上有線程調用Object.notify()或者Object.notifyAll()。

●當所有線程卡在無限迴圈中。

這裡的問題並不詳盡,我相信還有很多重要的問題並未提及,您認為還有哪些問題應該包括在上面呢?歡迎在評論中分享任何形式的問題與建議。

我是天王蓋地虎的分割線                                         

 

 

參考:http://blog.jobbole.com/18571/

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.