在什么情况下,不写notify()或者notifyAll()就能唤醒被wait()阻塞的线程?

之前再看java关于线程的某视频时,发现在JDK源码中,join()=join(0)=wait()=wait(0),但是视频中在join()了之后,并没有用notify()或者notifyAll()去唤醒,遂有了一个疑问:**在什么情况下,不写notify()或者notifyAll()就能唤醒被wait()阻塞的线程? **

**以下是思考的过程,如果不想看,可以直接跳到 总结。 **

**测试代码如下: **
main类

import  java.lang.*;

public class Main {

    public static void main(String[] args) {
        new ThreadOne().start();
    }
}

ThreadOne类

public class ThreadOne extends Thread{
    @Override
    public  void run(){
        System.out.println("1 start");
        ThreadTwo t2 = new ThreadTwo();
        t2.start();
        try {
            t2.join();  
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("1 end");
    }
}

ThreadTwo类

public class ThreadTwo extends Thread{
    @Override
    public synchronized  void run() {
        System.out.println("2 start");
        System.out.println("2 end");
    }
}

按理说,t1线程在调用t2的join()(在底层中相当于wait())之后,应该是被阻塞的。按照之前学的知识,wait()之后需要notify()或者notifyAll()才会被被唤醒,然而运行结果是这样的:


也就是说,代码中我并没有使用notify()或者notifyAll(),但是t1还是被唤醒了,是被谁唤醒的呢?

对此我有了初步猜测:t1线程在调用t2的wait()之后,被阻塞,在t2自己运行完run()了之后,会隐式调用notify()或者notifyAll(),去唤醒被t2的wait()阻塞的线程。

有了猜测就开始去调研啦
先是查询了一些博客:
https://blog.csdn.net/nmyangym/article/details/7850882
https://blog.csdn.net/Deronn/article/details/80450959

博客做过一些实验后,结论如下,和我的猜测差不多:

1.线程对象的wait()方法运行后,可以不用其notify()方法退出,会在线程结束后,自动退出。

2.线程间的等待唤醒机制,最好不要用线程对象做同步锁!

随后又去查看了JDK的源码,join(long millis)的注释是这样的:

* Waits at most {@code millis} milliseconds for this thread to
* die. A timeout of {@code 0} means to wait forever.
*
* <p> This implementation uses a loop of {@code this.wait} calls
* conditioned on {@code this.isAlive}. As a thread terminates the
* {@code this.notifyAll} method is invoked. It is recommended that
* applications not use {@code wait}, {@code notify}, or
* {@code notifyAll} on {@code Thread} instances.

其中的As a thread terminates the {@code this.notifyAll} method is invoked.告诉我们:一个线程在结束后,会调用notifyAll()方法。证实了我的初步猜测,隐式调用了notifyAll()方法。

但是在join(long millis)的代码实现中,告诉了我们join(0)实际上是调用了wait(0)方法。

if (millis == 0) {
    while (isAlive()) {
        wait(0);
    }
} 

我能不能追究到更细节的一些东西呢?然后我又去看了看wait(long timeout)的源码,它是个native方法,无法直接查看源码。

没法看wait()的源码咯,那就看看注释吧,然而注释并没能解决我的问题,好吧,就不钻牛角尖了。问题到此结束。

总结

**遇上的问题:** 众所周知,wait()之后要用notify()或者notifyAll()把线程从等待状态转为就绪状态。随后发现在底层JDK源码中,join()=join(0)=wait()=wait(0),但是在我的代码展示中,线程t1调用t2的wait()方法被阻塞后,并没有用notify()或者notifyAll()去唤醒,但是t1还是被唤醒了,究竟是谁唤醒的呢?

初步猜测:
t1线程在调用t2的wait()之后,被阻塞,在t2自己运行完run()了之后,会隐式调用notify()或者notifyAll(),去唤醒被t2的wait()阻塞的线程。

调研过程:
经过了查博客,查JDK源码(join()和wait())之后,发现在join()的注释里有这么一句话。As a thread terminates the {@code this.notifyAll} method is invoked.告诉我们:一个线程在结束后,会调用notifyAll()方法。

收获:
1.线程对象的wait()方法运行后,可以不用其notify()方法退出,因为一个线程在结束后,会调用notifyAll()方法。

2.线程间的等待唤醒机制,最好不要用线程对象做同步锁!

3.java源码中的native方法是不能直接在jdk中看到的,因为jdk不是开源的,要看到的话需要sun授权才行,现在只有openjdk是被sun公司授权。

4.博客园的markdown换行方式竟然不支持连续两个以上空格+回车

posted @ 2019-10-31 17:15  led二极管  阅读(468)  评论(0编辑  收藏  举报