(九)、線程sleep和wait的區別


功能差不多,都用來進行線程控制。

sleep()方法

sleep是線程類(Thread)的靜態方法。

sleep的作用是讓線程休眠制定的時間,在時間到達時恢復,也就是說sleep將在接到時間到達事件事恢復線程執行。

例如

try{
    System.out.println("I'm going to bed");
    Thread.sleep(1000);
    System.out.println("I wake up");
}catch(IntrruptedException e) {
}

 

讓調用的線程進入指定時間睡眠狀態,使得當前線程進入阻塞狀態,告訴系統至少在指定時間內不需要為線程調度器為該線程分配執行時間片,給執行機會給其他線程(實際上,調用sleep()方法時並不要求持有任何鎖,即sleep()可在任何地方使用。),但是監控狀態依然保持,到時后會自動恢復

sleep()休眠時間滿后,該線程不一定會立即執行,這是因為其他線程可能正在運行而起沒有被調度為放棄執行,除非此線程具有更高的優先級。

 sleep()必須捕獲異常。

在sleep的過程中過程中有可能被其他對象調用它的interrupt(),產生InterruptedException異常,如果你的程序不捕獲這個異常,線程就會異常終止,進入TERMINATED狀態,如果你的程序捕獲了這個異常,那么程序就會繼續執行catch語句塊(可能還有finally語句塊)以及以后的代碼。

在沒有鎖的情況下,sleep()可以使低優先級的線程得到執行的機會,當然也可以讓同優先級、高優先級的線程有執行的機會。

 

wait()方法

wait()方法是Object類里的方法。

當一個線程執行wait()方法時,它就進入到一個和該對象相關的等待池中(進入等待隊列,也就是阻塞的一種,叫等待阻塞),同時釋放對象鎖,並讓出CPU資源,待指定時間結束后返還得到對象鎖。

wait()使用notify()方法、notiftAll()方法或者等待指定時間來喚醒當前等待池中的線程。

 

try{
    obj.wait();  //suspend thread until obj.notify() is called
}catch(InterrputedException e) {
}

 

 

 

等待的線程只是被激活,但是必須得再次獲得鎖才能繼續往下執行,也就是說只要鎖沒被釋放,原等待線程因為為獲取鎖仍然無法繼續執行。

notify的作用只負責喚醒線程,線程被喚醒后有權利重新參與線程的調度。

wait()方法、notify()方法和notiftAll()方法用於協調多線程對共享數據的存取,所以只能在同步方法或者同步塊中使用,否則拋出IllegalMonitorStateException。

 

兩者的區別

(1)屬於不同的兩個類,sleep()方法是線程類(Thread)的靜態方法,wait()方法是Object類里的方法。

(2)sleep()方法不會釋放鎖,wait()方法釋放對象鎖。

(3)sleep()方法可以在任何地方使用,wait()方法則只能在同步方法或同步塊中使用。

(4)sleep()必須捕獲異常,wait()方法、notify()方法和notiftAll()方法不需要捕獲異常。

(5)sleep()使線程進入阻塞狀態(線程睡眠),wait()方法使線程進入等待隊列(線程掛起),也就是阻塞類別不同。

   (6)  它們都可以被interrupted方法中斷。

 

wait(1000)與sleep(1000)的區別

Thread.Sleep(1000) 

意思是在未來的1000毫秒內本線程不參與CPU競爭,1000毫秒過去之后,這時候也許另外一個線程正在使用CPU,那么這時候操作系統是不會重新分配CPU的,直到那個線程掛起或結束。

即使這個時候恰巧輪到操作系統進行CPU 分配,那么當前線程也不一定就是總優先級最高的那個,CPU還是可能被其他線程搶占去。

另外值得一提的是Thread.Sleep(0)的作用,就是觸發操作系統立刻重新進行一次CPU競爭,競爭的結果也許是當前線程仍然獲得CPU控制權,也許會換成別的線程獲得CPU控制權。

 

wait(1000)

表示將鎖釋放1000毫秒,到時間后如果鎖沒有被其他線程占用,則再次得到鎖,然后wait方法結束,執行后面的代碼,如果鎖被其他線程占用,則等待其他線程釋放鎖。

注意,設置了超時時間的wait方法一旦過了超時時間,並不需要其他線程執行notify也能自動解除阻塞,但是如果沒設置超時時間的wait方法必須等待其他線程執行notify。

實例:

public class test{
    public static void main(String[] args) {
        Integer i = new Integer(1);
        new Thread(new waitThread(i)).start();
        new Thread(new notifyThread(i)).start();
    }
}

class waitThread implements Runnable{
    Integer i;
    public waitThread(Integer i){
        super();
        this.i = i;
    }

    @Override
    public void run(){
        try{
            synchronized(i){
                long start = System.currentTimeMillis();
                i.wait(1000);
                System.out.println("waitThread "+(System.currentTimeMillis()-start)+" done");
            }
        }catch(InterruptedException e){
            e.printStackTrace();
        }
    }
}

class notifyThread implements Runnable{
    Integer i;
    public notifyThread(Integer i){
        super();
        this.i = i;
    }

    @Override
    public void run(){
        try{
            long start = System.currentTimeMillis();
            //如果此處設成1500,因為sleep沒有占有鎖,wait方法在1000ms后會自動再次獲得鎖然后解除阻塞執行。
            Thread.sleep(500); 
            synchronized(i){
                Thread.sleep(1500);
                //如果wait過了超時時間,無論有無notify,wait都會自動解除阻塞,即該句可以注釋,不影響結果。
                //但是如果wait沒有設置超時時間,該句必須存在,否則waitThread用於處於阻塞狀態。
                i.notify();
                System.out.println("notifyThread "+(System.currentTimeMillis()-start)+" done");
            }
        }catch(InterruptedException e){
            e.printStackTrace();
        }
    }
}

 

join()方法:

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

yield()方法:

       該方法與sleep()類似,都是可以讓當前正在運行的線程暫停,區別在於yield()方法不會阻塞該線程,它只是將線程轉換成就緒狀態,讓系統的調度器重新調度一次,並且yield()方法只能讓優先級相同或許更高的線程有執行的機會。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM