十一、下面的代碼,實際上有幾個線程在運行:編程
兩個:線程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,那它也就沒法同步了。做用於線程
實現原理
yield(): 它僅僅釋放線程所佔有的CPU資源,從而讓其餘線程有機會運行,可是並不能保證某個特定的線程可以得到CPU資源。誰能得到CPU徹底取決於調度器,在有些狀況下調用yield方法的線程甚至會再次獲得CPU資源。因此,依賴於yield方法是不可靠的,它只能盡力而爲。做用於線程
wait():
· wait只能在同步(synchronize)環境中被調用,而sleep不須要。
· 進入wait狀態的線程可以被notify和notifyAll線程喚醒,可是進入sleeping狀態的線程不能被notify方法喚醒。
· wait一般有條件地執行,線程會一直處於wait狀態,直到某個條件變爲真。可是sleep僅僅讓你的線程進入睡眠狀態。
· wait方法在進入wait狀態的時候會釋放對象的鎖,可是sleep方法不會。
wait方法是針對一個被同步代碼塊加鎖的對象
見代碼ThreadBlockTest1-5
1四、爲何不推薦使用stop和destroy方法來結束線程的運行?
stop():此方法能夠強行停止一個正在運行或掛起的線程。但stop方法不安全,就像強行切斷計算機電源,而不是按正常程序關機。可能會產生不可預料的結果。
舉例來講:
當在一個線程對象上調用stop()方法時,這個線程對象所運行的線程就會當即中止,並拋出特殊的ThreadDeath()異常。這裏的「當即」由於太「當即」了,
假如一個線程正在執行:
因爲方法是同步的,多個線程訪問時總能保證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通常是以匿名類的方式建立。
語法簡介:
用法簡介:
//如下是幾種調度task的方法:
// time爲Date類型:在指定時間執行一次。
// firstTime爲Date類型,period爲long
// 從firstTime時刻開始,每隔period毫秒執行一次。
// delay 爲long類型:從如今起過delay毫秒執行一次
// delay爲long,period爲long:從如今起過delay毫秒之後,每隔period
// 毫秒執行一次。
舉例:
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() 方法而阻塞的線程中隨機選取的,咱們沒法預料哪個線程將會被選擇。