大家在学习Java的过程中,势必要进行多线程的系统学习,这部分内容知识对于你在工作中的影响是极大的,并且在面试的过程中,这部分知识也是必然会被问到的。既然多线程的知识如此重要,那么我们就不能浅尝辄止。在这篇文章中,我想通过阅读源码的方式给大家分享一下我自己对于Java中wait(),notify()和sleep()的理解,并且在后面我也做一些内容上的扩展,与大家共同思考。如果在文章中有描述不妥或者逻辑错误的地方,欢迎大家指正,谢谢!
wait()和sleep()
我们先简单的了解一下wait()和sleep()这两个方法:
首先wait()是属于Object类的方法,从源码给出的解释来看,wait()方法可以做到如下几点:
(1)首先,调用了wait()之后会引起当前线程处于等待状状态。
(2)其次,每个线程必须持有该对象的monitor。如果在当前线程中调用wait()方法之后,该线程就会释放monitor的持有对象并让自己处于等待状态。
(3)如果想唤醒一个正在等待的线程,那么需要开启一个线程通过notify()或者notifyAll()方法去通知正在等待的线程获取monitor对象。如此,该线程即可打破等待的状态继续执行代码。
代码演示:
从代码来看,在执行线程和线程结束之间,我们先让该线程获取object对象作为自己的object's monitor,然后调用了object对象的wait()方法从而让其进入等待状态。那么程序运行的结果如下:
程序在未被唤醒之后,将不再打印“线程结束”,并且程序无法执行完毕一直处于等待状态。
sleep()方法来自于Thread类,从源码给出的解释来看,sleep()方法可以做到如下几点:
(1)首先,调用sleep()之后,会引起当前执行的线程进入暂时中断状态,也即睡眠状态。
(2)其次,虽然当前线程进入了睡眠状态,但是依然持有monitor对象。
(3)在中断完成之后,自动进入唤醒状态从而继续执行代码。
代码演示:
从运行的结果来看,我们可以看出程序虽然在运行过程中中断了3秒,但是在3秒结束之后依然会继续执行代码,直到运行结束。在睡眠的期间内,线程会一直持有monitor对象。
那么从以上的理论和实践来分析,我们能得出如下结论:
(1)在线程的运行过程中,调用该线程持有monitor对象的wait()方法时,该线程首先会进入等待状态,并将自己持有的monitor对象释放。
(2)如果一个线程正处于等待状态时,那么唤醒它的办法就是开启一个新的线程,通过notify()或者notifyAll()的方式去唤醒。当然,需要注意的一点就是,必须是同一个monitor对象。
(3)sleep()方法虽然会使线程中断,但是不会将自己的monitor对象释放,在中断结束后,依然能够保持代码继续执行。
notify()和notifyAll()
notify()实现有序唤醒的思路和实现
在以上代码中,我写了三个线程A,B,C用来作为等待线程,并且最后通过一个唤醒线程来唤醒这三个线程。
最后运行的结果如下: