Java線程之線程狀態的轉換以及sleep和wait有什麼區別

線程的狀態轉換是線程控制的基礎。線程狀態總的能夠分爲五大狀態:分別是生、可運行、運行、等待|阻塞|睡眠、死。java

 

一、新狀態:線程對象已經建立,尚未在其上調用start()方法。多線程

 

二、可運行狀態:當線程有資格運行,但調度程序尚未把它選定爲運行線程時線程所處的狀態。當start()方法調用時,線程首先進入可運行狀態,在線程運行以後或者阻塞、等待或睡眠狀態回來後,也返回到能夠運行狀態。ide

 

三、運行狀態:線程調度陳旭從可運行池中選擇一個線程做爲當前線程時線程所處的狀態。這也是線程進入運行狀態的惟一一種方式。post

 

四、等待|阻塞|睡眠狀態:這是線程有資格運行時它所處的狀態。實際上這是那個狀態能夠合爲一種,this

 

其共同點爲:線程仍舊還活着。可是當前沒有條件運行。換句話說,它是可運行的,可是若是某件事情出現,他可能返回到可運行狀態。spa

 

五、 死亡狀態:當線程的run()方法完成時就能夠認爲線程死去了。這個線程對象或許是活的,可是,它已經不是一個單獨可執行的線程。線程一旦死亡,就不能復 生。若是在一個死去的線程上調用start()方法,會拋出java.lang.IllegalThreadStateException異常。線程

 

2、阻止線程執行設計

 

對於線程的阻止,考慮一下三個方面,不考慮IO阻塞的狀況:對象

 

睡眠、等待blog

 

須要一個對象的鎖定而被阻塞。

 

一、睡眠 sleep()

 

Thread.sleep(long millis) 和 Thread.sleep(long millis, int nanos)靜態方法強制當前正在執行的線程睡眠(暫停執行),以"減慢線程"。當線程睡眠時,它入睡在某個地方,在甦醒以前不會返回到可運行狀態。當睡 覺時間到期,則返回到可運行狀態。

 

線程睡眠的緣由:線程執行太快,或者須要強制進入下一輪,由於Java規範不保證合理的輪換。

 

睡眠的實現:調用靜態方法便可。

 

 

 

Java代碼   收藏代碼
  1. <span style="font-size: medium;">public void run() {  
  2.         int count = 0;  
  3.         while (true) {  
  4.             try {  
  5.                 Thread.sleep(1000);  
  6.             } catch (InterruptedException e) {  
  7.                 e.printStackTrace();  
  8.             }  
  9.             System.out.println(Thread.currentThread().getName() + ":" + (count++));  
  10.         }  
  11.     }</span>  

 

 

 

睡眠的位置:爲了讓其餘線程有機會執行,能夠將Thread.sleep()的調用放到線程run()方法以內,這樣才能保證線程執行過程當中會睡眠。

 

 

例如:

 

 

 

Java代碼   收藏代碼
  1. <span style="font-size: medium;">package com.sample.client;  
  2.   
  3. /** 
  4.  *  
  5.  * @author DYLAN 
  6.  */  
  7. public class Client implements Runnable {  
  8.   
  9.     @Override  
  10.     public void run() {  
  11.         for (int i = 0; i < 5; i++) {  
  12.             try {  
  13.                 Thread.sleep(1000);  
  14.             } catch (InterruptedException e) {  
  15.                 e.printStackTrace();  
  16.             }  
  17.             System.out.println(Thread.currentThread().getName() + ":" + i);  
  18.         }  
  19.     }  
  20.   
  21.     public static void main(String[] args) {  
  22.         Client client = new Client();  
  23.         Thread t = new Thread(client);  
  24.         t.setName("阿貓");  
  25.         t.start();  
  26.           
  27.         Thread t2 = new Thread(client);  
  28.         t2.setName("阿狗");  
  29.         t2.start();  
  30.     }  
  31. }</span>  

 

Java代碼   收藏代碼
  1. <span style="font-size: medium;">阿貓:0  
  2. 阿狗:0  
  3. 阿貓:1  
  4. 阿狗:1  
  5. 阿狗:2  
  6. 阿貓:2  
  7. 阿貓:3  
  8. 阿狗:3  
  9. 阿貓:4  
  10. 阿狗:4  
  11. </span>  

 

