精選Java線(xiàn)程面試題
Java是一門(mén)面向對象編程語(yǔ)言,不僅吸收了C++語(yǔ)言的各種優(yōu)點(diǎn),還摒棄了C++里難以理解的多繼承、指針等概念。下面是小編搜集的Java線(xiàn)程面試題,歡迎大家閱讀。
1)什么是線(xiàn)程?
線(xiàn)程是操作系統能夠進(jìn)行運算調度的最小單位,它被包含在進(jìn)程之中,是進(jìn)程中的實(shí)際運作單位。程序員可以通過(guò)它進(jìn)行多處理器編程,你可以使用多線(xiàn)程對運算密集型任務(wù)提速。比如,如果一個(gè)線(xiàn)程完成一個(gè)任務(wù)要100毫秒,那么用十個(gè)線(xiàn)程完成改任務(wù)只需10毫秒。Java在語(yǔ)言層面對多線(xiàn)程提供了卓越的支持,它也是一個(gè)很好的賣(mài)點(diǎn)。欲了解更多詳細信息請點(diǎn)擊這里。
2)線(xiàn)程和進(jìn)程有什么區別?
線(xiàn)程是進(jìn)程的子集,一個(gè)進(jìn)程可以有很多線(xiàn)程,每條線(xiàn)程并行執行不同的任務(wù)。不同的進(jìn)程使用不同的內存空間,而所有的線(xiàn)程共享一片相同的內存空間。別把它和棧內存搞混,每個(gè)線(xiàn)程都擁有單獨的棧內存用來(lái)存儲本地數據。更多詳細信息請點(diǎn)擊這里。
3)如何在Java中實(shí)現線(xiàn)程?
在語(yǔ)言層面有兩種方式。java。lang。Thread 類(lèi)的實(shí)例就是一個(gè)線(xiàn)程但是它需要調用java。lang。Runnable接口來(lái)執行,由于線(xiàn)程類(lèi)本身就是調用的Runnable接口所以你可以繼承java。lang。Thread 類(lèi)或者直接調用Runnable接口來(lái)重寫(xiě)run()方法實(shí)現線(xiàn)程。更多詳細信息請點(diǎn)擊這里。
4)用Runnable還是Thread?
這個(gè)問(wèn)題是上題的后續,大家都知道我們可以通過(guò)繼承Thread類(lèi)或者調用Runnable接口來(lái)實(shí)現線(xiàn)程,問(wèn)題是,那個(gè)方法更好呢?什么情況下使用它?這個(gè)問(wèn)題很容易回答,如果你知道Java不支持類(lèi)的多重繼承,但允許你調用多個(gè)接口。所以如果你要繼承其他類(lèi),當然是調用Runnable接口好了。更多詳細信息請點(diǎn)擊這里。
5)Thread 類(lèi)中的start() 和 run() 方法有什么區別?
這個(gè)問(wèn)題經(jīng)常被問(wèn)到,但還是能從此區分出面試者對Java線(xiàn)程模型的理解程度。start()方法被用來(lái)啟動(dòng)新創(chuàng )建的線(xiàn)程,而且start()內部調用了run()方法,這和直接調用run()方法的效果不一樣。當你調用run()方法的時(shí)候,只會(huì )是在原來(lái)的線(xiàn)程中調用,沒(méi)有新的線(xiàn)程啟動(dòng),start()方法才會(huì )啟動(dòng)新線(xiàn)程。更多討論請點(diǎn)擊這里
6)Java中Runnable和Callable有什么不同?
Runnable和Callable都代表那些要在不同的線(xiàn)程中執行的任務(wù)。Runnable從JDK1。0開(kāi)始就有了,Callable是在JDK1。5增加的。它們的主要區別是Callable的 call() 方法可以返回值和拋出異常,而Runnable的run()方法沒(méi)有這些功能。Callable可以返回裝載有計算結果的Future對象。我的博客有更詳細的說(shuō)明。
7)Java中CyclicBarrier 和 CountDownLatch有什么不同?
CyclicBarrier 和 CountDownLatch 都可以用來(lái)讓一組線(xiàn)程等待其它線(xiàn)程。與 CyclicBarrier 不同的是,CountdownLatch 不能重新使用。點(diǎn)此查看更多信息和示例代碼。
8) Java中CyclicBarrier 和 CountDownLatch有什么不同?
CyclicBarrier 和 CountDownLatch 都可以用來(lái)讓一組線(xiàn)程等待其它線(xiàn)程。與 CyclicBarrier 不同的是,CountdownLatch 不能重新使用。
9) Java內存模型是什么?
Java內存模型規定和指引Java程序在不同的內存架構、CPU和操作系統間有確定性地行為。它在多線(xiàn)程的情況下尤其重要。Java內存模型對一 個(gè)線(xiàn)程所做的變動(dòng)能被其它線(xiàn)程可見(jiàn)提供了保證,它們之間是先行發(fā)生了關(guān)系。這個(gè)關(guān)系定義了一些規則讓程序員在并發(fā)編程時(shí)思路更清晰。比如,先行發(fā)生了關(guān)系確保 了:
線(xiàn)程內的代碼能夠按先后順序執行,這被稱(chēng)為程序次序規則。
對于同一個(gè)鎖,一個(gè)解鎖操作一定要發(fā)生在時(shí)間上后發(fā)生的另一個(gè)鎖定操作之前,也叫做管程鎖定規則。
前一個(gè)對volatile的寫(xiě)操作在后一個(gè)volatile的讀操作之前,也叫volatile變量規則。
一個(gè)線(xiàn)程內的任何操作必需在這個(gè)線(xiàn)程的start()調用之后,也叫作線(xiàn)程啟動(dòng)規則。
一個(gè)線(xiàn)程的所有操作都會(huì )在線(xiàn)程終止之前,線(xiàn)程終止規則。
一個(gè)對象的終結操作必需在這個(gè)對象構造完成之后,也叫對象終結規則。
可傳遞性
10) Java中的volatile 變量是什么?
volatile是一個(gè)特殊的修飾符,只有成員變量才能使用它。在Java并發(fā)程序缺少同步類(lèi)的情況下,多線(xiàn)程對成員變量的操作對其它線(xiàn)程是透明的。volatile變量可以保證下一個(gè)讀取操作會(huì )在前一個(gè)寫(xiě)操作之后發(fā)生,就是上一題的volatile變量規則。
11) 什么是線(xiàn)程安全?Vector是一個(gè)線(xiàn)程安全類(lèi)嗎?
如果你的代碼所在的進(jìn)程中有多個(gè)線(xiàn)程在同時(shí)運行,而這些線(xiàn)程可能會(huì )同時(shí)運行這段代碼。如果每次運行結果和單線(xiàn)程運行的結果是一樣的,而且其他的變量 的值也和預期的是一樣的,就是線(xiàn)程安全的。一個(gè)線(xiàn)程安全的計數器類(lèi)的同一個(gè)實(shí)例對象在被多個(gè)線(xiàn)程使用的情況下也不會(huì )出現計算失誤。很顯然你可以將集合類(lèi)分 成兩組,線(xiàn)程安全和非線(xiàn)程安全的。Vector 是用同步方法來(lái)實(shí)現線(xiàn)程安全的, 而和它相似的ArrayList不是線(xiàn)程安全的。
12) Java中什么是競態(tài)條件? 舉個(gè)例子說(shuō)明。
競態(tài)條件會(huì )導致程序在并發(fā)情況下出現一些bugs。多線(xiàn)程對一些資源的競爭的時(shí)候就會(huì )產(chǎn)生競態(tài)條件,如果首先要執行的程序競爭失敗排到后面執行了, 那么整個(gè)程序就會(huì )出現一些不確定的bugs。這種bugs很難發(fā)現而且會(huì )重復出現,因為線(xiàn)程間的隨機競爭。
13) Java中如何停止一個(gè)線(xiàn)程?
Java提供了很豐富的API但沒(méi)有為停止線(xiàn)程提供API。JDK 1。0本來(lái)有一些像stop(), suspend() 和 resume()的控制方法但是由于潛在的死鎖威脅因此在后續的JDK版本中他們被棄用了,之后Java API的設計者就沒(méi)有提供一個(gè)兼容且線(xiàn)程安全的方法來(lái)停止一個(gè)線(xiàn)程。當run() 或者 call() 方法執行完的時(shí)候線(xiàn)程會(huì )自動(dòng)結束,如果要手動(dòng)結束一個(gè)線(xiàn)程,你可以用volatile 布爾變量來(lái)退出run()方法的循環(huán)或者是取消任務(wù)來(lái)中斷線(xiàn)程。
14) 一個(gè)線(xiàn)程運行時(shí)發(fā)生異常會(huì )怎樣?
這是我在一次面試中遇到的一個(gè)很刁鉆的Java面試題, 簡(jiǎn)單的說(shuō),如果異常沒(méi)有被捕獲該線(xiàn)程將會(huì )停止執行。Thread。UncaughtExceptionHandler是用于處理未捕獲異常造成線(xiàn)程突然中 斷情況的一個(gè)內嵌接口。當一個(gè)未捕獲異常將造成線(xiàn)程中斷的時(shí)候JVM會(huì )使用Thread。getUncaughtExceptionHandler()來(lái) 查詢(xún)線(xiàn)程的UncaughtExceptionHandler并將線(xiàn)程和異常作為參數傳遞給handler的uncaughtException()方法 進(jìn)行處理。
15) 如何在兩個(gè)線(xiàn)程間共享數據?
你可以通過(guò)共享對象來(lái)實(shí)現這個(gè)目的,或者是使用像阻塞隊列這樣并發(fā)的數據結構。
。ㄉ婕暗皆趦蓚(gè)線(xiàn)程間共享對象)用wait和notify方法實(shí)現了生產(chǎn)者消費者模型。
16) Java中notify 和 notifyAll有什么區別?
這又是一個(gè)刁鉆的問(wèn)題,因為多線(xiàn)程可以等待單監控鎖,java API 的設計人員提供了一些方法當等待條件改變的時(shí)候通知它們,但是這些方法沒(méi)有完全實(shí)現。notify()方法不能喚醒某個(gè)具體的線(xiàn)程,所以只有一個(gè)線(xiàn)程在等 待的時(shí)候它才有用武之地。而notifyAll()喚醒所有線(xiàn)程并允許他們爭奪鎖確保了至少有一個(gè)線(xiàn)程能繼續運行。
17) 為什么wait, notify 和 notifyAll這些方法不在thread類(lèi)里面?
這是個(gè)設計相關(guān)的問(wèn)題,它考察的是面試者對現有系統和一些普遍存在但看起來(lái)不合理的事物的看法;卮疬@些問(wèn)題的時(shí)候,你要說(shuō)明為什么把這些方法放在 Object類(lèi)里是有意義的,還有不把它放在Thread類(lèi)里的原因。一個(gè)很明顯的原因是JAVA提供的'鎖是對象級的而不是線(xiàn)程級的,每個(gè)對象都有鎖,通 過(guò)線(xiàn)程獲得。如果線(xiàn)程需要等待某些鎖那么調用對象中的wait()方法就有意義了。如果wait()方法定義在Thread類(lèi)中,線(xiàn)程正在等待的是哪個(gè)鎖 就不明顯了。簡(jiǎn)單的說(shuō),由于wait,notify和notifyAll都是鎖級別的操作,所以把他們定義在Object類(lèi)中因為鎖屬于對象。
18) 什么是ThreadLocal變量?
ThreadLocal是Java里一種特殊的變量。每個(gè)線(xiàn)程都有一個(gè)ThreadLocal就是每個(gè)線(xiàn)程都擁有了自己獨立的一個(gè)變量,競爭條件被 徹底消除了。它是為創(chuàng )建代價(jià)高昂的對象獲取線(xiàn)程安全的好方法,比如你可以用ThreadLocal讓SimpleDateFormat變成線(xiàn)程安全的,因 為那個(gè)類(lèi)創(chuàng )建代價(jià)高昂且每次調用都需要創(chuàng )建不同的實(shí)例所以不值得在局部范圍使用它,如果為每個(gè)線(xiàn)程提供一個(gè)自己獨有的變量拷貝,將大大提高效率。首先,通 過(guò)復用減少了代價(jià)高昂的對象的創(chuàng )建個(gè)數。其次,你在沒(méi)有使用高代價(jià)的同步或者不變性的情況下獲得了線(xiàn)程安全。線(xiàn)程局部變量的另一個(gè)不錯的例子是 ThreadLocalRandom類(lèi),它在多線(xiàn)程環(huán)境中減少了創(chuàng )建代價(jià)高昂的Random對象的個(gè)數。
19) 什么是FutureTask?
在Java并發(fā)程序中FutureTask表示一個(gè)可以取消的異步運算。它有啟動(dòng)和取消運算、查詢(xún)運算是否完成和取回運算結果等方法。只有當運算完 成的時(shí)候結果才能取回,如果運算尚未完成get方法將會(huì )阻塞。一個(gè)FutureTask對象可以對調用了Callable和Runnable的對象進(jìn)行包 裝,由于FutureTask也是調用了Runnable接口所以它可以提交給Executor來(lái)執行。
20) Java中interrupted 和 isInterruptedd方法的區別?
interrupted() 和 isInterrupted()的主要區別是前者會(huì )將中斷狀態(tài)清除而后者不會(huì )。Java多線(xiàn)程的中斷機制是用內部標識來(lái)實(shí)現的,調用Thread。interrupt()來(lái)中斷一個(gè)線(xiàn)程就會(huì )設置中斷標識為true。當中斷線(xiàn)程調用靜態(tài)方法Thread。interrupted()來(lái) 檢查中斷狀態(tài)時(shí),中斷狀態(tài)會(huì )被清零。而非靜態(tài)方法isInterrupted()用來(lái)查詢(xún)其它線(xiàn)程的中斷狀態(tài)且不會(huì )改變中斷狀態(tài)標識。簡(jiǎn)單的說(shuō)就是任何拋 出InterruptedException異常的方法都會(huì )將中斷狀態(tài)清零。無(wú)論如何,一個(gè)線(xiàn)程的中斷狀態(tài)有有可能被其它線(xiàn)程調用中斷來(lái)改變。
21) 為什么wait和notify方法要在同步塊中調用?
主要是因為Java API強制要求這樣做,如果你不這么做,你的代碼會(huì )拋出IllegalMonitorStateException異常。還有一個(gè)原因是為了避免wait和notify之間產(chǎn)生競態(tài)條件。
22) 為什么你應該在循環(huán)中檢查等待條件?
處于等待狀態(tài)的線(xiàn)程可能會(huì )收到錯誤警報和偽喚醒,如果不在循環(huán)中檢查等待條件,程序就會(huì )在沒(méi)有滿(mǎn)足結束條件的情況下退出。因此,當一個(gè)等待線(xiàn)程醒來(lái) 時(shí),不能認為它原來(lái)的等待狀態(tài)仍然是有效的,在notify()方法調用之后和等待線(xiàn)程醒來(lái)之前這段時(shí)間它可能會(huì )改變。
23) Java中的同步集合與并發(fā)集合有什么區別?
同步集合與并發(fā)集合都為多線(xiàn)程和并發(fā)提供了合適的線(xiàn)程安全的集合,不過(guò)并發(fā)集合的可擴展性更高。在Java1。5之前程序員們只有同步集合來(lái)用且在 多線(xiàn)程并發(fā)的時(shí)候會(huì )導致?tīng)幱,阻礙了系統的擴展性。Java5介紹了并發(fā)集合像ConcurrentHashMap,不僅提供線(xiàn)程安全還用鎖分離和內部分 區等現代技術(shù)提高了可擴展性。
24) Java中堆和棧有什么不同?
為什么把這個(gè)問(wèn)題歸類(lèi)在多線(xiàn)程和并發(fā)面試題里?因為棧是一塊和線(xiàn)程緊密相關(guān)的內存區域。每個(gè)線(xiàn)程都有自己的棧內存,用于存儲本地變量,方法參數和棧 調用,一個(gè)線(xiàn)程中存儲的變量對其它線(xiàn)程是不可見(jiàn)的。而堆是所有線(xiàn)程共享的一片公用內存區域。對象都在堆里創(chuàng )建,為了提升效率線(xiàn)程會(huì )從堆中弄一個(gè)緩存到自己 的棧,如果多個(gè)線(xiàn)程使用該變量就可能引發(fā)問(wèn)題,這時(shí)volatile 變量就可以發(fā)揮作用了,它要求線(xiàn)程從主存中讀取變量的值。
25) 什么是線(xiàn)程池? 為什么要使用它?
創(chuàng )建線(xiàn)程要花費昂貴的資源和時(shí)間,如果任務(wù)來(lái)了才創(chuàng )建線(xiàn)程那么響應時(shí)間會(huì )變長(cháng),而且一個(gè)進(jìn)程能創(chuàng )建的線(xiàn)程數有限。為了避免這些問(wèn)題,在程序啟動(dòng)的時(shí) 候就創(chuàng )建若干線(xiàn)程來(lái)響應處理,它們被稱(chēng)為線(xiàn)程池,里面的線(xiàn)程叫工作線(xiàn)程。從JDK1。5開(kāi)始,Java API提供了Executor框架讓你可以創(chuàng )建不同的線(xiàn)程池。比如單線(xiàn)程池,每次處理一個(gè)任務(wù);數目固定的線(xiàn)程池或者是緩存線(xiàn)程池(一個(gè)適合很多生存期短 的任務(wù)的程序的可擴展線(xiàn)程池)。
【精選Java線(xiàn)程面試題】相關(guān)文章:
java多線(xiàn)程面試題201711-07
Java線(xiàn)程同步的方法09-27
華為Java面試題精選10-24
構建多線(xiàn)程Java應用程序09-21