天天看點

Java中線程的狀态及其轉化

線程狀态轉化圖:

Java中線程的狀态及其轉化

說明:

線程總共包括以下5種狀态。

1、新狀态New:該狀态也叫建立狀态,當線程對象被建立後,線程就進入了建立狀态。例如:Thread thread = new Thread();。

2、就緒狀态Runnable:該狀态也被稱為可執行狀态。當線程對象被建立以後,其它線程調用了該對象的start()方法,進而來啟用該線程。例如:thread.start()。處于就緒狀态的線程,随時可能被CPU排程執行。

3、運作狀态(Running):線程擷取CPU權限進行執行。但注意的是線程隻能從就緒狀态進入到運作狀态。

4、阻塞狀态(Blocked):阻塞狀态時線程因為某種原因放棄了CPU的使用權,暫時停止運作。直到線程進入到就緒狀态才有機會轉到運作狀态。

阻塞的情況有三種:

  (1) 等待阻塞--同過調用線程的wait()方法,讓線程等待某工作的完成。

  (2) 同步阻塞 -- 線程在擷取synchronized同步鎖失敗(因為鎖被其它線程所占用),它會進入同步阻塞狀态。

  (3) 其他阻塞 -- 通過調用線程的sleep()或join()或發出了I/O請求時,線程會進入到阻塞狀态。當sleep()狀态逾時、join()等待線程終止或者逾時、或者I/O處理完畢時,線程重新轉入就緒狀态。

5、死亡狀态(Dead):線程執行完了或者因異常退出了run()方法,該線程結束生命周期。

一、wait(),notify(),notify(),和notifyAll()等方法介紹。

      在Object.java中,定義了wait(), notify()和notifyAll()等接口。

      wait()的作用是讓目前線程進入等待狀态,同時,wait()也會讓目前線程釋放它所持有的鎖。

      notify()和notifyAll()的作用,則是喚醒目前對象上的等待線程;notify()是喚醒單個線程,而notifyAll()是喚醒所有的線程。

Object類中關于等待/喚醒的API詳細資訊如下:

notify()       -- 喚醒在此對象螢幕上等待的單個線程。

notifyAll()   -- 喚醒在此對象螢幕上等待的所有線程。

wait()          -- 讓目前線程處于“等待(阻塞)狀态”,“直到其他線程調用此對象的 notify() 方法或 notifyAll() 方法”,目前線程被喚醒(進入“就緒狀态”)。

wait(long timeout)                   -- 讓目前線程處于“等待(阻塞)狀态”,“直到其他線程調用此對象的 notify() 方法                                                  或 notifyAll() 方法,或者超過指定的時間量”,目前線程被喚醒(進入“就緒狀                                                        态”)。

wait(long timeout, int nanos)  -- 讓目前線程處于“等待(阻塞)狀态”,“直到其他線程調用此對象的 notify() 方法或 notifyAll() 方法,或者其他某個線程中斷目前線程,或者已超過某個實際時間量”,目前線程被喚醒(進入“就緒狀态”)。

 二、為什麼notify(), wait()等函數定義在Object中,而不是Thread中。

Object中的wait(), notify()等函數,和synchronized一樣,會對“對象的同步鎖”進行操作。

wait()會使“目前線程”等待,因為線程進入等待狀态,是以線程應該釋放它鎖持有的“同步鎖”,否則其它線程擷取不到該“同步鎖”而無法運作!

OK,線程調用wait()之後,會釋放它鎖持有的“同步鎖”;而且,根據前面的介紹,我們知道:等待線程可以被notify()或notifyAll()喚醒。現在,請思考一個問題:notify()是依據什麼喚醒等待線程的?或者說,wait()等待線程和notify()之間是通過什麼關聯起來的?答案是:依據“對象的同步鎖”。

負責喚醒等待線程的那個線程(我們稱為“喚醒線程”),它隻有在擷取“該對象的同步鎖”(這裡的同步鎖必須和等待線程的同步鎖是同一個),并且調用notify()或notifyAll()方法之後,才能喚醒等待線程。雖然,等待線程被喚醒;但是,它不能立刻執行,因為喚醒線程還持有“該對象的同步鎖”。必須等到喚醒線程釋放了“對象的同步鎖”之後,等待線程才能擷取到“對象的同步鎖”進而繼續運作。

