java多線程之線程狀態?

一、線程狀態

線程的狀態轉換是線程控制的基礎。線程狀態總的可分為五大狀態:分別是生、死、可運行、運行、等待/阻塞

1、新狀態:線程對象已經創建,還沒有在其上調用start()方法。

2、可運行狀態:當線程有資格運行,但調度程序還沒有把它選定為運行線程時線程所處的狀態。當start()方法調用時,線程首先進入可運行狀態。在線程運行之後或者從阻塞、等待或睡眠狀態回來後,也返回到可運行狀態。

3、運行狀態:線程調度程序從可運行池中選擇一個線程作為當前線程時線程所處的狀態。這也是線程進入運行狀態的唯一一種方式。

4、等待/阻塞/睡眠狀態:這是線程有資格運行時它所處的狀態。實際上這個三狀態組合為一種,其共同點是:線程仍舊是活的,但是當前沒有條件運行。換句話說,它是可運行的,但是如果某件事件出現,他可能返回到可運行狀態。

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

有關詳細狀態轉換圖可以參看本人的“Java多線程編程總結”中的圖

二、阻止線程執行

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

睡眠;

等待;

因為需要一個對象的鎖定而被阻塞。

1、睡眠

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

線程睡眠的原因:線程執行太快,或者需要強制進入下一輪,因為Java規範不保證合理的輪換。

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

try { Thread.sleep(123); } catch (InterruptedException e) { e.printStackTrace(); }

睡眠的位置:為了讓其他線程有機會執行,可以將Thread.sleep()的調用放線程run()之內。這樣才能保證該線程執行過程中會睡眠。

例如,在前面的例子中,將一個耗時的操作改為睡眠,以減慢線程的執行。可以這麼寫:

