1. 程式人生 > >java 中的sleep()和wait() 等的區別和詳解

java 中的sleep()和wait() 等的區別和詳解

1、sleep()

  使當前執行緒(即呼叫該方法的執行緒)暫停執行一段時間,讓其他執行緒有機會繼續執行,但它並不釋放物件鎖。也就是說如果有synchronized同步快,其他執行緒仍然不能訪問共享資料。注意該方法要捕捉異常。
例如有兩個執行緒同時執行(沒有synchronized)一個執行緒優先順序為MAX_PRIORITY,另一個為MIN_PRIORITY,如果沒有Sleep()方法,只有高優先順序的執行緒執行完畢後,低優先順序的執行緒才能夠執行;但是高優先順序的執行緒sleep(500)後,低優先順序就有機會執行了。

總之,sleep()可以使低優先順序的執行緒得到執行的機會,當然也可以讓同優先順序、高優先順序的執行緒有執行的機會。

2、join()

  join()方法使呼叫該方法的執行緒在此之前執行完畢,也就是等待該方法的執行緒執行完畢後再往下繼續執行。注意該方法也需要捕捉異常。

3、yield()

  該方法與sleep()類似,只是不能由使用者指定暫停多長時間,並且yield()方法只能讓同優先順序的執行緒有執行的機會。

4、wait()和notify()、notifyAll()

  這三個方法用於協調多個執行緒對共享資料的存取,所以必須在synchronized語句塊內使用。synchronized關鍵字用於保護共享資料,阻止其他執行緒對共享資料的存取,但是這樣程式的流程就很不靈活了,如何才能在當前執行緒還沒退出synchronized資料塊時讓其他執行緒也有機會訪問共享資料呢?此時就用這三個方法來靈活控制。
wait()方法使當前執行緒暫停執行並釋放物件鎖標示,讓其他執行緒可以進入synchronized資料塊,當前執行緒被放入物件等待池中。當呼叫notify()方法後,將從物件的等待池中移走一個任意的執行緒並放到鎖標誌等待池中,只有鎖標誌等待池中執行緒能夠獲取鎖標誌;如果鎖標誌等待池中沒有執行緒,則notify()不起作用。
notifyAll()則從物件等待池中移走所有等待那個物件的執行緒並放到鎖標誌等待池中。
注意 這三個方法都是java.lang.Object的方法。

5、run和start()

  把需要處理的程式碼放到run()方法中,start()方法啟動執行緒將自動呼叫run()方法,這個由java的記憶體機制規定的。並且run()方法必需是public訪問許可權,返回值型別為void。

6、關鍵字synchronized

  該關鍵字用於保護共享資料,當然前提條件是要分清哪些資料是共享資料。每個物件都有一個鎖標誌,當一個執行緒訪問到該物件,被Synchronized修飾的資料將被”上鎖”,阻止其他執行緒訪問。當前執行緒訪問完這部分資料後釋放鎖標誌,其他執行緒就可以訪問了。

7、wait()和notify(),notifyAll()是Object類的方法,sleep()和yield()是Thread類的方法。

(1)、常用的wait方法有wait()和wait(long timeout);

void wait() 在其他執行緒呼叫此物件的 notify() 方法或者 notifyAll()方法前,導致當前執行緒等待。
void wait(long timeout)在其他執行緒呼叫此物件的notify() 方法 或者 notifyAll()方法,或者超過指定的時間量前,導致當前執行緒等待。
wait()後,執行緒會釋放掉它所佔有的“鎖標誌”,從而使執行緒所在物件中的其他synchronized資料可被別的執行緒使用。

wait()notify()因為會對物件的“鎖標誌”進行操作,所以他們必需在Synchronized函式或者 synchronized block 中進行呼叫。如果在non-synchronized 函式或 non-synchronized block 中進行呼叫,雖然能編譯通過,但在執行時會發生IllegalMonitorStateException的異常。。

