1. 程式人生 > >wait執行緒阻塞

wait執行緒阻塞

介紹

執行緒阻塞通常是指一個執行緒在執行過程中由於某種原因從執行狀態轉為暫停狀態的過程,執行緒阻塞會放棄CPU的使用權, 並且等待某個條件重新從暫停狀態改為就緒狀態。在Java中,通常使用object.wait讓執行緒進入阻塞狀態。

使用

首先我們先看wait方法,wait方法總共有三個過載方法,分別是 wait() wait(long timeout) wait(long timeout, int nanos),其中wait方法內部是呼叫了wait(0),顧名思義timeout就是超時時間,那麼timeout等於0是什麼意思呢,檢視官方API如下:
這裡寫圖片描述
意思就是如果timeout是0,不需考慮超時時間,即執行緒會無限等待直到被喚醒。
下面寫一個demo,程式碼如下:

    public static void main(String args[]) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println( "執行執行緒中");
            }
        });
        thread.setName("MyThread");
        thread.start();
        
        try{
            thread.wait();
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(thread.getName() + "已經執行結束");
    }

預想的輸出結果應該是

執行執行緒中
MyThread已經執行結束

實際上報錯了

Exception in thread "main" java.lang.IllegalMonitorStateException

檢視wait的API介紹有這麼一句標註 The current thread must own this object’s monitor.,大意就是執行wait方法的執行緒必須持有執行緒的物件鎖,使用synchronized對thread物件加鎖既可,程式碼如下:

        try{
            synchronized (thread) {
                thread.wait();
            }
        }catch (InterruptedException e) {
            e.printStackTrace();
        }

這樣一來,通過synchronize既可獲取執行緒的物件鎖,就可以達到阻塞執行緒的作用了,有人可能會疑惑說為什麼沒有呼叫notify方法,這是因為當執行緒死亡之後,相應的wait方法也會失效。

當然對於執行緒的阻塞,通用使用執行緒的join方法,程式碼如下:

    public static void main(String args[]) {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println( "執行執行緒1中");
            }
        });
        thread1.setName("MyThread -- 1");
        thread1.start();

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println( "執行執行緒2中");
            }
        });
        thread2.setName("MyThread -- 2");
        thread2.start();

        try{
            thread1.join();
            thread2.join();
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(thread1.getName() + " " + thread2.getName()  + "  已經執行結束");
    }

通過呼叫join方法,就可以讓執行緒阻塞,我們看一下join的方法實現:

    public final synchronized void join(long var1) throws InterruptedException {
        long var3 = System.currentTimeMillis();
        long var5 = 0L;
        if (var1 < 0L) {
            throw new IllegalArgumentException("timeout value is negative");
        } else {
            if (var1 == 0L) {
                while(this.isAlive()) {
                    this.wait(0L);
                }
            } else {
                while(this.isAlive()) {
                    long var7 = var1 - var5;
                    if (var7 <= 0L) {
                        break;
                    }

                    this.wait(var7);
                    var5 = System.currentTimeMillis() - var3;
                }
            }

        }
    }

其實就是當執行緒還存活時,呼叫wait方法。需要注意的是,join方法是synchronize的,因為需要獲取物件鎖。

參考