求求大廠給個Offer:多線程基礎(chǔ)面試題
這是三歪第393篇原創(chuàng)
《求求大廠給個Offer》連載第四篇
我,三歪,最近開始寫面試系列。我給這個面試系列取了一個名字,叫做《求求大廠給個Offer》
前面已經(jīng)寫了三篇了,主要的內(nèi)容包含集合和簡歷,喜歡看的同學在微信公眾號下回復(fù)「面試」即可觀看。
所以這篇文章叫做《求求大廠給個Offer:多線程基礎(chǔ)面試題》
接下來就開始吧。

面試現(xiàn)場
面試官:“聽說你上次還差一點點在看數(shù)才及格,但你的表現(xiàn)我覺得還是可以的,破格再來面試一輪唄,這次我們來聊聊多線程吧。”

三歪:“嗯嗯,大多數(shù)人都還是比較喜歡看的,謝謝面試官給予我多一次的機會。”
面試官:“首先你來講講進程和線程的區(qū)別吧?”
三歪:“進程是系統(tǒng)進行資源分配和調(diào)度的獨立單位,每一個進程都有它自己的內(nèi)存空間和系統(tǒng)資源。進程實現(xiàn)多處理機環(huán)境下的進程調(diào)度,分派,切換時,都需要花費較大的時間和空間開銷。為了提高系統(tǒng)的執(zhí)行效率,減少處理機的空轉(zhuǎn)時間和調(diào)度切換的時間,以及便于系統(tǒng)管理,所以有了線程,線程取代了進程了調(diào)度的基本功能”

三歪:“簡單來說:進程作為資源分配的基本單位,線程作為資源調(diào)度的基本單位”

面試官:“那我們?yōu)槭裁匆枚嗑€程呢?你平時工作中用得多嗎?”
三歪:“使用多線程最主要的原因是提高系統(tǒng)的資源利用率。現(xiàn)在CPU基本都是多核的,如果你只用單線程,那就是只用到了一個核心,其他的核心就相當于空閑在那里了。
三歪:“在平時工作中多線程是隨時都可見的。比如說,我們系統(tǒng)Web服務(wù)器用的是Tomcat,Tomcat處理每一個請求都會從線程連接池里邊用一個線程去處理。又比如說,我們用連接數(shù)據(jù)庫會用對應(yīng)的連接池,比如Druid/C3P0/DBCP等等,這些都用了多線程的。”

三歪:“除了上面這些框架已經(jīng)幫我們屏蔽掉「手寫」多線程的問題,在我本身的系統(tǒng)也會用到多線程的。比如說:現(xiàn)在要跑一個定時任務(wù),該任務(wù)的鏈路執(zhí)行時間和過程都非常長,我們這邊就用一個線程池將該定時任務(wù)的請求進行處理,這樣做的好處就是可以及時返回結(jié)果給調(diào)用方,能夠提高系統(tǒng)的吞吐量。“
//?請求直接交給線程池來處理
public?void?push(PushParam?pushParam)?{
??try?{
????pushServiceThreadExecutor.submit(()?->?{
??????handler(pushParam);
????});
??}?catch?(Exception?e)?{
????logger.error("pushServiceThreadExecutor?error,?exception{}:",?e);
??}
}
三歪:”還有就是我的系統(tǒng)中用了很多生產(chǎn)者與消費者模式,會用多個線程去消費隊列的消息,來提高并發(fā)度“
面試官:”要不你來講講什么是線程安全?“

三歪:”在我的理解下,在Java世界里邊,所謂線程安全就是多個線程去執(zhí)行某類,這個類始終能表現(xiàn)出正確的行為,那么這個類就是線程安全的。比如我有一個count變量,在service方法不斷的累加這個count變量。
public?class?UnsafeCountingServlet?extends?GenericServlet?implements?Servlet?{
????private?long?count?=?0;
????public?long?getCount()?{
????????return?count;
????}
????public?void?service(ServletRequest?servletRequest,?ServletResponse?servletResponse)?throws?ServletException,?IOException?{
????????++count;
????????//?To?something?else...
????}
}
三歪:”假設(shè)相同的條件下,count變量每次執(zhí)行的結(jié)果都是相同,那我們就可以說是線程安全的。顯然上面的代碼肯定不是線程安全的。“
三歪:”只要用到多線程,我們肯定得考慮線程安全的問題。“
面試官:”那你是怎么解決線程安全問題的呢?“
三歪:”其實大部分時間我們在代碼里邊都沒有顯式去處理線程安全問題,因為這大部分都由框架所做了。正如上面提到的Tomcat、Druid、SpringMVC等等。“
三歪:”很多時候,我們判斷是否要處理線程安全問題,就看有沒有多個線程同時訪問一個共享變量。像SpringMVC這種,我們?nèi)粘i_發(fā)時,不涉及到操作同一個成員變量,那我們就很少需要考慮線程安全問題。我個人解決線程安全問題的思路有以下:“
能不能保證操作的原子性,考慮atomic包下的類夠不夠我們使用。
能不能保證操作的可見性,考慮
volatile關(guān)鍵字夠不夠我們使用如果涉及到對線程的控制(比如一次能使用多少個線程,當前線程觸發(fā)的條件是否依賴其他線程的結(jié)果),考慮CountDownLatch/Semaphore等等。
如果是集合,考慮
java.util.concurrent包下的集合類。如果synchronized無法滿足,考慮lock包下的類
....
三歪:”總的來說,就是先判斷有沒有線程安全問題,如果存在則根據(jù)具體的情況去判斷使用什么方式去處理線程安全的問題。雖然synchronized很牛逼,但無腦使用synchronized會影響我們程序的性能的。“
面試官:”死鎖你了解嗎?什么情況會造成死鎖?要是你能給我講清楚死鎖,我就錄取你了“
三歪:”要是你錄取我,我就給你講清楚死鎖“
面試官&三歪:”......“
三歪:”造成死鎖的原因可以簡單概括為:當前線程擁有其他線程需要的資源,當前線程等待其他線程已擁有的資源,都不放棄自己擁有的資源。避免死鎖的方式一般有以下方案:
固定加鎖的順序“,比如我們可以使用Hash值的大小來確定加鎖的先后 盡可能縮減加鎖的范圍,等到操作共享變量的時候才加鎖。 使用可釋放的定時鎖(一段時間申請不到鎖的權(quán)限了,直接釋放掉)
三歪:”面試官,你覺得我講得怎么樣?“
面試官:”說實話,還是差點東西。多線程顯然不單單這么點東西,你也別想著這么簡單我就放你通過了,不過今天的面試時間也到這里就結(jié)束了。這樣吧,你這次要是能拿到100個在看,我再約你下一輪,再好好面你Java鎖相關(guān)的知識,這次沒有100個在看,面試就結(jié)束了。“
題外話
針對這次的面試可能你想了解更多的細節(jié),可以在公眾號后臺回復(fù)「多線程」即可獲取我之前寫的原創(chuàng)文章,里邊有更詳細的講解,不怕面試官深問!
原創(chuàng)電子書原創(chuàng)思維導圖
掃碼或微信搜 Java3y?回復(fù)「888」領(lǐng)取1000+頁原創(chuàng)電子書和思維導圖。
![]() |
|





