在什么情况下,不写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换行方式竟然不支持连续两个以上空格+回车
在什么情况下,不写notify()或者notifyAll()就能唤醒被wait()阻塞的线程?的更多相关文章
- JDK1.8 StampedLock: 解决ReentrantReadWriteLock在读多写少情况下,写线程饥饿问题
ReentrantReadWriteLock 在沒有任何读写锁时,才可以取得写入锁,这可用于实现了悲观读取(Pessimistic Reading), 即如果执行中进行读取时,经常可能有另一执行要写入 ...
- 什么情况下可以不写PHP的结束标签“?>”
我们经常看到有些PHP文件中的代码是只有开始标签,而没有结束标签的,那么什么情况下可以不写这个结束标签,而什么情况下必须写?先来看2个例子: 下面的代码正常运行: <?php echo 1234 ...
- MessagePack Java Jackson 在不关闭输出流(output stream)的情况下序列化多变量
com.fasterxml.jackson.databind.ObjectMapper 在默认的情况下在写出输入后将会关闭输出流(output stream). 如果你希望序列化多值变量在同一个输出流 ...
- 关于socket阻塞与非阻塞情况下的recv、send、read、write返回值(转载)
1.阻塞模式与非阻塞模式下recv的返回值各代表什么意思?有没有区别?(就我目前了解阻塞与非阻塞recv返回值没有区分,都是 <0:出错,=0:连接关闭,>0接收到数据大小,特别:返回值 ...
- UNIX网络编程——关于socket阻塞与非阻塞情况下的recv、send、read、write返回值
1.阻塞模式与非阻塞模式下recv的返回值各代表什么意思?有没有 区别?(就我目前了解阻塞与非阻塞recv返回值没有区分,都是 <0:出错,=0:连接关闭,>0接收到数据大小,特别:返回 ...
- 关于socket阻塞与非阻塞情况下的recv、send、read、write返回值---部分内容可能不确切,待讨论
1.阻塞模式与非阻塞模式下recv的返回值各代表什么意思?有没有区别?(就我目前了解阻塞与非阻塞recv返回值没有区分,都是 <0:出错,=0:连接关闭,>0接收到数据大小,特别:返回值 ...
- 如何使用wait(), notify() and notifyAll() – Java
Java多线程是个很复杂的问题,尤其在多线程在任何给定的时间访问共享资源需要更加注意.Java 5引入了一些类比如BlockingQueue 和Executors 类提供了易于使用的API,避免了一些 ...
- JAVA线程同步 (二)notify()与notifyAll()-***
编写多线程程序需要进行线程协作,前面介绍的利用互斥来防止线程竞速是来解决线程协作的衍生危害的.编写线程协作程序的关键是解决线程之间的协调问题,在这些任务中,某些可以并行执行,但是某些步骤需要所有的任务 ...
- 最简实例说明wait、notify、notifyAll的使用方法
wait().notify().notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态. 这三个方法最终调用的都是jvm级的native方法.随着jvm运行平台的不同可能有些 ...
随机推荐
- Apache 容器 Directory Location Files 及htaccess文件
配置段容器的类型 相关模块 core mod_proxy 相关指令 <Directory> <DirectoryMatch> <Files> <FilesMa ...
- 1213 - Fantasy of a Summation
1213 - Fantasy of a Summation If you think codes, eat codes then sometimes you may get stres ...
- java架构之路-(dubbo专题)dubbo的基本使用
今天我们来说一下dubbo的基本使用,没有什么高阶的知识,真的超级简单易懂. Dubbo核心功能解释 dubbo 阿里开源的一个SOA服务治理框架,从目前来看把它称作是一个RPC远程调用框架更为贴切. ...
- 关于OFFICE 文件在线编辑dsoframer
下载dsoframer.ocx 系统为32位时:拷贝 dsoframer.ocx 到c:\windows\system32\dsoframer.ocx打开cmd命令行注册 regsvr32.exe ...
- PMP--2.1 商业论证(经济可行性研究报告)
####################################################### PS:半个月没有更新文档,因为是有点单线程,在整理启动过程组和规划过程组的内容,在规划规 ...
- 如何用apply实现一个bind?
面试题:如何用apply实现一个bind? Function.prototype._bind = function(target) { // 保留调用_bind方法的对象 let _this = th ...
- Git安装配置及第一次上传项目到GitHub
平时的学习工作少不了保存自己的Code到代码库,这里必须要使用到Git与GitHub. 1. 关于Git的安装 下载Git:下载地址:https://git-scm.com/downloads ...
- Mac-MacOS降级(Mac系统降级,系统回退)
前言 最近把macOS更新到了 macOS Catalina,使用了一段时间后,结合自己的使用环境和体验,感觉 Catalina 不太好用,就想把系统回退到 macOS Mojave,但是平时几乎不用 ...
- yum的repo的配置文件说明
[base]:容器名称,一定要放在[]中.name:容器说明,可以自己随便写.mirrorlist:镜像站点,这个可以注释掉.baseurl:我们的 yum 源服务器的地址.默认是 CentOS 官方 ...
- C#_Excel数据读取与写入_自定义解析封装类_支持设置标题行位置&使用excel表达式收集数据&单元格映射&标题映射&模板文件的参数数据替换
本篇博客园是被任务所逼,而已有的使用nopi技术的文档技术经验又不支持我需要的应对各种复杂需求的苛刻要求,只能自己造轮子封装了,由于需要应对很多总类型的数据采集需求,因此有了本篇博客的代码封装,下面一 ...