public void run() { for(int i = 0;i<5;i++){

// 很耗時的操作,用來減慢線程的執行// for(long k= 0; k <100000000;k++); try {Thread.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); . } System.out.println(this.getName()+" :"+i); } }

運行結果:

阿三 :0 李四 :0 阿三 :1 阿三 :2 阿三 :3 李四 :1 李四 :2 阿三 :4 李四 :3 李四 :4 Process finished with exit code 0

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

注意:

1、線程睡眠是幫助所有線程獲得運行機會的最好方法。

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

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

下面給個例子:

/** * 一個計數器,計數到100,在每個數字之間暫停1秒,每隔10個數字輸出一個字符串 * * @author leizhimin 2008-9-14 9:53:49 */publicclass MyThread extends Thread { publicvoid run() { for (int i = 0; i < 100; i++) { if ((i) % 10 == 0) { System.out.println("-------" + i); } System.out.print(i); try { Thread.sleep(1); System.out.print(" 線程睡眠1毫秒!\n"); } catch (InterruptedException e) { e.printStackTrace(); } } } publicstaticvoid main(String[] args) { new MyThread().start(); } }

-------0 0 線程睡眠1毫秒! 1 線程睡眠1毫秒! 2 線程睡眠1毫秒! 3 線程睡眠1毫秒! 4 線程睡眠1毫秒! 5 線程睡眠1毫秒! 6 線程睡眠1毫秒! 7 線程睡眠1毫秒! 8 線程睡眠1毫秒! 9 線程睡眠1毫秒! -------10 10 線程睡眠1毫秒! 11 線程睡眠1毫秒! 12 線程睡眠1毫秒! 13 線程睡眠1毫秒! 14 線程睡眠1毫秒! 15 線程睡眠1毫秒! 16 線程睡眠1毫秒! 17 線程睡眠1毫秒! 18 線程睡眠1毫秒! 19 線程睡眠1毫秒! -------20 20 線程睡眠1毫秒! 21 線程睡眠1毫秒! 22 線程睡眠1毫秒! 23 線程睡眠1毫秒! 24 線程睡眠1毫秒! 25 線程睡眠1毫秒! 26 線程睡眠1毫秒! 27 線程睡眠1毫秒! 28 線程睡眠1毫秒! 29 線程睡眠1毫秒! -------30 30 線程睡眠1毫秒! 31 線程睡眠1毫秒! 32 線程睡眠1毫秒! 33 線程睡眠1毫秒! 34 線程睡眠1毫秒! 35 線程睡眠1毫秒! 36 線程睡眠1毫秒! 37 線程睡眠1毫秒! 38 線程睡眠1毫秒! 39 線程睡眠1毫秒! -------40 40 線程睡眠1毫秒! 41 線程睡眠1毫秒! 42 線程睡眠1毫秒! 43 線程睡眠1毫秒! 44 線程睡眠1毫秒! 45 線程睡眠1毫秒! 46 線程睡眠1毫秒! 47 線程睡眠1毫秒! 48 線程睡眠1毫秒! 49 線程睡眠1毫秒! -------50 50 線程睡眠1毫秒! 51 線程睡眠1毫秒! 52 線程睡眠1毫秒! 53 線程睡眠1毫秒! 54 線程睡眠1毫秒! 55 線程睡眠1毫秒! 56 線程睡眠1毫秒! 57 線程睡眠1毫秒! 58 線程睡眠1毫秒! 59 線程睡眠1毫秒! -------60 60 線程睡眠1毫秒! 61 線程睡眠1毫秒! 62 線程睡眠1毫秒! 63 線程睡眠1毫秒! 64 線程睡眠1毫秒! 65 線程睡眠1毫秒! 66 線程睡眠1毫秒! 67 線程睡眠1毫秒! 68 線程睡眠1毫秒! 69 線程睡眠1毫秒! -------70 70 線程睡眠1毫秒! 71 線程睡眠1毫秒! 72 線程睡眠1毫秒! 73 線程睡眠1毫秒! 74 線程睡眠1毫秒! 75 線程睡眠1毫秒! 76 線程睡眠1毫秒! 77 線程睡眠1毫秒! 78 線程睡眠1毫秒! 79 線程睡眠1毫秒! -------80 80 線程睡眠1毫秒! 81 線程睡眠1毫秒! 82 線程睡眠1毫秒! 83 線程睡眠1毫秒! 84 線程睡眠1毫秒! 85 線程睡眠1毫秒! 86 線程睡眠1毫秒! 87 線程睡眠1毫秒! 88 線程睡眠1毫秒! 89 線程睡眠1毫秒! -------90 90 線程睡眠1毫秒! 91 線程睡眠1毫秒! 92 線程睡眠1毫秒! 93 線程睡眠1毫秒! 94 線程睡眠1毫秒! 95 線程睡眠1毫秒! 96 線程睡眠1毫秒! 97 線程睡眠1毫秒! 98 線程睡眠1毫秒! 99 線程睡眠1毫秒! Process finished with exit code 0

2、線程的優先級和線程讓步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 分配給線程的默認優先級。

3、Thread.yield()方法

Thread.yield()方法作用是:暫停當前正在執行的線程對象,並執行其他線程。

yield()應該做的是讓當前運行線程回到可運行狀態,以允許具有相同優先級的其他線程獲得運行機會。因此,使用yield()的目的是讓相同優先級的
線程之間能適當的輪轉執行。但是,實際中無法保證yield()達到讓步目的,因為讓步的線程還有可能被線程調度程序再次選中。

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

4、join()方法

Thread的非靜態方法join()讓一個線程B“加入”到另外一個線程A的尾部。在A執行完畢之前,B不能工作。例如:

Thread t = new MyThread(); t.start(); t.join();

另外,join()方法還有帶超時限制的重載版本。 例如t.join(5000);則讓線程等待5000毫秒,如果超過這個時間,則停止等待,變為可運行狀態。

線程的加入join()對線程棧導致的結果是線程棧發生了變化,當然這些變化都是瞬時的。下面給示意圖:

相關問題答案