Java面試老失利?必定是多線程面試答案有問題!

十一、下面的代碼,實際上有幾個線程在運行:編程

  

cfedc1a56ecb4ffeb5f7df0708bee65e.png

兩個:線程t和main()方法(主線程)。安全

 

 

十二、線程的幾種狀態服務器

1.線程一般有五種狀態,建立,就緒,運行、阻塞和死亡狀態。多線程

2.阻塞的狀況又分爲三種:線程

  • (1)、等待阻塞:運行的線程執行wait()方法,該線程會釋放佔用的全部資源,JVM會把該線程放入「等待池」中。進入這個狀態後,是不能自動喚醒的,必須依靠其餘線程調用notify()或notifyAll()方法才能被喚醒,wait是object類的方法對象

  • (2)、同步阻塞:運行的線程在獲取對象的同步鎖時,若該同步鎖被別的線程佔用,則JVM會把該線程放入「鎖池」中。blog

  • (3)、其餘阻塞:運行的線程執行sleep()或join()方法,或者發出了I/O請求時,JVM會把該線程置爲阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程從新轉入就緒狀態。sleep是Thread類的方法生命週期

  •  

  • 1.新建狀態(New):新建立了一個線程對象。資源

  • 2.就緒狀態(Runnable):線程對象建立後,其餘線程調用了該對象的start()方法。該狀態的線程位於可運行線程池中,變得可運行,等待獲取CPU的使用權。同步

  • 3. 運行狀態(Running):就緒狀態的線程獲取了CPU,執行程序代碼。

  • 4.阻塞狀態(Blocked):阻塞狀態是線程由於某種緣由放棄CPU使用權,暫時中止運行。直到線程進入就緒狀態,纔有機會轉到運行狀態。

  • 5.死亡狀態(Dead):線程執行完了或者因異常退出了run()方法,該線程結束生命週期。

 

 

1三、說說:sleep、yield、join、wait方法的區別。

sleep()方法須要指定等待的時間,它可讓當前正在執行的線程在指定的時間內暫停執行,進入阻塞狀態,該方法既可讓其餘同優先級或者高優先級的線程獲得執行的機會,也可讓低優先級的線程獲得執行機會。可是sleep()方法不會釋放「鎖標誌」,也就是說若是有synchronized同步塊,其餘線程仍然不能訪問共享數據。 做用於線程

  • ·  Thread.sleep()方法用來暫停線程的執行,將CPU放給線程調度器。

  • ·  Thread.sleep()方法是一個靜態方法,它暫停的是當前執行的線程。

  • ·  Java有兩種sleep方法,一個只有一個毫秒參數,另外一個有毫秒和納秒兩個參數。

  • ·  與wait方法不一樣,sleep方法不會釋放鎖

  • ·  若是其餘的線程中斷了一個休眠的線程,sleep方法會拋出Interrupted Exception。

  • ·  休眠的線程在喚醒以後不保證能獲取到CPU,它會先進入就緒態,與其餘線程競爭CPU。

  • ·  有一個易錯的地方,當調用t.sleep()的時候,會暫停線程t。這是不對的,由於Thread.sleep是一個靜態方法,它會使當前線程而不是線程t進入休眠狀態。


join(): 當前線程等待調用此方法的線程執行結束再繼續執行。如:在main方法中調用t.join(),那main方法在此時進入阻塞狀態,一直等t線程執行完,main方法再恢復到就緒狀態,準備繼續執行。

join方法必須在線程start方法調用以後調用纔有意義。這個也很容易理解:若是一個線程都沒有start,那它也就沒法同步了。做用於線程

 

實現原理

0d19868471f745498f84cb58e4e09629.png

yield(): 它僅僅釋放線程所佔有的CPU資源,從而讓其餘線程有機會運行,可是並不能保證某個特定的線程可以得到CPU資源。誰能得到CPU徹底取決於調度器,在有些狀況下調用yield方法的線程甚至會再次獲得CPU資源。因此,依賴於yield方法是不可靠的,它只能盡力而爲。做用於線程

wait():

·       wait只能在同步(synchronize)環境中被調用,而sleep不須要。

·       進入wait狀態的線程可以被notify和notifyAll線程喚醒,可是進入sleeping狀態的線程不能被notify方法喚醒。

·       wait一般有條件地執行,線程會一直處於wait狀態,直到某個條件變爲真。可是sleep僅僅讓你的線程進入睡眠狀態。

·       wait方法在進入wait狀態的時候會釋放對象的鎖,可是sleep方法不會。

wait方法是針對一個被同步代碼塊加鎖的對象

8661a29c0b4a48faa98fa3b2f4707bb6.png

見代碼ThreadBlockTest1-5

 

 

1四、爲何不推薦使用stop和destroy方法來結束線程的運行?

stop():此方法能夠強行停止一個正在運行或掛起的線程。但stop方法不安全,就像強行切斷計算機電源,而不是按正常程序關機。可能會產生不可預料的結果。

舉例來講:

當在一個線程對象上調用stop()方法時,這個線程對象所運行的線程就會當即中止,並拋出特殊的ThreadDeath()異常。這裏的「當即」由於太「當即」了,

假如一個線程正在執行:

8438051010144d44adfdc80310dd87e3.png

