多線程技術(shù)在互聯(lián)網(wǎng)技術(shù)方面使用如此廣泛陌知,幾乎所有的后端技術(shù)面試官都要在并發(fā)編程的使用和原理方面對小伙伴們進(jìn)行各種刁難。作為一名在互聯(lián)網(wǎng)技術(shù)行業(yè)打擊過成百上千名【請允許我夸張一下】的資深技術(shù)面試官掖肋,看過了無數(shù)落寞的身影失望的離開仆葡,略感愧疚,故獻(xiàn)上此文志笼,希望各位讀者以后面試勢如破竹沿盅,永無失敗纫溃!
覺得文章對你有幫助的話嗡呼,可以點贊關(guān)注一下,給作者一點小鼓勵皇耗。
什么是線程?
線程是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位揍很,它被包含在進(jìn)程之中郎楼,是進(jìn)程中的實際運(yùn)作單位,可以使用多線程對進(jìn)行運(yùn)算提速窒悔。
比如呜袁,如果一個線程完成一個任務(wù)要100毫秒,那么用十個線程完成改任務(wù)只需10毫秒
什么是多線程简珠?優(yōu)缺點阶界?
什么是多線程?
多線程:是指從軟件或者硬件上實現(xiàn)多個線程的并發(fā)技術(shù)聋庵。
多線程的好處:
1.使用多線程可以把程序中占據(jù)時間長的任務(wù)放到后臺去處理膘融,如圖片、視屏的下載
2.發(fā)揮多核處理器的優(yōu)勢祭玉,并發(fā)執(zhí)行讓系統(tǒng)運(yùn)行的更快氧映、更流暢,用戶體驗更好
多線程的缺點:
1.大量的線程降低代碼的可讀性脱货;
2.更多的線程需要更多的內(nèi)存空間
3.當(dāng)多個線程對同一個資源出現(xiàn)爭奪時候要注意線程安全的問題岛都。
線程的五個狀態(tài)(五種狀態(tài),創(chuàng)建振峻、就緒臼疫、運(yùn)行、阻塞和死亡)?
線程通常都有五種狀態(tài)扣孟,創(chuàng)建烫堤、就緒、運(yùn)行、阻塞和死亡塔逃。
第一是創(chuàng)建狀態(tài)讯壶。在生成線程對象,并沒有調(diào)用該對象的start方法湾盗,這是線程處于創(chuàng)建狀態(tài)伏蚊。
第二是就緒狀態(tài)。當(dāng)調(diào)用了線程對象的start方法之后格粪,該線程就進(jìn)入了就緒狀態(tài)躏吊,但是此時線程調(diào)度程序還沒有把該線程設(shè)置為當(dāng)前線程,此時處于就緒狀態(tài)帐萎。在線程運(yùn)行之后,從等待或者睡眠中回來之后疆导,也會處于就緒狀態(tài)赁项。
第三是運(yùn)行狀態(tài)。線程調(diào)度程序?qū)⑻幱诰途w狀態(tài)的線程設(shè)置為當(dāng)前線程澈段,此時線程就進(jìn)入了運(yùn)行狀態(tài)悠菜,開始運(yùn)行run函數(shù)當(dāng)中的代碼。
第四是阻塞狀態(tài)败富。線程正在運(yùn)行的時候悔醋,被暫停,通常是為了等待某個時間的發(fā)生(比如說某項資源就緒)之后再繼續(xù)運(yùn)行兽叮。sleep,suspend芬骄,wait等方法都可以導(dǎo)致線程阻塞。
第五是死亡狀態(tài)鹦聪。如果一個線程的run方法執(zhí)行結(jié)束或者調(diào)用stop方法后账阻,該線程就會死亡。對于已經(jīng)死亡的線程椎麦,無法再使用start方法令其進(jìn)入就緒
什么是CAS宰僧?
CAS(compare and swap)的縮寫,中文翻譯成比較并交換观挎。
CAS 不通過JVM,直接利用java本地方 JNI(Java Native Interface為JAVA本地調(diào)用),直接調(diào)用CPU 的cmpxchg(是匯編指令)指令琴儿。
利用CPU的CAS指令,同時借助JNI來完成Java的非阻塞算法,實現(xiàn)原子操作嘁捷。其它原子操作都是利用類似的特性完成的造成。
整個java.util.concurrent都是建立在CAS之上的,因此對于synchronized阻塞算法雄嚣,J.U.C在性能上有了很大的提升晒屎。
CAS是項樂觀鎖技術(shù)喘蟆,當(dāng)多個線程嘗試使用CAS同時更新同一個變量時,只有其中一個線程能更新變量的值鼓鲁,而其它線程都失敗蕴轨,失敗的線程并不會被掛起,而是被告知這次競爭中失敗骇吭,并可以再次嘗試橙弱。
CAS應(yīng)用
CAS有3個操作數(shù),內(nèi)存值V燥狰,舊的預(yù)期值A(chǔ)棘脐,要修改的新值B。當(dāng)且僅當(dāng)預(yù)期值A(chǔ)和內(nèi)存值V相同時龙致,將內(nèi)存值V修改為B蛀缝,否則什么都不做。
CAS優(yōu)點
確保對內(nèi)存的讀-改-寫操作都是原子操作執(zhí)行
CAS缺點
CAS雖然很高效的解決原子操作目代,但是CAS仍然存在三大問題屈梁。ABA問題,循環(huán)時間長開銷大和只能保證一個共享變量的原子操作
什么是AQS榛了?
AbstractQueuedSynchronizer簡稱AQS俘闯,是一個用于構(gòu)建鎖和同步容器的框架。事實上concurrent包內(nèi)許多類都是基于AQS構(gòu)建忽冻,例如ReentrantLock,Semaphore此疹,CountDownLatch僧诚,ReentrantReadWriteLock,FutureTask等蝗碎。AQS解決了在實現(xiàn)同步容器時設(shè)計的大量細(xì)節(jié)問題湖笨。
AQS使用一個FIFO的隊列表示排隊等待鎖的線程,隊列頭節(jié)點稱作“哨兵節(jié)點”或者“啞節(jié)點”蹦骑,它不與任何線程關(guān)聯(lián)慈省。其他的節(jié)點與等待線程關(guān)聯(lián),每個節(jié)點維護(hù)一個等待狀態(tài)waitStatus眠菇。
什么是樂觀鎖和悲觀鎖边败?
悲觀鎖
Java在JDK1.5之前都是靠synchronized關(guān)鍵字保證同步的,這種通過使用一致的鎖定協(xié)議來協(xié)調(diào)對共享狀態(tài)的訪問捎废,可以確保無論哪個線程持有共享變量的鎖笑窜,都采用獨占的方式來訪問這些變量。獨占鎖其實就是一種悲觀鎖登疗,所以可以說synchronized是悲觀鎖排截。
樂觀鎖
樂觀鎖( Optimistic Locking)其實是一種思想嫌蚤。相對悲觀鎖而言,樂觀鎖假設(shè)認(rèn)為數(shù)據(jù)一般情況下不會造成沖突断傲,所以在數(shù)據(jù)進(jìn)行提交更新的時候脱吱,才會正式對數(shù)據(jù)的沖突與否進(jìn)行檢測,如果發(fā)現(xiàn)沖突了认罩,則讓返回用戶錯誤的信息箱蝠,讓用戶決定如何去做。
并發(fā)編程(concurrency)并行編程(parallellism)有什么區(qū)別猜年?
并發(fā)(concurrency)和并行(parallellism)是:
解釋一:并行是指兩個或者多個事件在同一時刻發(fā)生抡锈;而并發(fā)是指兩個或多個事件在同一時間間隔發(fā)生。
解釋二:并行是在不同實體上的多個事件乔外,并發(fā)是在同一實體上的多個事件床三。
解釋三:在一臺處理器上“同時”處理多個任務(wù),在多臺處理器上同時處理多個任務(wù)杨幼。如hadoop分布式集群
所以并發(fā)編程的目標(biāo)是充分的利用處理器的每一個核撇簿,以達(dá)到最高的處理性能。
想要了解更多多線程知識點的差购,可以加群650385180四瘫,多線程的學(xué)習(xí)資料以及多線程面試題匯總都在群的共享區(qū)供大家免費(fèi)下載.
怎么喚醒一個阻塞的線程?
如果線程是因為調(diào)用了wait()、sleep()或者join()方法而導(dǎo)致的阻塞欲逃,可以中斷線程找蜜,并且通過拋出InterruptedException來喚醒它;如果線程遇到了IO阻塞稳析,無能為力洗做,因為IO是操作系統(tǒng)實現(xiàn)的,Java代碼并沒有辦法直接接觸到操作系統(tǒng)彰居。
如何檢測死鎖诚纸?怎么預(yù)防死鎖?
所謂死鎖:是指兩個或兩個以上的進(jìn)程在執(zhí)行過程中陈惰,因爭奪資源而造成的一種互相等待的現(xiàn)象畦徘,若無外力作用,它們都將無法推進(jìn)下去抬闯。此時稱系統(tǒng)處于死鎖
通俗地講就是兩個或多個進(jìn)程被無限期地阻塞井辆、相互等待的一種狀態(tài)
死鎖產(chǎn)生的原因?
1.因競爭資源發(fā)生死鎖 現(xiàn)象:系統(tǒng)中供多個進(jìn)程共享的資源的數(shù)目不足以滿足全部進(jìn)程的需要時溶握,就會引起對諸資源的競爭而發(fā)生死鎖現(xiàn)象
2.進(jìn)程推進(jìn)順序不當(dāng)發(fā)生死鎖
死鎖的四個必要條件:
互斥條件:進(jìn)程對所分配到的資源不允許其他進(jìn)程進(jìn)行訪問掘剪,若其他進(jìn)程訪問該資源,只能等待奈虾,直至占有該資源的進(jìn)程使用完成后釋放該資源
請求和保持條件:進(jìn)程獲得一定的資源之后夺谁,又對其他資源發(fā)出請求廉赔,但是該資源可能被其他進(jìn)程占有,此事請求阻塞匾鸥,但又對自己獲得的資源保持不放
不可剝奪條件:是指進(jìn)程已獲得的資源蜡塌,在未完成使用之前,不可被剝奪勿负,只能在使用完后自己釋放
環(huán)路等待條件:是指進(jìn)程發(fā)生死鎖后馏艾,若干進(jìn)程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系
這四個條件是死鎖的必要條件,只要系統(tǒng)發(fā)生死鎖奴愉,這些條件必然成立琅摩,而只要上述條件之
一不滿足,就不會發(fā)生死鎖锭硼。
檢測死鎖
有兩個容器房资,一個用于保存線程正在請求的鎖,一個用于保存線程已經(jīng)持有的鎖檀头。每次加鎖之前都會做如下檢測:
檢測當(dāng)前正在請求的鎖是否已經(jīng)被其它線程持有,如果有轰异,則把那些線程找出來
遍歷第一步中返回的線程,檢查自己持有的鎖是否正被其中任何一個線程請求暑始,如果第二步返回真,表示出現(xiàn)了死鎖
死鎖的解除與預(yù)防:
理解了死鎖的原因搭独,尤其是產(chǎn)生死鎖的四個必要條件,就可以最大可能地避免廊镜、預(yù)防和
解除死鎖牙肝。
所以,在系統(tǒng)設(shè)計嗤朴、進(jìn)程調(diào)度等方面注意如何不讓這四個必要條件成立惊奇,如何確
定資源的合理分配算法,避免進(jìn)程永久占據(jù)系統(tǒng)資源播赁。
此外,也要防止進(jìn)程在處于等待狀態(tài)的情況下占用資源吼渡。因此容为,對資源的分配要給予合理的規(guī)劃。
想要了解更多多線程知識點的寺酪,可以加群650385180坎背,多線程的學(xué)習(xí)資料以及多線程面試題匯總都在群的共享區(qū)供大家免費(fèi)下載.
更多多線程面試題
1.什么是原子操作?在Java Concurrency API中有哪些原子類(atomic classes)寄雀?
2.什么是Executors框架得滤?
3.什么是阻塞隊列?如何使用阻塞隊列來實現(xiàn)生產(chǎn)者-消費(fèi)者模型盒犹?
4.什么是Callable和Future?
5.什么是FutureTask?
6.什么是同步容器和并發(fā)容器的實現(xiàn)懂更?
7.什么是多線程的上下文切換眨业?
8.ThreadLocal的設(shè)計理念與作用?
9. ThreadPool(線程池)用法與優(yōu)勢沮协?
10.加群:650385180獲取更多多線程知識點及面試題
11. Concurrent包里的其他東西:ArrayBlockingQueue龄捡、CountDownLatch等等。
12. synchronized和ReentrantLock的區(qū)別慷暂?
13. Semaphore有什么作用聘殖?
14. Java Concurrency API中的Lock接口(Lock interface)是什么?對比同步它有什么優(yōu)勢行瑞?
總結(jié)
關(guān)于Java多線程面試技術(shù)點的一些總結(jié)已經(jīng)寫完了奸腺,受限于我的視野,所以可能寫的不是很全面血久,大家要是有不同意見的突照,可以分享出來,一起交流洋魂,要是想深入了解多線程技術(shù)知識點的绷旗,可以加上面的群,希望可以幫助在這個行業(yè)發(fā)展的朋友和童鞋們副砍,在論壇博客等地方少花些時間找資料衔肢,把有限的時間,真正花在學(xué)習(xí)上豁翎。