之前再看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()的源码咯,那就看看注释吧,然而注释并没能解决我的问题,好吧,就不钻牛角尖了。问题到此结束。
<h3 id="final">总结</h3>
遇上的问题:
众所周知,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公司授权。