標籤:
Java線程各個階段的狀態:
那麼我們開始一點點研究吧:
啟動線程
一、定義線程 1、擴充java.lang.Thread類。 此類中有個run()方法,應該注意其用法:
public void run()
-
如果該線程是使用獨立的
Runnable 運行物件建構的,則調用該
Runnable 對象的
run 方法;否則,該方法不執行任何操作並返回。
-
Thread 的子類應該重寫該方法。
2、實現java.lang.Runnable介面。 void
run()
-
使用實現介面
Runnable 的對象建立一個線程時,啟動該線程將導致在獨立執行的線程中調用對象的
run 方法。
-
方法
run 的常規協定是,它可能執行任何所需的操作。
二、執行個體化線程
1、如果是擴充java.lang.Thread類的線程,則直接new即可。 2、如果是實現了java.lang.Runnable介面的類,則用Thread的構造方法:Thread(Runnable target)
Thread(Runnable target, String name)
Thread(ThreadGroup group, Runnable target)
Thread(ThreadGroup group, Runnable target, String name)
Thread(ThreadGroup group, Runnable target, String name, long stackSize)
三、啟動線程 線上程的Thread對象上調用start()方法,而不是run()或者別的方法。 在調用start()方法之前:線程處於新狀態中,新狀態指有一個Thread對象,但還沒有一個真正的線程。 在調用start()方法之後:發生了一系列複雜的事情啟動新的執行線程(具有新的調用棧);該線程從新狀態轉移到可運行狀態;當該線程獲得機會執行時,其目標run()方法將運行。 注意:對Java來說,run()方法沒有任何特別之處。像main()方法一樣,它只是新線程知道調用的方法名稱(和簽名)。因此,在Runnable上或者Thread上調用run方法是合法的。但並不啟動新的線程。
三、啟動線程
線上程的Thread對象上調用start()方法,而不是run()或者別的方法。 在調用start()方法之前:線程處於新狀態中,新狀態指有一個Thread對象,但還沒有一個真正的線程。 在調用start()方法之後:發生了一系列複雜的事情 啟動新的執行線程(具有新的調用棧);該線程從新狀態轉移到可運行狀態;當該線程獲得機會執行時,其目標run()方法將運行。(如果不明白,仔細看一吧!) 注意:對Java來說,run()方法沒有任何特別之處。像main()方法一樣,它只是新線程知道調用的方法名稱(和簽名)。因此,在Runnable上或者Thread上調用run方法是合法的。但並不啟動新的線程。 執行個體:通過繼承Thread類實現線程
package com.haixu.thread;/* * 線程練習 * 通過繼承Thread類來建立線程類 * */public class FirstThread extends Thread{ private int i; //重寫run()方法,run()方法的防反彈就是線程的執行體 public void run(){ for(;i < 5 ; i++){ //當線程類繼承Thread類時,直接使用this即可獲得當前的線程 //Thread對象的getName()返回當前線程的名字 //因此可以直接調用getName()方法返回當前線程的名字 System.out.println( getName() + " " + i); } } public static void main(String[] args) {for(int i = 0; i<4; i++){System.out.println(Thread.currentThread().getName() + " " + i);if(i == 3){//建立第一個線程new FirstThread().start();//建立第二個線程new FirstThread().start();}}}}
運行結果:
main 0main 1main 2main 3Thread-0 0Thread-0 1Thread-0 2Thread-0 3Thread-0 4Thread-1 0Thread-1 1Thread-1 2Thread-1 3Thread-1 4
通過實現Runnable介面來建立線程類
package com.haixu.thread;/* * 線程學習 * 通過實現Runnable介面來建立線程類 * */public class SecondThread implements Runnable{private int i;//run()方法同樣是線程的執行體public void run(){for(; i<5; i++){//當線程類實現了Runnable介面時//如果想擷取當前線程,只能通過調用Threand.currentThread()方法System.out.println(Thread.currentThread().getName() + " " + i);}}public static void main(String[] args) {for(int i = 0 ; i<4; i++){System.out.println(Thread.currentThread().getName() + " " + i);if(i==3){SecondThread st = new SecondThread();//通過new Thread(target,name)方法建立新線程 new Thread(st , "線程1").start(); new Thread(st , "線程2").start(); }}}}
運行結果:
main 0main 1main 2main 3線程1 0線程1 1線程2 1線程1 2線程2 3線程1 4
四、一些常見問題 1、線程的名字,一個運行中的線程總是有名字的,名字有兩個來源,一個是虛擬機器自己給的名字,一個是你自己的定的名字。在沒有指定線程名字的情況下,虛擬機器總會為線程指定名字,並且主線程的名字總是mian,非主線程的名字不確定。 2、線程都可以設定名字,也可以擷取線程的名字,連主線程也不例外。 3、擷取當前線程的對象的方法是:Thread.currentThread();此方法是Thread類的靜態方法。 4、在上面的代碼中,只能保證:每個線程都將啟動,每個線程都將運行直到完成。一系列線程以某種順序啟動並不意味著將按該順序執行。對於任何一組啟動的線程來說,發送器不能保證其執行次序,期間也無法保證。 5、當線程目標run()方法結束時該線程完成。 6、一旦線程啟動,它就永遠不能再重新啟動。只有一個新的線程可以被啟動,並且只能一次。一個可啟動並執行線程或死線程可以被重新啟動。 7、線程的調度是JVM的一部分,在一個CPU的機器上上,實際上一次只能運行一個線程。一次只有一個線程棧執行。JVM線程發送器決定實際運行哪個處於可運行狀態的線程。眾多可運行線程中的某一個會被選中做為當前線程。可運行線程被選擇啟動並執行順序是沒有保障的。 8、儘管通常採用隊列形式,但這是沒有保障的。隊列形式是指當一個線程完成“一輪”時,它移到可運行隊列的尾部等待,直到它最終排隊到該隊列的前端為止,它才能被再次選中。事實上,我們把它稱為可運行池而不是一個可運行隊列,目的是協助認識線程並不都是以某種有保障的順序排列唱呢個一個隊列的事實。 9、儘管我們沒有無法控制線程發送器,但可以通過別的方式來影響線程調度的方式。
線程狀態的轉換
線程狀態 線程的狀態轉換是線程式控制制的基礎。線程狀態總的可分為五大狀態:分別是生、死、可運行、運行、等待/阻塞。如: 1、新狀態:線程對象已經建立,還沒有在其上調用start()方法。 2、可運行狀態:當線程有資格運行,但發送器還沒有把它選定為運行線程時線程所處的狀態。當start()方法調用時,線程首先進入可運行狀態。線上程運行之後或者從阻塞、等待或睡眠狀態回來後,也返回到可運行狀態。 3、運行狀態:線程發送器從可運行池中選擇一個線程作為當前線程時線程所處的狀態。這也是線程進入運行狀態的唯一一種方式。 4、等待/阻塞/睡眠狀態:這是線程有資格運行時它所處的狀態。實際上這個三狀態組合為一種,其共同點是:線程仍舊是活的,但是當前沒有條件運行。換句話說,它是可啟動並執行,但是如果某件事件出現,他可能返回到可運行狀態。 5、死亡態:當線程的run()方法完成時就認為它死去。這個線程對象也許是活的,但是,它已經不是一個單獨執行的線程。線程一旦死亡,就不能複生。 如果在一個死去的線程上調用start()方法,會拋出java.lang.IllegalThreadStateException異常。 具體的實現過程請查看下一篇博文,具體講述各個狀態的執行個體
瘋狂Java學習筆記(63)-----------線程進階