在Java中,線程通常有五種狀態:創建,就緒,運行,阻塞和死亡。
創建狀態:在生成線程對象,並沒有調用該對象的star方法,這時線程處於創建狀態。
就緒狀態:當調用了線程對象的start方法之後,該線程就進入就緒狀態。但是此時線程調度程序還沒有把該線程設置
爲當前線程,此時處於就緒狀態。在線程運行之後,從等待或者睡眠中回來之後,也會處於就緒狀態。
運行狀態:線程調度程序將處於就緒狀態的線程設置爲當前線程,此時線程就進入了運行狀態,開始運行run函數中的代碼。
阻塞狀態:線程正在運行的時候,被暫停 ,通常是爲了等待某個事件的發生之後再運行。sleep,suspend,wait等方法
都可以導致線程阻塞。
死亡狀態:如果一個線程的run方法執行結束或者被調用stop方法後,該線程就會死亡。對於死亡的線程,無法再使用start方法
令其進入就緒。
實現線程的方法
Java中實現並啓動線程有兩種方法:
1.寫一個類繼承Thread類,重寫run方法,用start方法啓動線程。
2.寫一個類實現Runnable接口,實現run方法。用new Thread(Runnable target).start()方法來啓動。
start()方法
用start方法來啓動線程,真正實現了多線程運行,這時無需等待run方法體代碼執行完畢而直接繼續執行下面的代碼。通過調用Thread類的start()方法來啓動一個線程,這時此線程處於就緒(可運行)狀態,並沒有運行,一旦得到cpu時間片,就開始執行run()方法,這裏方法 run()稱爲線程體,它包含了要執行的這個線程的內容,Run方法運行結束,此線程隨即終止。run()方法
run()方法只是類的一個普通方法而已,如果直接調用Run方法,程序中依然只有主線程這一個線程,其程序執行路徑還是隻有一條,還是要順序執行,還是要等待run方法體執行完畢後纔可繼續執行下面的代碼,這樣就沒有達到寫線程的目的。總結:調用start方法方可啓動線程,而run方法只是thread的一個普通方法調用,還是在主線程裏執行。這兩個方法應該都比較熟悉,把需要並行處理的代碼放在run()方法中,start()方法啓動線程將自動調用 run()方法,這是由jvm的內存機制規定的。並且run()方法必須是public訪問權限,返回值類型爲void。
Thread的子類要重寫這個方法,通過Thread調用run()方法,執行線程的線程體。
調用start()後,線程會被放到等待隊列,等待CPU調度,並不一定要馬上開始執行,只是將這個線程置於可動行狀態。然後通過JVM,線程Thread會調用run()方法,執行本線程的線程體。先調用start後調用run,這麼麻煩,爲了不直接調用run?就是爲了實現多線程的優點,沒這個start不行。
多線程就是分時利用CPU,宏觀上讓所有線程一起執行 ,也叫併發。
public class Test1 {
public static void main(String[] args) {
ThreadTest1 t1 = new ThreadTest1();
ThreadTest2 t2 = new ThreadTest2();
Thread thread1 = new Thread(t1);
Thread thread2 = new Thread(t2);
thread1.start();
thread2.start();
}
}
class ThreadTest1 implements Runnable {
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("ThreadTest1正在運行==========" + i);
}
}
}
class ThreadTest2 implements Runnable {
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("ThreadTest2正在運行==========" + i);
}
}
}
從執行結果來看,ThreadTest1和ThreadTest2是交叉執行,即併發執行的。
ThreadTest1正在運行==========0
ThreadTest2正在運行==========0
ThreadTest1正在運行==========1
ThreadTest2正在運行==========1
ThreadTest2正在運行==========2
ThreadTest2正在運行==========3
ThreadTest2正在運行==========4
ThreadTest2正在運行==========5
ThreadTest2正在運行==========6
ThreadTest2正在運行==========7
ThreadTest2正在運行==========8
ThreadTest2正在運行==========9
ThreadTest2正在運行==========10
ThreadTest2正在運行==========11
ThreadTest2正在運行==========12
ThreadTest1正在運行==========2
ThreadTest1正在運行==========3
ThreadTest1正在運行==========4
ThreadTest1正在運行==========5
ThreadTest2正在運行==========13
ThreadTest2正在運行==========14
ThreadTest2正在運行==========15
ThreadTest2正在運行==========16
ThreadTest2正在運行==========17
ThreadTest2正在運行==========18
ThreadTest1正在運行==========6
ThreadTest2正在運行==========19
ThreadTest1正在運行==========7
ThreadTest1正在運行==========8
ThreadTest1正在運行==========9
ThreadTest1正在運行==========10
ThreadTest1正在運行==========11
ThreadTest1正在運行==========12
ThreadTest1正在運行==========13
ThreadTest1正在運行==========14
ThreadTest1正在運行==========15
ThreadTest1正在運行==========16
ThreadTest1正在運行==========17
ThreadTest1正在運行==========18
ThreadTest1正在運行==========19
public class Test1 {
public static void main(String[] args) {
ThreadTest1 t1 = new ThreadTest1();
ThreadTest2 t2 = new ThreadTest2();
Thread thread1 = new Thread(t1);
Thread thread2 = new Thread(t2);
thread1.run();
thread2.run();
}
}
class ThreadTest1 implements Runnable {
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("ThreadTest1正在運行==========" + i);
}
}
}
class ThreadTest2 implements Runnable {
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("ThreadTest2正在運行==========" + i);
}
}
}
從運行結果來看,ThreadTest1和ThreadTest2是順序執行的。
ThreadTest1正在運行==========0
ThreadTest1正在運行==========1
ThreadTest1正在運行==========2
ThreadTest1正在運行==========3
ThreadTest1正在運行==========4
ThreadTest1正在運行==========5
ThreadTest1正在運行==========6
ThreadTest1正在運行==========7
ThreadTest1正在運行==========8
ThreadTest1正在運行==========9
ThreadTest1正在運行==========10
ThreadTest1正在運行==========11
ThreadTest1正在運行==========12
ThreadTest1正在運行==========13
ThreadTest1正在運行==========14
ThreadTest1正在運行==========15
ThreadTest1正在運行==========16
ThreadTest1正在運行==========17
ThreadTest1正在運行==========18
ThreadTest1正在運行==========19
ThreadTest2正在運行==========0
ThreadTest2正在運行==========1
ThreadTest2正在運行==========2
ThreadTest2正在運行==========3
ThreadTest2正在運行==========4
ThreadTest2正在運行==========5
ThreadTest2正在運行==========6
ThreadTest2正在運行==========7
ThreadTest2正在運行==========8
ThreadTest2正在運行==========9
ThreadTest2正在運行==========10
ThreadTest2正在運行==========11
ThreadTest2正在運行==========12
ThreadTest2正在運行==========13
ThreadTest2正在運行==========14
ThreadTest2正在運行==========15
ThreadTest2正在運行==========16
ThreadTest2正在運行==========17
ThreadTest2正在運行==========18
ThreadTest2正在運行==========19
實現Runnable接口所具有的優勢:
1.避免Java單繼承的問題。
2.適合多線程處理同一個資源。
3.代碼可以被多線程共享,數據獨立,很容易實現資源共享。
4.線程池只能放入實現Runable或callable類線程,不能直接放入繼承Thread的類