因爲方法是同步的,多個線程訪問時總能保證x,y被同時賦值,而若是一個線程正在執行到x = 3;時,被調用了 stop()方法,即便在同步塊中,它也乾脆地stop了,這樣就產生了不完整的殘廢數據。而多線程編程中最最基礎的條件要保證數據的完整性,因此請忘記 線程的stop方法,之後咱們不再要說「中止線程」了。

 

destroy():該方法最初用於破壞該線程,但不做任何資源釋放。它所保持的任何監視器都會保持鎖定狀態。不過,該方法決不會被實現。即便要實現,它也極有可能以 suspend() 方式被死鎖。若是目標線程被破壞時保持一個保護關鍵系統資源的鎖,則任何線程在任什麼時候候都沒法再次訪問該資源。若是另外一個線程曾試圖鎖定該資源,則會出現死鎖。

 

 

1五、寫個代碼說明,終止線程的典型方式。

(1)    當run()方法執行完後,線程就自動終止了。

(2)    但有些時候run()方法不會結束(如服務器端監聽程序),或者其它須要用循環來處理的任務。在這種狀況下,通常是將這些任務放在一個循環中,如while循環。若是想讓循環永遠運行下去,可使用while(true){……}來處理。但要想使while循環在某一特定條件下退出,最直接的方法就是設一個boolean類型的標誌,並經過設置這個標誌爲true或false來控制while循環是否退出。

見代碼ThreadEndTest

代碼中定義了一個退出標誌exit,當exit爲true時,while循環退出,exit的默認值爲false.在定義exit時,使用了一個Java關鍵字volatile,這個關鍵字的目的是使exit同步,也就是說在同一時刻只能由一個線程來修改exit的值。

 

 

1六、A線程的優先級是10,B線程的優先級是1,那麼當進行調度時必定會調用A嗎?

不必定。線程優先級對於不一樣的線程調度器可能有不一樣的含義,可能並非用戶直觀的推測。

見代碼ThreadPriorityTest

 

 

1七、synchronize修飾在方法前是什麼意思?

一次只能有一個線程進入該方法,其餘線程要想在此時調用該方法,只能排隊等候,當前線程(就是在synchronized方法內部的線程)執行完該方法後,別的線程才能進入.

見代碼SynchronizedTest1

 

 

1八、使用Timer和TimerTask實現定時執行,定時在天天下午17:00執行。

見代碼TimerTest1-3

知識點簡介:

(1)        Timer:定時器,其實是個線程,定時調度所擁有的TimerTasks。

(2)        TimerTask:一個擁有run方法的類,須要定時執行的代碼放到run方法體內。 TimerTask通常是以匿名類的方式建立。

語法簡介:

4060724e0a29480ea773cf8478541df7.png

用法簡介:

//如下是幾種調度task的方法:  

21952e04f3384ee4b8a682e8f958eb8b.png

// time爲Date類型:在指定時間執行一次。  

6c4d910f8e024c3fbf43c0005d75df86.png

// firstTime爲Date類型,period爲long  

// 從firstTime時刻開始,每隔period毫秒執行一次。  

c3ad8c72283144f89626fc5dc5b97cc8.png

// delay 爲long類型:從如今起過delay毫秒執行一次  

06d512246fa34a31af3cbbd548c2f71b.png

// delay爲long,period爲long:從如今起過delay毫秒之後,每隔period  

// 毫秒執行一次。 

   舉例:

18cf602858bd45f4aec996e8d277f0f3.png

 

 

1九、wait方法被調用時,所在線程是否會釋放所持有的鎖資源? sleep方法呢?

wait:釋放CPU,釋放鎖;

sleep:釋放CPU,不釋放鎖。

 

 

20、wait、notify、notifyAll是在Thread類中定義的方法嗎?做用分別是什麼?

wait(),notify(),notifyAll()不屬於Thread類,而是屬於Object類,也就是說每一個對象都有wait(),notify(),notifyAll()的功能。

由於每一個對像都有鎖,鎖是每一個對像的基礎,而wait(),notify(),notifyAll()都是跟鎖有關的方法。

 

三個方法的做用分別是:

  • wait:致使當前線程等待,進入阻塞狀態,直到其餘線程調用此對象的 notify() 方法或 notifyAll() 方法。當前線程必須擁有此對象監視器(對象鎖)。該線程釋放對此監視器的全部權並等待,直到其餘線程經過調用 notify 方法,或 notifyAll 方法通知在此對象的監視器上等待的線程醒來。而後該線程將等到從新得到對監視器的全部權後才能繼續執行.

  • notify:喚醒在此對象監視器(對象鎖)上等待的單個線程。若是全部線程都在此對象上等待,則會選擇喚醒其中一個線程。直到當前線程放棄此對象上的鎖定,才能繼續執行被喚醒的線程。此方法只應由做爲此對象監視器的全部者的線程來調用.

    "當前線程必須擁有此對象監視器"與"此方法只應由做爲此對象監視器的全部者的線程來調用"說明wait方法與    notify方法必須在同步塊內執行,即synchronized(obj以內).

  • notifyAll: 喚醒在此對象監視器(對象鎖)上等待的全部線程。

 

 

2一、notify是喚醒所在對象wait pool中的第一個線程嗎?

不是。

調用 notify() 方法致使解除阻塞的線程是從因調用該對象的 wait() 方法而阻塞的線程中隨機選取的,咱們沒法預料哪個線程將會被選擇。

22ceb816a8f04a6a97784f9451cd0262.png

相關文章
相關標籤/搜索