線程的5個狀態可分為,分別是新、死、可運行、運行、阻塞狀態。可以用如下一幅圖表示:
1、 初生狀態:已建立線程對象,但沒有執行start()方法的線程;
2、 可運行狀態:已執行start()方法,並滿足運行條件,等待CPU調度;
3、 運行狀態:正在CPU上運行;
4、 死亡狀態:線程運行結束,也就是run()方法運行結束;
5、 阻塞狀態:正在啟動並執行線程因為某些原因,如CPU調度策略,或者有更高優先順序的進程要運行,或者啟動並執行條件不滿足等,暫停執行。
下面介紹通過睡眠和等待來控制線程。
1、 睡眠
可以線上程的run()方法中調用Thread.sleep(long millis)和Thread.sleep(long millis, int nanos)靜態方法強制當前正在執行的線程休眠(暫停執行),
class Demo3 extends Thread{ @Override public void run() { for(int i = 5;i<11;i++){ System.out.println("這裡線程睡眠5秒鐘"); try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println("線程運行結束"); } } |
這樣執行的結果就是每隔兩秒鐘列印一句。
注意:
a、線程睡眠是協助所有線程獲得運行機會的最好方法。
b、線程睡眠到期自動蘇醒,並返回到可運行狀態,不是運行狀態。sleep()中指定的時間是線程不會啟動並執行最短時間。因此,sleep()方法不能保證該線程睡眠到期後就開始執行。
c、sleep()是靜態方法,只能控制當前正在啟動並執行線程。
2、線程讓步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()方法作用是:暫停當前正在執行的線程對象,並執行其他線程。
yield()應該做的是讓當前運行線程回到可運行狀態,以允許具有相同優先順序的其他線程獲得運行機會。因此,使用yield()的目的是讓相同優先順序的線程之間能適當的輪轉執行。但是,實際中無法保證yield()達到讓步目的,因為讓步的線程還有可能被線程發送器再次選中。
結論:yield()從未導致線程轉到等待/睡眠/阻塞狀態。在大多數情況下,yield()將導致線程從運行狀態轉到可運行狀態,但有可能沒有效果。
3、join()方法
Thread的非靜態方法join()讓一個線程B“加入”到另外一個線程A的尾部。在A執行完畢之前,B不能工作。例如:
Thread t = new MyThread();
t.start();
t.join();
另外,join()方法還有帶逾時限制的重載版本。 例如t.join(5000);則讓線程等待5000毫秒,如果超過這個時間,則停止等待,變為可運行狀態。
package learn.thread; public class LearnThree { public static void main(String[] args) { Demo3 demo = new Demo3(); for (int i = 0; i < 1000; i++) { System.out.println(Thread.currentThread().getName()+"這是中main線程中。"); if (5 == i) { demo.start(); try { demo.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } class Demo3 extends Thread { @Override public void run() { for (int i = 5; i < 11; i++) { System.out.println("這裡線程睡眠5秒鐘"); // Thread.sleep(2000); Thread.yield(); } System.out.println("線程運行結束"); } } |
參考:http://lavasoft.blog.51cto.com/62575/99153