java線程技術6_線程的掛起和喚醒[轉]

轉自:http://blog.chinaunix.net/uid-122937-id-215913.htmlcss

1. 線程的掛起和喚醒
      掛起其實是讓線程進入「非可執行」狀態下,在這個狀態下CPU不會分給線程時間片,進入這個狀態能夠用來暫停一個線程的運行;在線程掛起後,能夠經過從新喚醒線程來使之恢復運行。

掛起的緣由多是以下幾種狀況:
     (1)經過調用sleep()方法使線程進入休眠狀態,線程在指定時間內不會運行。
     (2)經過調用join()方法使線程掛起,使本身等待另外一個線程的結果,直到另外一個線程執行完畢爲止。
     (3)經過調用wait()方法使線程掛起,直到線程獲得了notify()和notifyAll()消息,線程纔會進入「可執行」狀態。
     (4)使用suspend掛起線程後,能夠經過resume方法喚醒線程。
      雖然suspend和resume能夠很方便地使線程掛起和喚醒,但因爲使用這兩個方法可能會形成死鎖,所以,這兩個方法被標識爲deprecated(抗議)標記,這代表在之後的jdk版本中這兩個方法可能被刪除,因此儘可能不要使用這兩個方法來操做線程。

      調用sleep()、yield()、suspend()的時候並無被釋放鎖
      調用wait()的時候釋放當前對象的鎖

      wait()方法表示,放棄當前對資源的佔有權,一直等到有線程通知,纔會運行後面的代碼。
      notify()方法表示,當前的線程已經放棄對資源的佔有,通知等待的線程來得到對資源的佔有權,可是隻有一個線程可以從wait狀態中恢復,而後繼續運行wait()後面的語句。
      notifyAll()方法表示,當前的線程已經放棄對資源的佔有,通知全部的等待線程從wait()方法後的語句開始運行。 

2.
等待和鎖實現資源競爭

      等待機制與鎖機制是密切關聯的,對於須要競爭的資源,首先用synchronized確保這段代碼只能一個線程執行,能夠再設置一個標誌位condition判斷該資源是否準備好,若是沒有,則該線程釋放鎖,本身進入等待狀態,直到接收到notify,程序從wait處繼續向下執行。
html

  1. synchronized(obj) {
  2.   while(!condition) {
  3.    obj.wait();
  4.   }
  5.   obj.doSomething();
  6. }

以上程序表示只有一個線程A得到了obj鎖後,發現條件condition不知足,沒法繼續下一處理,因而線程A釋放該鎖,進入wait()。

      在另外一線程B中,若是B更改了某些條件,使得線程A的condition條件知足了,就能夠喚醒線程A:java

  1. synchronized(obj) {
  2.  condition = true;
  3.  obj.notify();
  4. }

須要注意的是:
  # 調用obj的wait(), notify()方法前,必須得到obj鎖,也就是必須寫在synchronized(obj) {...} 代碼段內。
  # 調用obj.wait()後,線程A就釋放了obj的鎖,不然線程B沒法得到obj鎖,也就沒法在synchronized(obj) {...} 代碼段內喚醒A。
  # 當obj.wait()方法返回後,線程A須要再次得到obj鎖,才能繼續執行。
  # 若是A1,A2,A3都在obj.wait(),則B調用obj.notify()只能喚醒A1,A2,A3中的一個(具體哪個由JVM決定)
  # obj.notifyAll()則能所有喚醒A1,A2,A3,可是要繼續執行obj.wait()的下一條語句,必須得到obj鎖,所以,A1,A2,A3只有一個有機會得到鎖繼續執行,例如A1,其他的須要等待A1釋放obj鎖以後才能繼續執行。
  # 當B調用obj.notify/notifyAll的時候,B正持有obj鎖,所以,A1,A2,A3雖被喚醒,可是仍沒法得到obj鎖。直到B退出synchronized塊,釋放obj鎖後,A1,A2,A3中的一個纔有機會得到鎖繼續執行。


例1:
單個線程對多個線程的喚醒

      假設只有一個Game對象,但有3我的要玩,因爲只有一個遊戲資源,必須必然依次玩。web

  1. /**
  2.  * 玩遊戲的人.
  3.  * @version V1.0 ,2011-4-8
  4.  * @author xiahui
  5.  */
  6. public class Player implements Runnable {
  7.     private final int id;
  8.     private Game game;
  9.     public Player(int id, Game game) {
  10.         this.id = id;
  11.         this.game = game;
  12.     }
  13.     public String toString() {
  14.         return "Athlete<" + id + ">";
  15.     }
  16.     public int hashCode() {
  17.         return new Integer(id).hashCode();
  18.     }
  19.     
  20.     public void playGame() throws InterruptedException{
  21.         System.out.println(this.toString() + " ready!");
  22.         game.play(this);
  23.     }
  24.     public void run() {
  25.         try {
  26.             playGame();
  27.         } catch (InterruptedException e) {
  28.             System.out.println(this + " quit the game");
  29.         }
  30.     }
  31. }

