更新時間:2020-02-06 16:42:45 來源:動力節(jié)點 瀏覽2879次
進(jìn)程與線程的區(qū)別
進(jìn)程是資源分配的最小單位,線程是CPU調(diào)度的最小單位
所有與進(jìn)程相關(guān)的資源,都被記錄在PCB(進(jìn)程控制塊)中
進(jìn)程是搶占處理機(jī)的調(diào)度單位;線程屬于某個進(jìn)程,共享其資源
線程只由堆棧寄存器、程序計數(shù)器和TCB(線程控制塊)組成
總結(jié):
線程不能看做獨立應(yīng)用,而進(jìn)程可看做獨立應(yīng)用
進(jìn)程有獨立的地址空間,相互不影響,線程只是進(jìn)程的不同執(zhí)行路徑
線程沒有獨立的地址空間,多進(jìn)程的程序比多線程的程序健壯
進(jìn)程的開銷比線程大,切換代價高
Java進(jìn)程和線程的關(guān)系
Java對操作系統(tǒng)的功能進(jìn)行封裝,包括進(jìn)程和線程
運(yùn)行一個程序會產(chǎn)生一個進(jìn)程,進(jìn)程包含至少一個線程
每個進(jìn)程對應(yīng)一個JVM實例,多個線程共享JVM里的堆
Java采用單線程編程模型,程序會自動創(chuàng)建主線程
主線程可以創(chuàng)建子線程,原則上要后于子線程完成執(zhí)行
start和run的區(qū)別
調(diào)用start()方法會創(chuàng)建一個新的子線程并啟動
run()方法只是Thread的一個普通方法的調(diào)用(注:還是在主線程里面執(zhí)行)
Thread和Runnable
Thread是實現(xiàn)了Runnable接口的類,使得run支持多線程
publicclassThreadimplementsRunnable
因為類的單一繼承原則,推薦多使用Runnable接口
如何給run()方法傳參
實現(xiàn)方式有三種
構(gòu)造函數(shù)傳參
成員變量傳參
回調(diào)函數(shù)傳參
如何實現(xiàn)處理線程的返回值
實現(xiàn)的方式主要有三種:
主線程等待法
使用Thread類的join()阻塞當(dāng)前線程以等待子線程處理完畢
通過Callable接口實現(xiàn):通過FutureOr線程池獲取
Java線程的六個狀態(tài)
新建(New):創(chuàng)建后尚未啟動的線程的狀態(tài)
運(yùn)行(Runnable):包含Running和Ready
無限期等待(Waiting):不會被分配CPU執(zhí)行時間,需要顯示被喚醒
限期等待(TimedWaiting):在一定時間后會由系統(tǒng)自動喚醒
阻塞(Blocked):等待獲取排它鎖
結(jié)束(Terminated):已終止線程的狀態(tài),線程已經(jīng)結(jié)束執(zhí)行
Sleep和wait的區(qū)別
sleep是Thread的方法,wait是Object類中定義的方法
sleep()方法可以在任何地方使用
wait()方法只能在synchronized方法或synchronized塊中使用
Thread.sleep只會讓出CPU,不會導(dǎo)致鎖行為的改變
Object.wait不僅讓出CPU,還會釋放已經(jīng)占有的同步資源鎖
notify和notifyAll的區(qū)別
鎖池EntryList:假設(shè)線程A已經(jīng)獲得了某個對象(不是類)的鎖,而其他線程B,C想要調(diào)用這個對象的某個synchronized方法(或者塊),由于B,C線程在進(jìn)入對象的synchronized方法之前必須獲得該對象鎖的擁有權(quán),而恰巧該對象的鎖剛好被線程A所占用,此時B,C線程就會被阻塞,進(jìn)入一個地方去等待鎖的釋放,這個地方就是鎖池。
等待池WaitSet:假設(shè)線程A調(diào)用了某個對象的wait()方法,線程A就會釋放該對象的鎖,同時線程A就進(jìn)入到了該對象的等待池中,進(jìn)入到等待池中的線程不會去競爭該對象的鎖。
notifyAll會讓所有出于等待池WaitSet的線程全部進(jìn)入鎖池EntryList去競爭獲取鎖的機(jī)會
notify只會隨機(jī)選取一個處于等待池中的線程進(jìn)入鎖池去競爭獲取鎖的機(jī)會
Yield與join的區(qū)別
當(dāng)調(diào)用Thread.yeild()函數(shù)時,會給線程調(diào)度器一個當(dāng)前線程愿意讓出CPU使用的暗示,但是線程調(diào)度器可能會忽略這個暗示。并不會讓出當(dāng)前線程的鎖。
yield是一個靜態(tài)的原生(native)方法
yield不能保證是的當(dāng)前正在運(yùn)行的線程迅速轉(zhuǎn)換到可運(yùn)行的狀態(tài),僅能從運(yùn)行態(tài)轉(zhuǎn)換到可運(yùn)行態(tài),而不能是等待或阻塞。
join方法可以使得一個線程在另一個線程結(jié)束后再執(zhí)行。當(dāng)前線程將阻塞直到這個線程實例完成了再執(zhí)行。
join方法可設(shè)置超時,使得join()方法的影響在特定超時后無效,如,join(50)。注:join(0),并不是等待0秒,而是等待無限時間,等價join()。
-join方法必須在線程start()方法調(diào)用之后才有意義
join方法的原理,就是調(diào)用了相應(yīng)線程的wait方法
如何中斷線程
已經(jīng)被拋棄的方法:
通過調(diào)用stop()方法停止線層(原因:不安全,會釋放掉鎖)
通過調(diào)用suspend()和resume()方法
目前使用的方法:
調(diào)用interrput(),通知線程應(yīng)該中斷了:1.如果線程出于被阻塞的狀態(tài),那么線程將立即退出被阻塞狀態(tài),并拋出一個InterruputedException異常。2.如果線程出于正常的活動狀態(tài),那么會將該線程的中斷標(biāo)志設(shè)置為true。被設(shè)置中斷標(biāo)志的線程將繼續(xù)正常運(yùn)行,不受影響。
需要被調(diào)用的線程配合中斷:1.在正常運(yùn)行任務(wù)時,經(jīng)常檢查本線程的中斷標(biāo)志位,如果被設(shè)置了中斷標(biāo)志就自行停止線程。2.如果線程處于正常活動狀態(tài),那么會將該線程的中斷標(biāo)志設(shè)置為true。被設(shè)置中斷標(biāo)志的線程將繼續(xù)正常運(yùn)行,不受影響。
Synchronized
線程安全出現(xiàn)的原因:
存在共享數(shù)據(jù)(也稱為臨界資源)
存在多線程共同操作這些共享數(shù)據(jù)
解決線程安全的根本辦法:同一時刻有且只有一個線程在操作共享數(shù)據(jù),其他線程必須等到該線程處理完數(shù)據(jù)之后再對共享數(shù)據(jù)進(jìn)行操作,引入了互斥鎖
互斥鎖的特性:
互斥性:即在同一個時間只允許一個線程持有某個對象鎖,通過這種特性來實現(xiàn)多線程的協(xié)調(diào)機(jī)制,這樣在同一時間只有一個線程對需要同步的代碼塊(復(fù)合操作)進(jìn)行訪問。互斥性也成為操作的原子性。
可見性:必須確保在鎖被釋放之前,對共享變量所做的修改,對于隨后獲得該鎖的另一個線程是可見的(即在獲得鎖時應(yīng)獲得最新的共享變量的值),否則另一個線程可能是在本地緩存的某個副本上繼續(xù)操作,從而引起不一致性。
synchronized鎖的不是代碼,是對象。
根據(jù)獲取的鎖分類:
獲取對象鎖:1、同步代碼塊(synchronized(this),synchronized(類實例對象)),鎖是小括號()中的實例對象。2、同步非靜態(tài)方法(synchronizedmethod),鎖是當(dāng)前對象的實例對象。
獲取類鎖:1、同步代碼塊(synchronized(類.class)),鎖是小括號()中的類對象(class對象)。2、同步靜態(tài)方法(synchronizedstaticmethod),鎖是當(dāng)前對象的類對象(class對象)。
有線程訪問對象的同步代碼塊時,另外的線程可以訪問該對象的非同步代碼塊
若鎖住的是同一個對象,一個線程在訪問對象的同步代碼塊時,另一個線程訪問對象的同步方法,會被阻塞
類鎖和對象鎖互補(bǔ)干擾
synchronized底層實現(xiàn)原理:
Monitor:每個java對象天生自帶了一把看不見的鎖(c++實現(xiàn))
Monitor鎖的競爭、獲取與釋放
自旋鎖:緣由,1、許多情況下,共享數(shù)據(jù)的鎖定狀態(tài)持續(xù)時間較短,切換線程不值得。2、通過讓線程執(zhí)行忙循環(huán)等待鎖的釋放,不讓出CPU。3、若鎖被其他線程長時間占用,會帶來許多性能上的開銷
自適應(yīng)自旋鎖:1、自旋的次數(shù)不固定。2、由前一次在同一個鎖上的自旋時間及鎖的擁有者的狀態(tài)來決定
鎖消除:JIT編譯時,對運(yùn)行上下文進(jìn)行掃描,去除不可能存在競爭的鎖
鎖粗化:通過擴(kuò)大鎖的范圍,避免反復(fù)的加鎖和解鎖
鎖的內(nèi)存語義:
當(dāng)線程釋放鎖時,Java內(nèi)存模型會把該線程對應(yīng)的本地內(nèi)存中的共享變量刷新到主內(nèi)存中去;
而當(dāng)線程獲得鎖時,Java內(nèi)存模型會把該線程對應(yīng)的本地內(nèi)存置為無效,從而使得監(jiān)視器保護(hù)的臨界區(qū)代碼必須從主內(nèi)存中讀取共享變量。
synchronized的四種狀態(tài):
無鎖
偏向鎖:減少同一線程獲取鎖的代價,大多數(shù)情況下,鎖不存在多線程競爭,總是由同一線程多層次獲得。核心思想:如果一個線程獲得了鎖,那么鎖就進(jìn)入偏向模式,此時MarkWord的結(jié)構(gòu)也變?yōu)槠蜴i結(jié)構(gòu),當(dāng)該線程再次請求鎖時,無需任何同步操作,即獲取鎖的過程只需要檢查Markword的鎖標(biāo)記位為偏向鎖以及當(dāng)前線程Id等于Markword的ThreadId即可,這樣就省去了大量有關(guān)鎖申請的操作。不適合鎖競爭比較激烈的多線程場合
輕量級鎖:由偏向鎖升級來的,偏向鎖運(yùn)行在一個線程進(jìn)入同步塊的情況下,當(dāng)?shù)诙€線程加入鎖爭用的時候,偏向鎖就會升級為輕量級鎖。適應(yīng)場景:線程交替執(zhí)行同步代碼塊。若存在同一時間訪問同一鎖的情況,就導(dǎo)致輕量級鎖膨脹為重量級鎖
以上就是動力節(jié)點Java培訓(xùn)機(jī)構(gòu)小編介紹的“Java線程與多線程面試問答題”的內(nèi)容,希望對大家有幫助,如有疑問,請在線咨詢,有專業(yè)老師隨時為你服務(wù)。
相關(guān)推薦
相關(guān)閱讀
初級 202925
初級 203221
初級 202629
初級 203743