這樣,線程在每次執行過程當中,總會睡眠1000毫秒,只有線程睡眠了,其餘的線程就有機會執行了。

 

 

 

注意:

 

a、線程睡眠是幫組全部線程得到運行機會的最好方法。

 

b、線程睡眠到期自動甦醒,並返回到可運行狀態,不是運行狀態。sleep()中指定的時間是線程不會運行的最短期。所以,sleep()方法不能保證該線程到期後就開始執行。

 

c、sleep()是靜態方法,只能控制當前正在運行的線程。

 

 

 

二、線程的優先級和線程讓步yield()

 

線程的讓步是經過Thread.yield()來實現的。yield()方法的做用是:暫停當前正在執行的線程對象,並執行其餘線程。

 

要理解yield()必須瞭解線程優先級的概念,線程老是存在優先級,優先級範圍在1-10之間,JVM線程調度程序是基於優先級的搶先調度機制。在大多數的狀況下,當前運行的線程優先級大於或等於線程池中任何線程的優先級。但這僅僅是大多數狀況。

 

注意:當設計多線程應用程序的時候,必定不要依賴於線程的優先級。由於線程調度優先級操做是沒有保障的,只能把線程優先級做爲一種提升程序效率的方法,可是要保證不依賴這種操做。

 

 

 

當線程池中線程都具備相同的優先級,調度程序的JVM實現自由選擇它喜歡的線程。這時候調度程序的操做有兩種可能:一是選擇一個線程運行,直到它阻塞或者運行徹底終止,二是時候切片,爲池內的每一個線程提供均等的運行機會。

 

設置線程的優先級:線程默認的優先級是建立它的執行線程的優先級。能夠經過setPriority(int newPriority)更改線程的優先級。

 

Thread t = new MyThread();

 

t.setPriority(8);

 

t.start();

 

線程優先級爲1-10之間的正整數,JVM從不會改變一個線程的優先級。然而,1-10之間的數值是沒有保證的。一些JVM可能不能識別10個不一樣的值,而將這些優先級進行每兩個或多個合併,變成至少10個的優先級,則兩個或多個優先級的線程可能被映射爲一個優先級。

 

線程默認優先級爲5,Thread類中有三個常量,定義線程優先級範圍:

 

static int MAX_PRIORITY 線程能夠具備的最高優先級。

 

static int MIN_PRIORITY 線程能夠具備的最低優先級。

 

static int NORM_PRIORITY 分配給線程的默認優先級

 

 

 三、Thread.yield()方法

 

Thread.yield() 方法做用是:暫停當前正在執行的線程對象,並執行其餘線程。yield應該作的是讓當前運行的線程回到可運行狀態,以容許具備相同優先級的其餘線程得到運 行機會。所以,使用yield的目的是讓相同優先級的線程之間能適當的輪轉執行。可是,實際中沒法保證yield達到讓步目的,由於讓步的線程還有可能被 線程調度程序再次選中。

 

結論:yield()從未致使線程轉到等待|睡眠|阻塞狀態。在大多數狀況下,yield()將致使線程從運行狀態轉到可運行狀態,可是可能沒有效果。

 

 

 

四、join()方法

 

Thread的非靜態方法join()讓一個線程B加入到另一個線程A的尾部。在A執行完畢以前,B不能執行。

 

 

 

Java代碼   收藏代碼
  1. <span style="font-size: medium;">Client client = new Client();  
  2. Thread t = new Thread(client);  
  3. t.setName("阿貓");  
  4. t.setPriority(8);  
  5. t.start();  
  6. t.join();  
  7.           
  8. Thread t2 = new Thread(client);  
  9. t2.setName("阿狗");  
  10. t2.start();</span>  

 

 線程t執行完畢後線程t2方能執行。

 

 

小結:

 

到目前爲止,線程離開運行狀態的3中方法:

 

一、調用Thread.sleep():使當前線程睡眠至少多少毫秒(儘管它可能在指定的時間以前被調度程序中斷)。

 