遊戲類,只實例化一個設計模式

  1. import java.util.HashSet;
  2. import java.util.Iterator;
  3. import java.util.Set;
  4. /**
  5.  * 遊戲類.
  6.  * @version V1.0 ,2011-4-8
  7.  * @author xiahui
  8.  */
  9. public class Game implements Runnable {
  10.     private boolean start = false;
  11.     public void play(Player player) throws InterruptedException {
  12.         synchronized (this) {
  13.             while (!start)
  14.                 wait();
  15.             if (start)
  16.                 System.out.println(player + " have played!");
  17.         }
  18.     }
  19.     //通知全部玩家
  20.     public synchronized void beginStart() {
  21.         start = true;
  22.         notifyAll();
  23.     }
  24.     public void run() {
  25.         start = false;
  26.         System.out.println("Ready......");
  27.         System.out.println("Ready......");
  28.         System.out.println("game start");
  29.         beginStart();//通知全部玩家遊戲準備好了
  30.     }
  31.     public static void main(String[] args) {
  32.         Set<Player> players = new HashSet<Player>();
  33.         //實例化一個遊戲
  34.         Game game = new Game();
  35.         
  36.         //實例化3個玩家
  37.         for (int i = 0; i < 3; i++)
  38.             players.add(new Player(i, game));
  39.         
  40.         //啓動3個玩家
  41.         Iterator<Player> iter = players.iterator();
  42.         while (iter.hasNext())
  43.             new Thread(iter.next()).start();
  44.         Thread.sleep(100);
  45.         
  46.         //遊戲啓動
  47.         new Thread(game).start();
  48.     }
  49. }

程序先啓動玩家,三個玩家競爭玩遊戲,但只能有一個進入play,其餘二個等待,進入的玩家發現遊戲未準備好,因此wait,等遊戲準備好後,依次玩。
運行結果多線程

  1. Athlete<0> ready!
  2. Athlete<1> ready!
  3. Athlete<2> ready!
  4. Ready......
  5. Ready......
  6. game start
  7. Athlete<2> have played!
  8. Athlete<1> have played!
  9. Athlete<0> have played!


3.一次喚醒一個線程
      一次喚醒全部玩家,但只有一個玩家能玩,不如一個一個喚醒
將上面的代碼修改以下ui

  1.     public void play(Player player) throws InterruptedException {
  2.         synchronized (this) {
  3.             while (!start)
  4.                 wait();
  5.             if (start){
  6.                 System.out.println(player + " have played!");
  7.                 notify();//玩完後,通知下一個玩家來玩
  8.             }
  9.         }
  10.     }
  11.     //通知一個玩家
  12.     public synchronized void beginStart() {
  13.         start = true;
  14.         notify();
  15.     }


4.suspend掛起
      該方法已不建議使用,例子以下
例2:suspend方法進行掛起和喚醒this

  1. /**
  2.  * suspend方法進行掛起和喚醒.
  3.  * @version V1.0 ,2011-3-27 
  4.  * @author xiahui
  5.  */
  6. public class SuspendThread implements Runnable{
  7.     public void run() {
  8.         try {
  9.             Thread.sleep(10);
  10.         } catch (Exception e) {
  11.             System.out.println(e);
  12.         }
  13.         for (int i = 0; i <= 1; i ) {
  14.             System.out.println(Thread.currentThread().getName() ":" i);
  15.         }
  16.     }
  17.     public static void main(String args[]) throws Exception {
  18.         Thread th1 = new Thread(new SuspendThread(),"thread1");
  19.         Thread th2 = new Thread(new SuspendThread(),"thread2");
  20.         System.out.println("Starting " th1.getName() "...");
  21.         th1.start();
  22.         System.out.println("Suspending " th1.getName() "...");
  23.         //Suspend the thread.
  24.         th1.suspend();
  25.         th2.start();
  26.         th2.join();
  27.         // Resume the thread.
  28.         th1.resume();
  29.     }
  30. }

運行結果spa

  1. Starting thread1...
  2. Suspending thread1...
  3. thread2:0
  4. thread2:1
  5. thread1:0
  6. thread1:1

注意:
      若是註釋掉//th2.join();則thread2運行後,主線程會直接執行thread1的resume,運行結果可能會是.net

  1. Starting thread1...
  2. Suspending thread1...
  3. thread1:0
  4. thread1:1
  5. thread2:0
  6. thread2:1



參考文獻
1.Java多線程設計模式:瞭解wait/notify機制. http://webservices.ctocio.com.cn/wsjavtec/335/8580335.shtml2.Java中使用wait()與notify()實現線程間協做. http://www.bianceng.cn/Programming/Java/201103/25215.htm

相關文章
相關標籤/搜索