Java 多线程编程之:notify 和 wait 用法
wait 和 notify 简介
wait 和 notify 均为 Object 的方法:
- Object.wait() —— 暂停一个线程
- Object.notify() —— 唤醒一个线程
从以上的定义中,我们可以了解到以下事实:
- 想要使用这两个方法,我们需要先有一个对象 Object。
- 在多个线程之间,我们可以通过调用同一个对象的
wait()
和notify()
来实现不同的线程间的可见。
对象控制权(monitor)
在使用 wait 和 notify 之前,我们需要先了解对象的控制权(monitor)。在 Java 中任何一个时刻,对象的控制权只能被一个线程拥有。如何理解控制权呢?请先看下面的简单代码:
public class ThreadTest {
public static void main(String[] args) {
Object object = new Object();
new Thread(new Runnable() {
@Override
public void run() {
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
直接执行,我们将会得到以下异常:
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at com.xiangyu.demo.ThreadTest$1.run(ThreadTest.java:10)
at java.lang.Thread.run(Thread.java:748)
出错的代码在:object.wait();
。这里我们需要了解以下事实:
- 无论是执行对象的 wait、notify 还是 notifyAll 方法,必须保证当前运行的线程取得了该对象的控制权(monitor)
- 如果在没有控制权的线程里执行对象的以上三种方法,就会报 java.lang.IllegalMonitorStateException 异常。
- JVM 基于多线程,默认情况下不能保证运行时线程的时序性
在上面的示例代码中,我们 new 了一个 Thread,但是对象 object 的控制权仍在主线程里。所以会报 java.lang.IllegalMonitorStateException 。
我们可以通过同步锁来获得对象控制权,例如:synchronized 代码块。对以上的示例代码做改造:
public class ThreadTest {
public static void main(String[] args) {
Object object = new Object();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (object){ // 修改处
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
再次执行,代码不再报错。
我们可以得到以下结论:
- 调用对象的
wait()
和notify()
方法,需要先取得对象的控制权 - 可以使用
synchronized (object)
来取得对于 object 对象的控制权
解题
了解了对象控制权之后,我们就可以正常地使用 notify 和 wait 了,下面给出我的解题方法,供参考。
public class ThreadTest {
private final Object flag = new Object(); public static void main(String[] args) {
ThreadTest threadTest = new ThreadTest();
ThreadA threadA = threadTest.new ThreadA();
threadA.start();
ThreadB threadB = threadTest.new ThreadB();
threadB.start();
} class ThreadA extends Thread {
@Override
public void run() {
synchronized (flag) {
for (int i = 0; i <= 100; i += 2) {
flag.notify();
System.out.println(i);
try {
flag.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} }
} class ThreadB extends Thread {
@Override
public void run() {
synchronized (flag) {
for (int i = 1; i < 100; i += 2) {
flag.notify();
System.out.println(i);
try {
flag.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
发散:notify()
和notifyAll()
这两个方法均为 native 方法,在JDK 1.8 中的关于notify()
的JavaDoc如下:
Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of them is chosen to be awakened.
译为:
唤醒此 object 控制权下的一个处于 wait 状态的线程。若有多个线程处于此 object 控制权下的 wait 状态,只有一个会被唤醒。
也就是说,如果有多个线程在 wait 状态,我们并不知道哪个线程会被唤醒。
在JDK 1.8 中的关于notifyAll()
的JavaDoc如下:
Wakes up all threads that are waiting on this object's monitor.
译为:
唤醒所有处于此 object 控制权下的 wait 状态的线程。
所以,我们需要根据实际的业务场景来考虑如何使用。
原文链接:https://segmentfault.com/a/1190000018096174?utm_source=tag-newest
参考地址:https://mp.weixin.qq.com/s/WoQtQSDygBwC_lJyOhf1EQ
Java 多线程编程之:notify 和 wait 用法的更多相关文章
- java多线程编程之synchronized
synchronized是用来解决多线程情况下的线程安全问题的,它可以修饰方法也可以修饰语句块 , 那么什么情况下是线程安全和线程不安全呢 ? 方法内的变量是线程安全的 , 类的实例变量是非线程安全的 ...
- Java 多线程编程之九:使用 Executors 和 ThreadPoolExecutor 实现的 Java 线程池的例子
线程池用来管理工作线程的数量,它持有一个等待被执行的线程的队列. java.util.concurrent.Executors 提供了 java.util.concurrent.Exe ...
- iOS多线程编程之GCD的常见用法(转载)
一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) withObject:nil aft ...
- Java并发编程之CAS
CAS(Compare and swap)比较和替换是设计并发算法时用到的一种技术.简单来说,比较和替换是使用一个期望值和一个变量的当前值进行比较,如果当前变量的值与我们期望的值相等,就使用一个新值替 ...
- [转] iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用
介绍: Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首 ...
- [转] iOS多线程编程之NSOperation和NSOperationQueue的使用
<iOS多线程编程之NSThread的使用> 介绍三种多线程编程和NSThread的使用,这篇介绍NSOperation的使用. 使用 NSOperation的方式有两种, 一种是用定义好 ...
- 深入浅出Cocoa多线程编程之 block 与 dispatch quene
深入浅出 Cocoa 多线程编程之 block 与 dispatch quene 罗朝辉(http://www.cppblog.com/kesalin CC 许可,转载请注明出处 block 是 Ap ...
- iOS多线程编程之NSOperation和NSOperationQueue的使用
前一篇 <iOS多线程编程之NSThread的使用> 介绍三种多线程编程和NSThread的使用,这篇介绍NSOperation的使用. 使用 NSOperation的方式有两种, 一种是 ...
- [Cocoa]深入浅出Cocoa多线程编程之 block 与 dispatch quene
深入浅出 Cocoa 多线程编程之 block 与 dispatch quene 罗朝辉(http://www.cppblog.com/kesalin CC 许可,转载请注明出处 block 是 Ap ...
随机推荐
- pyqt-swf
# pyqt5界面打开flash.swf文件 from PyQt5 import QtCore, QtGui, QAxContainer, QtWidgets class Ui_Flash(QAxCo ...
- gitlab docker中postgresql远程访问配置
1.配置postgresql远程访问 配置postgresql远程访问,需要修改两个文件,在gitlab-ce的docker中位置为 /var/opt/gitlab/postgresql/data 首 ...
- 正则获取a标签和a标签中的href地址
/(<\/?a.*?>)/ a标签 /<a\b.*?</a>/ 表式以"<a "(有空格) 开始 以"</a>" ...
- LeeCode - 括号生成
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合. 例如,给出 n = 3,生成结果为: [ "((()))", "(()())& ...
- Java设计模式:23种设计模式全面解析(超级详细)
设计模式(Design Pattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路.它不是语法规定,而是一套用来提高代码可复用性.可维护性.可读性.稳健性以及安全性的解决方案. 1995 ...
- IDEA中Springboot静态文件加载(热部署)
Springboot项目静态文件加载 昨天写项目的时候碰到一个问题,就是静态文件css无法读取到项目中,我仔细思考了下,总结了下,可能有两个问题 1.页面未加载更新 这个可能性非常大,Chrome就是 ...
- Cloud Computing——Everything as a Service
service 分类 有Iaas, Paas, SaaS HDFS 总结☞: HDFS应付不了的场景 无法低时延 小文件存储存在空间利用率问题 文件不可修改 三副本有什么作用 防止单机故障,提高可用性 ...
- java中的浅拷贝和深拷贝
复制 将一个对象的引用复制给另一个对象,一共有三种方式.第一种方式是直接赋值,第二种方式是浅复制,第三种方式是深复制. 1.直接赋值 在Java中,A a1 = a2,这实际上复制的是引用,也就是说 ...
- Python黑科技 | Python中四种运行其他程序的方式
在Python中,可以方便地使用os模块来运行其他脚本或者程序,这样就可以在脚本中直接使用其他脚本或程序提供的功能,而不必再次编写实现该功能的代码.为了更好地控制运行的进程,可以使用win32proc ...
- Python 爬虫如何入门学习?
"入门"是良好的动机,但是可能作用缓慢.如果你手里或者脑子里有一个项目,那么实践起来你会被目标驱动,而不会像学习模块一样慢慢学习. 另外如果说知识体系里的每一个知识点是图里的点,依 ...