二、調用Thread.yield():不能保障太多事情,儘管一般它會讓當前運行線程回到可運行性狀態,使得有相同優先級的線程有機會執行。

 

三、調用join()方法:保證當前線程中止執行,直到該線程所加入的線程完成爲止,然而,若是它加入的線程沒有存活,則當前線程不須要中止。

 

 

 

除了以上三種方式外,還有下面幾種特殊狀況可能使線程離開運行狀態:

 

一、線程的run()方法正常執行完畢。

 

二、在對象上調用wait()方法(不是在線程上調用)。

 

三、線程不能在對象上得到鎖定,它正試圖運行該對象上的方法代碼。

 

四、線程調度程序能夠決定將當前運行狀態移動到可運行狀態,以便另外一個線程得到運行機會,而不須要任何理由。

 

 

sleep和wait有什麼區別:

第一種解釋:

功能差很少,都用來進行線程控制,他們最大本質的區別是:sleep()不釋放同步鎖,wait()釋放同步縮.  
  還有用法的上的不一樣是:sleep(milliseconds)能夠用時間指定來使他自動醒過來,若是時間不到你只能調用interreput()來強行打斷;wait()能夠用notify()直接喚起.

第二種解釋:

sleep是Thread類的靜態方法。sleep的做用是讓線程休眠制定的時間,在時間到達時恢復,也就是說sleep將在接到時間到達事件事恢復線程執行,例如:
try{
System.out.println("I'm going to bed");
Thread.sleep(1000);
System.out.println("I wake up");
}
catch(IntrruptedException e) {
}
wait是Object的方法,也就是說能夠對任意一個對象調用wait方法,調用wait方法將會將調用者的線程掛起,直到其餘線程調用同一個對象的notify方法纔會從新激活調用者,例如:
//Thread 1

try{
obj.wait();//suspend thread until obj.notify() is called
}
catch(InterrputedException e) {
}

第三種解釋:

這二者的施加者是有本質區別的. 
sleep()是讓某個線程暫停運行一段時間,其控制範圍是由當前線程決定,也就是說,在線程裏面決定.比如如說,我要作的事情是 "點火->燒水->煮麪",而當我點完火以後我不當即燒水,我要休息一段時間再燒.對於運行的主動權是由個人流程來控制.

而 wait(),首先,這是由某個肯定的對象來調用的,將這個對象理解成一個傳話的人,當這我的在某個線程裏面說"暫停!",也是 thisOBJ.wait(),這裏的暫停是阻塞,仍是"點火->燒水->煮飯",thisOBJ就比如一個監督個人人站在我旁邊,原本該線 程應該執行1後執行2,再執行3,而在2處被那個對象喊暫停,那麼我就會一直等在這裏而不執行3,但正個流程並無結束,我一直想去煮飯,但還沒被容許, 直到那個對象在某個地方說"通知暫停的線程啓動!",也就是thisOBJ.notify()的時候,那麼我就能夠煮飯了,這個被暫停的線程就會從暫停處 繼續執行.


其實二者均可以讓線程暫停一段時間,可是本質的區別是一個線程的運行狀態控制,一個是線程之間的通信的問題

 在java.lang.Thread類中,提供了sleep(),
而java.lang.Object類中提供了wait(), notify()和notifyAll()方法來操做線程
sleep()能夠將一個線程睡眠,參數能夠指定一個時間。
而wait()能夠將一個線程掛起,直到超時或者該線程被喚醒。
    wait有兩種形式wait()和wait(milliseconds).
sleep和wait的區別有:
  1,這兩個方法來自不一樣的類分別是Thread和Object
  2,最主要是sleep方法沒有釋放鎖,而wait方法釋放了鎖,使得其餘線程可使用同步控制塊或者方法。
  3,wait,notify和notifyAll只能在同步控制方法或者同步控制塊裏面使用,而sleep能夠在
    任何地方使用
   synchronized(x){
      x.notify()
     //或者wait()
   }
   4,sleep必須捕獲異常,而wait,notify和notifyAll不須要捕獲異常

相關文章
相關標籤/搜索