總之,notify(), wait()依賴于“同步鎖”,而“同步鎖”是對象鎖持有,并且每個對象有且僅有一個!這就是為什麼notify(), wait()等函數定義在Object類,而不是Thread類中的原因。

三、 yield()介紹

yield()的作用是讓步。它能讓目前線程由“運作狀态”進入到“就緒狀态”,進而讓其它具有相同優先級的等待線程擷取執行權;但是,并不能保證在目前線程調用yield()之後,其它具有相同優先級的線程就一定能獲得執行權;也有可能是目前線程又進入到“運作狀态”繼續運作!

四、 yield() 與 wait()的比較

我們知道,wait()的作用是讓目前線程由“運作狀态”進入“等待(阻塞)狀态”的同時,也會釋放同步鎖。而yield()的作用是讓步,它也會讓目前線程離開“運作狀态”。它們的差別是:

(01) wait()是讓線程由“運作狀态”進入到“等待(阻塞)狀态”,而不yield()是讓線程由“運作狀态”進入到“就緒狀态”。

(02) wait()是會線程釋放它所持有對象的同步鎖,而yield()方法不會釋放鎖。

1 package com.zjk.thread;
 2 
 3 public class YieldLockTest {
 4         private  static Object obj = new Object();
 5         
 6         public static void main(String[] args) {
 7             ThreadA t1 = new ThreadA("t1");
 8             ThreadA t2 = new ThreadA("t2");
 9             t1.start();
10             t2.start();
11         }
12         
13         static class ThreadA extends Thread{
14             public ThreadA (String name) {
15                 super(name);
16             }        
17                 public void run () {
18                     //擷取obj對象的同步
19                     synchronized (obj) {
20                           for(int i=0; i <10; i++){ 
21                                 System.out.printf("%s [%d]:%d\n", this.getName(), this.getPriority(), i); 
22                                 // i整除4時,調用yield
23                                 if (i%4 == 0)
24                                     Thread.yield();
25                             }
26                     }
27                 }
28         }
29         
30 }      

輸出結果:

1 t1 [5]:0
 2 t1 [5]:1
 3 t1 [5]:2
 4 t1 [5]:3
 5 t1 [5]:4
 6 t1 [5]:5
 7 t1 [5]:6
 8 t1 [5]:7
 9 t1 [5]:8
10 t1 [5]:9
11 t2 [5]:0
12 t2 [5]:1
13 t2 [5]:2
14 t2 [5]:3
15 t2 [5]:4
16 t2 [5]:5
17 t2 [5]:6
18 t2 [5]:7
19 t2 [5]:8
20 t2 [5]:9      

說明:

主線程main中啟動了兩個線程t1和t2。t1和t2在run()會引用同一個對象的同步鎖,即synchronized(obj)。在t1運作過程中,雖然它會調用Thread.yield();但是,t2是不會擷取cpu執行權的。因為,t1并沒有釋放“obj所持有的同步鎖”!

五、sleep()介紹

sleep()定義在Thread.java中。

sleep() 的作用是讓目前線程休眠,即目前線程會從“運作狀态”進入到“休眠(阻塞)狀态”。sleep()會指定休眠時間,線程休眠的時間會大于/等于該休眠時間;線上程重新被喚醒時,它會由“阻塞狀态”變成“就緒狀态”,進而等待cpu的排程執行。

六、sleep()與wait()的比較

我們知道,wait()的作用是讓目前線程由“運作狀态”進入“等待(阻塞)狀态”的同時,也會釋放同步鎖。而sleep()的作用是也是讓目前線程由“運作狀态”進入到“休眠(阻塞)狀态”。

但是,wait()會釋放對象的同步鎖,而sleep()則不會釋放鎖。

轉載于:https://www.cnblogs.com/liuhuijie/p/11025728.html