(2)、Thread.sleep(long millis)必須帶有一個時間引數

  • sleep(long)使當前執行緒進入停滯狀態,所以執行sleep()的執行緒在指定的時間內肯定不會被執行;
  • sleep(long)可使優先順序低的執行緒得到執行的機會,當然也可以讓同優先順序的執行緒有執行的機會;
  • sleep(long)是不會釋放鎖標誌的。

(3)、yield()沒有引數

sleep 方法使當前執行中的執行緒睡眠一段時間,進入不可以執行狀態,這段時間的長短是由程式設定的,yield方法使當前執行緒讓出CPU佔有權,但讓出的時間是不可設定的。

yield()也不會釋放鎖標誌。實際上,yield()方法對應瞭如下操作;先檢測當前是否有相同優先順序的執行緒處於同可執行狀態,如有,則把CPU的佔有權交給次執行緒,否則繼續執行原來的執行緒,所以yield()方法稱為“退讓”,它把執行機會讓給了同等級的其他執行緒。

sleep 方法允許較低優先順序的執行緒獲得執行機會,但yield()方法執行時,當前執行緒仍處在可執行狀態,所以不可能讓出較低優先順序的執行緒此時獲取CPU佔有權。在一個執行系統中,如果較高優先順序的執行緒沒有呼叫sleep方法,也沒有受到I/O阻塞,那麼較低優先順序執行緒只能等待所有較高優先順序的執行緒執行結束,方可有機會執行。

yield()只是使當前執行緒重新回到可執行狀態,所有執行yield()的執行緒有可能在進入到可執行狀態後馬上又被執行,所以yield()方法只能使同優先順序的執行緒有執行的機會。

常用的sleep和wait,synchronized的使用案例程式碼如下:

package com.javathread;


public class ThreadTest {

    public static void main(String[] args) {

        new Thread(new Thread1()).start();

        synchronized (ThreadTest.class) {

            System.out.println("Main Thread go to sleep : currenttime-->"+ System.currentTimeMillis());

            // sleep 過程不會釋放資源
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        System.out.println("Main Thread get up : currenttime-->"+ System.currentTimeMillis());

        new Thread(new Thread2()).start();

        System.out.println("Main Thread over");





    }

    //執行緒一

    static class Thread1 implements Runnable{

        @Override
        public void run() {

            System.out.println("Thread1 is ready: currenttime-->"+System.currentTimeMillis());

            //因為sleep 不會釋放資源,所以在主執行緒sleep結束前,是不能獲取資源鎖的,而是在等待。。

            synchronized (ThreadTest.class) {

                System.out.println("Thread1 is running : currenttime-->"+System.currentTimeMillis());
                System.out.println("Thread1 is wait : currenttime-->"+System.currentTimeMillis());

                try {
                     //呼叫wait()方法,執行緒會放棄物件鎖,進入等待此物件的等待鎖定池
                    ThreadTest.class.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println("Thread1 is over");


            }



        }

    }

    //執行緒二
    static class Thread2 implements Runnable {

        @Override
        public void run() {

            System.out.println("Thread2 is ready :currenttime-->"+ System.currentTimeMillis());

            synchronized (ThreadTest.class) {

                System.out.println("Thread2 is running :currenttime-->"+ System.currentTimeMillis());

                System.out.println("Thread2 notify :currenttime-->"+ System.currentTimeMillis());

                ThreadTest.class.notify();

                System.out.println("Thread2 is over");

            }

        }

    }

}

執行結果如下:

Main Thread go to sleep : currenttime-->1478616007341
Thread1 is ready: currenttime-->1478616007341
Main Thread get up : currenttime-->1478616012341
Thread1 is running : currenttime-->1478616012341
Thread1 is wait : currenttime-->1478616012341
Main Thread over
Thread2 is ready :currenttime-->1478616012342
Thread2 is running :currenttime-->1478616012342
Thread2 notify :currenttime-->1478616012342
Thread2 is over
Thread1 is over

之前總是記不住java執行緒中這些屬性的用法,索性記錄了下來,寫例子加深印象~,共勉!