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