1. 程式人生 > >Thread的wait方法理解

Thread的wait方法理解

wait方法是Object物件的方法。執行緒與鎖是分不開的,執行緒的同步、等待、喚醒都與物件鎖是密不可分的。wait方法會將當前執行緒放入wait set,等待被喚醒,並放棄lock物件上的所有同步宣告,當前執行緒會因為執行緒排程的原因處於休眠狀態而不可用。只有通過以下四個方法可以主動喚醒:
1. notify
2. notifyAll
3. Thread.interrupt()
4. 等待時間過完。

當執行緒被喚醒後,執行緒就從wait set中移除了並且重新獲得執行緒排程能力,同時像其它執行緒一樣持有object的鎖。

一段synchronized的程式碼被一個執行緒執行之前,他要先拿到執行這段程式碼的許可權,
在Java裡邊就是拿到某個同步物件的鎖(一個物件只有一把鎖);
如果這個時候同步物件的鎖被其他執行緒拿走了,他(這個執行緒)就只能等了(執行緒阻塞在鎖池等待佇列中)。
取到鎖後,他就開始執行同步程式碼(被synchronized修飾的程式碼);
執行緒執行完同步程式碼後馬上就把鎖還給同步物件,其他在鎖池中等待的某個執行緒就可以拿到鎖執行同步程式碼了。


這樣就保證了同步程式碼在統一時刻只有一個執行緒在執行。

這裡就需要補充一下物件鎖和類鎖的區別。
事實上,synchronized修飾非靜態方法、同步程式碼塊的synchronized (this)用法和synchronized (非this物件)的用法鎖的是物件,執行緒想要執行對應同步程式碼,需要獲得物件鎖。

執行緒正常結束後,會使以這個執行緒物件執行的wait()等待,退出等待狀態!而如果在執行wait()之前,執行緒已經結束了,則這個wait就沒有程式喚醒了。
原碼裡的join()方法,實際上就是執行的 wait(). 需要執行join的執行緒執行join方法,實際上是在此執行緒上呼叫了需要加入的執行緒物件的wait()方法,加入的執行緒執行完後,自然從wait退出了。

 到此,就得出了我的結論:
1 執行緒物件的wait()方法執行後,可以不用其notify()方法退出,會線上程結束後,自動退出。
2 執行緒間的等待喚醒機制,最好不要用執行緒物件做同步鎖!

首先我們看一個例項:

public class TestDemo {
    public static void main(String []args) throws InterruptedException{
        MyThread myThread = new MyThread();
        System.out.println("before");
        myThread.start();
        System.out.println("after"
); } static class MyThread extends Thread{ public void run(){ synchronized (this) { for(int i=0;i<3;i++){ System.out.println("number:"+ i); } } } } }

輸出的結果是:
before
after
number:0
number:1
number:2

首先是Main執行緒具有搶佔cpu資源,然後執行完後,在開始執行子執行緒。

例項2:

public class TestDemo {
    public static void main(String []args) throws InterruptedException{
        MyThread myThread = new MyThread();
        System.out.println("before");
        myThread.start();
        synchronized (myThread) {
            myThread.wait();
        }
        System.out.println("after");
    }

    static class MyThread extends Thread{

        public void run(){
            synchronized (this) {
                for(int i=0;i<3;i++){
                    System.out.println("number:"+ i);
                }
            }
        }
    }
}

before
number:0
number:1
number:2
after

我們呼叫wait方法,Main執行緒會釋放當前鎖,進入wait set。然後子執行緒開始執行,當子執行緒執行完畢後,會把鎖歸還。