更新時(shí)間:2020-10-15 17:21:59 來源:動(dòng)力節(jié)點(diǎn) 瀏覽2093次
CPU是電腦的核心所在,如果能提高CPU的運(yùn)行效率,相應(yīng)的也能提高一個(gè)程序的運(yùn)行效率。采用多線程的方式就可以提高CPU的使用率,可以同時(shí)完成幾件事情而互不干擾,在java語(yǔ)言中,學(xué)習(xí)好多線程無疑是至關(guān)重要的,多線程面試題在java程序員的面試中是常出現(xiàn)的,下面總結(jié)了一些常考的最新多線程面試題,大家可以一起來學(xué)習(xí)。
1、說明類java.lang.ThreadLocal的作用和原理是什么?
答:作用:要編寫一個(gè)多線程安全(Thread-safe)的程序是困難的,為了讓線程共享資源,必須小心地對(duì)共享資源進(jìn)行同步,同步帶來一定的效能延遲,而另一方面,在處理同步的時(shí)候,又要注意對(duì)象的鎖定與釋放,避免產(chǎn)生死結(jié),種種因素都使得編寫多線程程序變得困難。嘗試從另一個(gè)角度來思考多線程共享資源的問題,既然共享資源這么困難,那么就干脆不要共享,何不為每個(gè)線程創(chuàng)造一個(gè)資源的復(fù)本。將每一個(gè)線程存取數(shù)據(jù)的行為加以隔離,實(shí)現(xiàn)的方法就是給予每個(gè)線程一個(gè)特定空間來保管該線程所獨(dú)享的資源。
ThreadLocal的原理:ThreadLocal做到為每一個(gè)線程維護(hù)變量的副本,實(shí)現(xiàn)的思路很簡(jiǎn)單,在ThreadLocal類中有一個(gè)Map,用于存儲(chǔ)每一個(gè)線程的變量的副本。
2、在java中怎么實(shí)現(xiàn)多線程?描述線程狀態(tài)的變化過程。
答:當(dāng)多個(gè)線程訪問同一個(gè)數(shù)據(jù)時(shí),容易出現(xiàn)線程安全問題,需要某種方式來確保資源在某一時(shí)刻只被一個(gè)線程使用。需要讓線程同步,保證數(shù)據(jù)安全線程同步的實(shí)現(xiàn)方案: 同步代碼塊和同步方法,均需要使用synchronized關(guān)鍵字。
同步代碼塊:public void makeWithdrawal(int amt) {
synchronized (acct) { }
}
同步方法:public synchronized void makeWithdrawal(int amt) { }
線程同步的好處:解決了線程安全問題;線程同步的缺點(diǎn):性能下降,可能會(huì)帶來死鎖。
3、樂觀鎖與悲觀鎖各是什么?
答:悲觀鎖(Pessimistic Lock), 顧名思義,就是很悲觀,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人會(huì)修改,所以每次在拿數(shù)據(jù)的時(shí)候都會(huì)上鎖,這樣別人想拿這個(gè)數(shù)據(jù)就會(huì)block直到它拿到鎖。傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)里邊就用到了很多這種鎖機(jī)制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。
樂觀鎖(Optimistic Lock), 顧名思義,就是很樂觀,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人不會(huì)修改,所以不會(huì)上鎖,但是在更新的時(shí)候會(huì)判斷一下在此期間別人有沒有去更新這個(gè)數(shù)據(jù),可以使用版本號(hào)等機(jī)制。樂觀鎖適用于多讀的應(yīng)用類型,這樣可以提高吞吐量,像數(shù)據(jù)庫(kù)如果提供類似于write_condition機(jī)制的其實(shí)都是提供的樂觀鎖。
4、在多線程編程里,wait方法的調(diào)用方式是怎樣的?
答:wait方法是線程通信的方法之一,必須用在 synchronized方法或者synchronized代碼塊中,否則會(huì)拋出異常,這就涉及到一個(gè)“鎖”的概念,而wait方法必須使用上鎖的對(duì)象來調(diào)用,從而持有該對(duì)象的鎖進(jìn)入線程等待狀態(tài),直到使用該上鎖的對(duì)象調(diào)用notify或者notifyAll方法來喚醒之前進(jìn)入等待的線程,以釋放持有的鎖。
5、volatile關(guān)鍵字是否能保證線程安全?
答:不能。雖然volatile提供了同步的機(jī)制,但是知識(shí)一種弱的同步機(jī)制,如需要強(qiáng)線程安全,還需要使用synchronized。Java語(yǔ)言提供了一種稍弱的同步機(jī)制,即volatile變量,用來確保將變量的更新操作通知到其他線程。當(dāng)把變量聲明為volatile類型后,編譯器與運(yùn)行時(shí)都會(huì)注意到這個(gè)變量是共享的,因此不會(huì)將該變量上的操作與其他內(nèi)存操作一起重排序。volatile變量不會(huì)被緩存在寄存器或者對(duì)其他處理器不可見的地方,因此在讀取volatile類型的變量時(shí)總會(huì)返回最新寫入的值。
6、創(chuàng)建線程的有哪些方式?
答:(1)繼承Thread類創(chuàng)建線程類;(2)通過Runnable接口創(chuàng)建線程類;(3)通過Callable和Future創(chuàng)建線程;(4)通過線程池創(chuàng)建。
7、線程池的優(yōu)點(diǎn)都有什么?
答:(1)重用存在的線程,減少對(duì)象創(chuàng)建銷毀的開銷;(2)可有效的控制最大并發(fā)線程數(shù),提高系統(tǒng)資源的使用率,同時(shí)避免過多資源競(jìng)爭(zhēng),避免堵塞;(3)提供定時(shí)執(zhí)行、定期執(zhí)行、單線程、并發(fā)數(shù)控制等功能。
8、synchronized和ReentrantLock的區(qū)別?
答:synchronized是和if、else、for、while一樣的關(guān)鍵字,ReentrantLock是類,這是二者的本質(zhì)區(qū)別。既然ReentrantLock是類,那么它就提供了比synchronized更多更靈活的特性,可以被繼承、可以有方法、可以有各種各樣的類變量,ReentrantLock比synchronized的擴(kuò)展性體現(xiàn)在幾點(diǎn)上:
(1)ReentrantLock可以對(duì)獲取鎖的等待時(shí)間進(jìn)行設(shè)置,這樣就避免了死鎖;
(2)ReentrantLock可以獲取各種鎖的信息;
(3)ReentrantLock可以靈活地實(shí)現(xiàn)多路通知。
9、線程的調(diào)度策略都有什么?
答:線程調(diào)度器選擇優(yōu)先級(jí)最高的線程運(yùn)行,但是,如果發(fā)生以下情況,就會(huì)終止線程的運(yùn)行:(1)線程體中調(diào)用了yield方法讓出了對(duì)cpu的占用權(quán)利;(2)線程體中調(diào)用了sleep方法使線程進(jìn)入睡眠狀態(tài);(3)線程由于IO操作受到阻塞;(4)另外一個(gè)更高優(yōu)先級(jí)線程出現(xiàn);(5)在支持時(shí)間片的系統(tǒng)中,該線程的時(shí)間片用完。
10、死鎖的原因?
答:(1)是多個(gè)線程涉及到多個(gè)鎖,這些鎖存在著交叉,所以可能會(huì)導(dǎo)致了一個(gè)鎖依賴的閉環(huán)。例如:線程在獲得了鎖A并且沒有釋放的情況下去申請(qǐng)鎖B,這時(shí),另一個(gè)線程已經(jīng)獲得了鎖B,在釋放鎖B之前又要先獲得鎖A,因此閉環(huán)發(fā)生,陷入死鎖循環(huán)。
(2)默認(rèn)的鎖申請(qǐng)操作是阻塞的。
所以要避免死鎖,就要在一遇到多個(gè)對(duì)象鎖交叉的情況,就要仔細(xì)審查這幾個(gè)對(duì)象的類中的所有方法,是否存在著導(dǎo)致鎖依賴的環(huán)路的可能性。總之是盡量避免在一個(gè)同步方法中調(diào)用其它對(duì)象的延時(shí)方法和同步方法。
11、怎么喚醒一個(gè)阻塞的線程?
答:如果線程是因?yàn)檎{(diào)用了wait()、sleep()或者join()方法而導(dǎo)致的阻塞,可以中斷線程,并且通過拋出InterruptedException來喚醒它;如果線程遇到了IO阻塞,無能為力,因?yàn)镮O是操作系統(tǒng)實(shí)現(xiàn)的,Java代碼并沒有辦法直接接觸到操作系統(tǒng)。
12、不可變對(duì)象對(duì)多線程有什么幫助?
答:不可變對(duì)象保證了對(duì)象的內(nèi)存可見性,對(duì)不可變對(duì)象的讀取不需要進(jìn)行額外的同步手段,提升了代碼執(zhí)行效率。
13、什么是多線程的上下文切換?
答:多線程的上下文切換是指CPU控制權(quán)由一個(gè)已經(jīng)正在運(yùn)行的線程切換到另外一個(gè)就緒并等待獲取CPU執(zhí)行權(quán)的線程的過程。
14、同步和異步有何異同?
答:(1)如果數(shù)據(jù)將在線程間共享。例如正在寫的數(shù)據(jù)以后可能被另一個(gè)線程讀到,或者正在讀的數(shù)據(jù)可能已經(jīng)被另一個(gè)線程寫過了,那么這些數(shù)據(jù)就是共享數(shù)據(jù),必須進(jìn)行同步存取。
(2)當(dāng)應(yīng)用程序在對(duì)象上調(diào)用了一個(gè)需要花費(fèi)很長(zhǎng)時(shí)間來執(zhí)行的方法,并且不希望讓程序等待方法的返回時(shí),就應(yīng)該使用異步編程,在很多情況下采用異步途徑往往更有效率。
15、Java線程數(shù)過多會(huì)造成什么異常?
答:(1)線程的生命周期開銷非常高;(2)消耗過多的CPU資源。如果可運(yùn)行的線程數(shù)量多于可用處理器的數(shù)量,那么有線程將會(huì)被閑置。大量空閑的線程會(huì)占用許多內(nèi)存,給垃圾回收器帶來壓力,而且大量的線程在競(jìng)爭(zhēng)CPU資源時(shí)還將產(chǎn)生其他性能的開銷;(3)降低穩(wěn)定性。JVM在可創(chuàng)建線程的數(shù)量上存在一個(gè)限制,這個(gè)限制值將隨著平臺(tái)的不同而不同,并且承受著多個(gè)因素制約,包括JVM的啟動(dòng)參數(shù)、Thread構(gòu)造函數(shù)中請(qǐng)求棧的大小,以及底層操作系統(tǒng)對(duì)線程的限制等。如果破壞了這些限制,那么可能拋出OutOfMemoryError異常。
以上是今天整理的java多線程面試題的內(nèi)容,大家可以根據(jù)給出相應(yīng)的參考答案來學(xué)習(xí)。CPU要花同樣多的時(shí)間去完成所有的事情,但多線程可以讓CPU摻插地同時(shí)做多件事情,希望朋友們可以通過多線程編程教程來學(xué)習(xí)更多的java多線程的知識(shí)。
0基礎(chǔ) 0學(xué)費(fèi) 15天面授
有基礎(chǔ) 直達(dá)就業(yè)
業(yè)余時(shí)間 高薪轉(zhuǎn)行
工作1~3年,加薪神器
工作3~5年,晉升架構(gòu)
提交申請(qǐng)后,顧問老師會(huì)電話與您溝通安排學(xué)習(xí)
初級(jí) 202925
初級(jí) 203221
初級(jí) 202629
初級(jí) 203743