多线程下的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。
最后奉劝各位小伙伴:
尽量不要使用线程本身的监视器锁,不然可能会出现非预期的线程唤醒= =、