多線程下的wait為什么可以不需要notify


多線程下的wait方法就像我無處安放的青春,胡亂來,感覺沒有一點套路。wait后不需要notify仍可以繼續執行。所以我決定看看到底咋回事。。。。。

先結合join方法了解一下。

join方法是可以等待其它線程執行完成的方法。就像Main線程需要等待A、B執行完畢,只需要執行a.join(),b.join()即可,主線程會阻塞等待A、B線程執行完畢。

join源碼:

public final void join() throws InterruptedException {
  join(0);
}

 

發現其使用的是join(long millis)

即:

    public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

 

可見,其實現使用的是wait方法。使用wait方法阻塞當前線程。此時就產生了一個很尷尬的問題,join內部使用wait后並沒有notify或notifyAll,線程不會一直阻塞嗎?

進入正題

查看一個wait列子:

public class WaitTest  {
    public static void main(String[] args) throws InterruptedException {
        Thread b = new B();
        new WaitTest().test(b);
    }

    public  void test(Thread b) throws InterruptedException {
        synchronized (b) {
            b.start();
            System.out.println("主方法開始執行");
            b.wait();
            System.out.println("主方法執行完畢");
        }
    }
}
class B extends Thread {
    @Override
    public void run() {
        synchronized (this) {
            System.out.println("開始執行線程B");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("B線程執行完畢");
        }
    }
}

 執行結果:

主方法開始執行
開始執行線程B
B線程執行完畢
主方法執行完畢

 

 可以見到主線程正常執行完畢了。十分疑惑了,從小老師就告訴我wait需要notify或notifyAll喚醒,咋滴多線程情況下膨脹了,不聽使喚了,一個wait可以單干了?

翻箱倒櫃一通倒騰,終於在openJDK源碼里找到了原因:

static void ensure_join(JavaThread* thread) {
  // We do not need to grab the Threads_lock, since we are operating on ourself.
  Handle threadObj(thread, thread->threadObj());
  assert(threadObj.not_null(), "java thread object must exist");
  ObjectLocker lock(threadObj, thread);
  // Ignore pending exception (ThreadDeath), since we are exiting anyway
  thread->clear_pending_exception();
  // Thread is exiting. So set thread_status field in  java.lang.Thread class to TERMINATED.
  java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
  // Clear the native thread instance - this makes isAlive return false and allows the join()
  // to complete once we've done the notify_all below
  java_lang_Thread::set_thread(threadObj(), NULL);
  lock.notify_all(thread); // Ignore pending exception (ThreadDeath), since we are exiting anyway
  thread->clear_pending_exception();
}

 

 調用鏈是:run() -> thread_main_inner() -> exit() -> ensure_join()。意思就是線程要結束之前肯定會調上邊這個ensure_join方法,而這個方法執行了lock.notify_all(thread)。可見老師沒騙我,wait是需要notify或notifyAll喚醒的,只不過是線程結束時,虛擬機幫我們做了一次notifyAll。

最后奉勸各位小伙伴:

盡量不要使用線程本身的監視器鎖,不然可能會出現非預期的線程喚醒= =、

 


免責聲明!

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



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