1. 程式人生 > >執行緒:sleep()、wait()、yield()和join()方法

執行緒:sleep()、wait()、yield()和join()方法

  1.sleep()和wait()

        這兩個方法都可以讓呼叫它的執行緒沉睡(sleep)/停止執行(wait)指定的時間,到了這個時間,執行緒就會自動醒來,變為可執行狀態(RUNNABLE)。

        public static native void sleep(long millis) throws InterruptedException;   
        public static void sleep(long millis, int nanos) throws InterruptedException 

        public final void wait() throws InterruptedException

        public final native void wait(long timeout) throws InterruptedException;   
        public final void wait(long timeout, int nanos) throws InterruptedException 

        Parameters:
        millis - the length of time to sleep in milliseconds.毫秒數
        nanos - 0-999999 additional nanoseconds to sleep.納秒數


        呼叫sleep()方法並不會讓執行緒釋放它所持有的同步鎖;而且在這期間它也不會阻礙其它執行緒的執行。
        當呼叫了某個物件的wait()方法時,當前執行的執行緒就會轉入WAITING狀態,等待別的執行緒再次呼叫這個物件的notify()或者notifyAll()方法喚醒它,或者到了指定的最大等待時間,執行緒自動醒來。如果執行緒呼叫了某個物件的wait()方法,這個執行緒就會釋放這個物件所持有的同步資源(不會釋放其他物件的同步鎖)。
  1. package edu.hust.test;
  2. publicclass ThreadSleep implements Runnable {
  3. /*
  4.      * 讓執行緒睡眠的理由很多,比如(1)認為該執行緒執行得太快,需要減緩一下,以便和其他執行緒協調;(2)查詢當時的股票價格,每睡5分鐘查詢一次,可以節省頻寬,而且即時性要求也不那麼高。
  5.      * 注意:時間的精確性。執行緒醒來之後不會馬上執行,而要等待cpu給其分配時間片。因此sleep()中指定的時間並不是執行緒不執行的精確時間!所以不能依賴sleep()方法提供十分精確的定時。
  6.      * 我們可以看到很多應用程式用sleep()作為定時器,實際是不精確的。
  7.      * 
  8.      * 
  9.      * Thread.sleep(5 * 1000)和Thread.currentThread().sleep(5 * 1000)沒區別:都表示讓當前執行緒sleep 5秒.
  10.      * 一個是通過類獲取靜態方法,一個是通過例項物件獲得靜態方法(sleep()為靜態方法).
  11.      * 
  12.      * 注意:sleep並不是Thread的一個STATE
  13.      */
  14.     publicvoid execute() {
  15. synchronized(this) {
  16. try {
  17.                 System.out.println(Thread.currentThread().getName() + ", sleep()前");
  18.                 Thread.sleep(1000);
  19.                 System.out.println(Thread.currentThread().getName() + ", sleep()後");
  20.             } catch (InterruptedException e) {
  21.                 System.out.println(Thread.currentThread().getName() + ", 誰把我吵醒了.....");
  22.             }
  23. //此處如果使用System.err, 會有很意外的結果。System.out和System.err的區別請見blog
  24.             System.out.println(Thread.currentThread().getName() + ", run()結束..進入TERMINATED狀態");
  25.         }
  26.     }
  27. publicvoid run() {
  28.         execute();
  29.     }
  30. publicstaticvoid main(String[] args) throws InterruptedException {
  31.         ThreadSleep threadSleep = new ThreadSleep();
  32.         Thread[] threads = new Thread[5];
  33.         System.out.println(Thread.currentThread().getName() + "執行緒的狀態為:" + Thread.currentThread().getState());
  34. for (Thread thread : threads) {
  35.             thread = new Thread(threadSleep);
  36.             thread.start();
  37. if ("Thread-1".equals(thread.getName()) || "Thread-3".equals(thread.getName()))
  38.                 thread.interrupt();
  39.         }
  40.     }
  41. /*
  42.      * 某次執行結果:
  43.      * main執行緒的狀態為:RUNNABLE
  44.      * Thread-1, sleep()前
  45.      * Thread-1, 誰把我吵醒了.....
  46.      * Thread-1, run()結束..進入TERMINATED狀態
  47.      * 
  48.      * Thread-3, sleep()前
  49.      * Thread-3, 誰把我吵醒了.....
  50.      * Thread-3, run()結束..進入TERMINATED狀態
  51.      * 
  52.      * Thread-0, sleep()前
  53.      * Thread-0, sleep()後
  54.      * Thread-0, run()結束..進入TERMINATED狀態
  55.      * 
  56.      * Thread-2, sleep()前
  57.      * Thread-2, sleep()後
  58.      * Thread-2, run()結束..進入TERMINATED狀態
  59.      * 
  60.      * Thread-4, sleep()前
  61.      * Thread-4, sleep()後
  62.      * Thread-4, run()結束..進入TERMINATED狀態
  63.      * 
  64.      * 從執行結果可以得出很多結論, 其中之一是:呼叫sleep()方法並不會讓執行緒釋放它所持有的同步鎖;而且在這期間它也不會阻礙其它執行緒的執行。
  65.      * 
  66.      * */
  67. }
  1. package edu.hust.test;
  2. class MyThread1 implements Runnable {
  3. private Object obj;
  4. public MyThread1(Object o) {
  5.         obj = o;
  6.     }
  7. publicvoid run() {
  8. synchronized (obj) { //這裡是給obj物件(也就是str="愛吃土豆")加鎖, 如寫成synchronized (this), 則表示是給myThread1加鎖.
  9. try {
  10.                 System.out.println("MyThread1進入wait狀態");
  11.                 obj.wait();
  12.                 System.out.println("MyThread1被notify");
  13.             } catch (InterruptedException e) {
  14.                 System.err.println("誰把我吵醒了.....");
  15.             }
  16.         }
  17.     }
  18. }
  19. class MyThread2 implements Runnable {
  20. private Object obj;
  21. public MyThread2(Object o) {
  22.         obj = o;
  23.     }
  24. publicvoid run() {
  25. synchronized (obj) {  //這裡是給obj物件(也就是str="愛吃土豆")加鎖, 如寫成synchronized (this), 則表示是給myThread2加鎖.
  26.             System.out.println("MyThread2呼叫notify()方法");
  27.             obj.notify();
  28.         }
  29.     }
  30. }
  31. publicclass ThreadWait {
  32. publicstaticvoid main(String[] args) {
  33. //錯誤的寫法, 這裡myThread1和myThread2操作的是兩個不同的物件.
  34. //Thread myThread1 = new Thread(new MyThread1(new String("愛吃土豆")));
  35. //Thread myThread2 = new Thread(new MyThread2(new String("愛吃土豆")));
  36. //正確的寫法, 這裡myThread1和myThread2操作的是同一個物件.
  37.         String str = "愛吃土豆";
  38.         Thread myThread1 = new Thread(new MyThread1(str));
  39.         Thread myThread2 = new Thread(new MyThread2(str));
  40.         myThread1.start();
  41.         myThread2.start();
  42.     }
  43. /*
  44.      * 執行結果:
  45.      * MyThread1進入wait狀態
  46.      * MyThread2呼叫notify()方法
  47.      * MyThread1被notify
  48.      * 
  49.      * 這裡使用了synchronized塊來包裝某個例項物件(String str = "愛吃土豆")的wait()和notify()方法, 這是由於呼叫這兩個方法的時候執行緒必須獲得同步鎖.
  50.      * 如果synchronized包裝的不是同一個例項物件的wait()和notify()方法, 則表示給wait()和notify()加的鎖不是同一把鎖,eg:將synchronized(lock)改為synchronized(this).
  51.      * 將會丟擲java.lang.IllegalMonitorStateException, 告訴你current thread not owner.
  52.      * 
  53.      * */
  54.     /*
  55.      * 摘錄:
  56.      * 多執行緒常用的一些方法: wait(),wait(long),notify(),notifyAll()
  57.      * wait()      是使持有物件鎖的執行緒釋放鎖;
  58.      * wait(long)  是使持有物件鎖的執行緒釋放鎖時間為long(毫秒)後,再次獲得鎖,wait()和wait(0)等價;
  59.      * notify()    是喚醒一個正在等待該物件鎖的執行緒,如果等待的執行緒不止一個,那麼被喚醒的執行緒由jvm確定;
  60.      * notifyAll   是喚醒所有正在等待該物件鎖的執行緒.
  61.      * 
  62.      * 應該優先使用notifyAll()方法, 因為喚醒所有執行緒比喚醒一個執行緒更容易讓jvm找到最適合被喚醒的執行緒.
  63.      * 對於上述方法,只有在當前執行緒中才能使用,否則報執行時錯誤java.lang.IllegalMonitorStateException: current thread not owner.
  64.      * 從實現角度來分析:
  65.      * 線上程呼叫wait()方法時,需要把它放到一個同步段裡,否則將會出現"java.lang.IllegalMonitorStateException: current thread not owner"的異常。
  66.      * 
  67.      * */
  68. }
  1. package edu.hust.test;
  2. publicclass ThreadWait2 implements Runnable {
  3. private Object monitor1 = new Object();
  4. private Object monitor2 = new Object();
  5. publicvoid run() {
  6. synchronized (monitor1) {
  7.             System.out.println("monitor1被鎖住了");
  8. synchronized (monitor2) {
  9.                 System.out.println("monitor2被鎖住了");
  10. try {
  11.                     System.out.println("monitor2進入wait()狀態");
  12.                     monitor2.wait();
  13.                 } catch (InterruptedException e) {
  14.                     System.out.println("誰把我吵醒了.....");
  15.                 }
  16.             }
  17.         }
  18.     }
  19. publicvoid getMonitor() throws InterruptedException {
  20.         Thread.sleep(3 * 1000); //讓main Thread延遲3秒執行, 使myThread獲得足夠時間進行執行緒初始化