Java多线程--wait(),notify(),notifyAll()的用法
忙等待没有对运行等待线程的 CPU 进行有效的利用(而且忙等待消耗cpu过于恐怖,请慎用),除非平均等待时间非常短。否则,让等待线程进入睡眠或者非运行状态更为明智,直到它接收到它等待的信号。
Java 有一个内建的等待机制来允许线程在等待信号的时候变为非运行状态。java.lang.Object 类定义了三个方法,wait()、notify()和 notifyAll()来实现这个等待机制。
但在使用wait()、notify()和 notifyAll()必须获取该对象的锁,否则的话会抛异常IllegalMonitorStateException!
wait():沉睡当前线程。
notify():随机唤醒一个正在等待当前对象的线程,不可以指定唤醒哪一个。
notify():唤醒所有正在等待当前对象的线程。
注意(同步块):
1.当一个线程被唤醒以后,并不会立即退出wait()方法去执行接下来的代码,直到调用notify()方法的线程退出它自己的同步块以后。
2.同样的使用notifyAll()方法以后,并不是所有的线程都会立即退出wait()方法,获得该对象锁的线程一个接一个的退出。
import org.junit.Test;
import static java.lang.Thread.sleep;
public class MyWaitNotify {
public class Monitor{
}
Monitor monitorObject = new Monitor();
boolean waitSign = false;
public void doWait(){
synchronized (monitorObject){
while (!waitSign)
{
try {
monitorObject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void doNotify(){
synchronized (monitorObject){
waitSign=true;
monitorObject.notify();
}
}
public void doNotifyAll(){
synchronized (monitorObject){
waitSign=true;
monitorObject.notifyAll();
}
}
@Test
public void testNotify(){
new Thread(){
public void run(){
try {
System.out.println("线程1:启动");
sleep(5000);
System.out.println("线程1:notify;");
doNotify();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程结束");
}
}.start();
System.out.println("主线程wait");
doWait();
System.out.println("主线程被激活");
}
@Test
public void testNotifyAll() {
new Thread(){
public void run(){
try {
System.out.println("线程1:启动");
sleep(5000);
System.out.println("线程1:notifyAll;");
doNotifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程1:结束");
}
}.start();
new Thread(){
public void run(){
System.out.println("线程2:等待");
doWait();
try {
sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程2:激活");
System.out.println("线程2:结束");
}
}.start();
System.out.println("主线程wait");
doWait();
System.out.println("主线程:激活");
try {
sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程:完成");
}
}
MyWaitNotify类中:
1.testNotify()方法中,测试了主线程wait,子线程notify。
2.testNotifyAll()方法中,测试了主线程wait,子线程2wait,子线程1notifyAll。
注意容易发生的问题:
1.notify()方法执行在wait()方法之前,那么会造成调用wait()方法的线程永远在等待,不在醒来。
解决方法:将notify()信号通过变量存储,任何一个线程需要wait()之前必须要检测该变量,保证没有notify才能wait。
2.调用wait()等待的线程可能会出现“假唤醒”的情况,也就是在没有notify()的情况下,调用wait()的线程自动醒来。
解决方法:通过while循环检测notify()信号变量,如果notify()信号变量表示没有线程执行过notify()那说明确实是“假唤醒”,则需要继续wait()。
public void doWait(){
synchronized (monitorObject){
while (!waitSign)
{
try {
monitorObject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
参考文档:http://wiki.jikexueyuan.com/project/java-concurrent/thread-communication.html
Java多线程--wait(),notify(),notifyAll()的用法的更多相关文章
- Java多线程_wait/notify/notifyAll方法
关于这三个方法,我们可以查询API得到下列解释: wait():导致当前的线程等待,直到其他线程调用此对象的notify( ) 方法或 notifyAll( ) 方法或者指定的事件用完 notify( ...
- java 为什么wait(),notify(),notifyAll()必须在同步方法/代码块中调用?
在Java中,所有对象都能够被作为"监视器monitor"——指一个拥有一个独占锁,一个入口队列和一个等待队列的实体entity.所有对象的非同步方法都能够在任意时刻被任意线程调用 ...
- 线程中wait/notify/notifyAll的用法
前言 多线程时,最关注的就是线程同步,线程间的同步一般用锁来实现,常见的锁就是synchronized和lock.用了synchronized,就不得不提到wait/notify/notifyAll. ...
- 多线程-wait/notify/notifyAll
引言 在Java中,可以通过配合调用Object对象的wait,notify和notifyAll来实现线程间的通信. 在线程中调用wait方法,将阻塞带带其他线程的通知(其他线程调用notify或no ...
- 玩转java多线程(wait和notifyAll的正确使用姿势)
转载请标明博客的地址 本人博客和github账号,如果对你有帮助请在本人github项目AioSocket上点个star,激励作者对社区贡献 个人博客:https://www.cnblogs.com/ ...
- [转]java 为什么wait(),notify(),notifyAll()必须在同步方法/代码块中调用?
在 Java中,所有对象都能够被作为"监视器monitor"——指一个拥有一个独占锁,一个入口队列和一个等待队列的实体entity. 所有对象的非同步 方法都能够在任意时刻被任意线 ...
- java多线程wait notify join
wait notify 几个注意点: wait 与 notify/notifyAll 方法必须在同步代码块中使用,即要先对调用对象加锁. 当线程执行wait()时,会把当前的锁释放,然后让出CPU,进 ...
- java使用wait(),notify(),notifyAll()实现等待/通知机制
public class WaitNotify { static boolean flag=true; static Object lock=new Object(); static class Wa ...
- java 为什么wait(),notify(),notifyAll()必须在同步(Synchronized)方法/代码块中调用?
wait()作用:该方法用来将当前线程置入休眠状态,直到接到通知或被中断为止.条件:在调用wait()之前,线程必须要获得该对象的对象级别锁,即只能在同步方法或同步块中调用wait()方法.进入wai ...
随机推荐
- 使用PopupWindow实现Menu功能
参考:http://www.cnblogs.com/sw926/p/3230659.html 注意: PopupWindow会给PopupView设置Padding,会导致ContentView的左右 ...
- IOC容器特性注入第一篇:程序集反射查找
学习kooboo的框架发现它的注入容器方法比较特别,同样是利用MVC的注入点,但它是查找网站下面bin所有的DLL利用反射查找特性找到对应的服务注入到容器. 这样的好处很简单:完全可以不用关心IOC容 ...
- 物料分类账 [COML] PART 2 - 总体流程
核心流程概要: [1]. 分类账在物料主数据的影响 首先描述下SAP中物料价格的 物料主数据相关的几个点: q价格控制(Price Control): 决定物料计价方式. S 标准价格(Standar ...
- DSP中CMD文件
DSP中CMD文件 (2012-12-26 20:54:17) 转载▼ 标签: 杂谈 分类: DSP FPGA DSP的存储器的地址范围,CMD是主要是根据那个来编的.CMD 它是用来分配rom和ra ...
- Xcode 中关于"#"的小知识
在代码中使用Autolayout时,大家都会使用NSDictionaryOfVariableBindings这个宏,这个宏可以生成一个变量名到变量值映射的Dictionary.比如NSDictiona ...
- 配置EF链接 MySql 的方法
材料: 1.MySQL for Visual Studio 1.2.4.msi 下载:http://dev.mysql.com/downloads/windows/visualstudio/ 2.my ...
- rsync安装配置及故障解决完全教程[window, 文件同步]
Rsync是的全称是: remote synchronize, 也就是远程同步数据, 它是一款不错的文件同步软件,而且是免费的, 它在镜像保存整个目录树和文件系统的同时保持原来文件的权限.时间.软硬链 ...
- Shell基础整理
Shell的作用是将用户输入的文本命令转换成内核能识别的数据指令交给内核进行执行,内核需要翻译成二进制交由CPU底层来执行 用户层->Shell->调用对应应用程序->ke ...
- C#ASP.NET 通用扩展函数之 IsWhat 简单好用
好东西都需要人去整理.分类 注意:需要引用命名空间 SyntacticSugar 用法: /***扩展函数名细***/ //[IsInRange] int num = 100; //以前写法 if ( ...
- DIV+CSS常用网页布局技巧!
以下是我整理的DIV+CSS常用网页布局技巧,仅供学习与参考! 第一种布局:左边固定宽度,右边自适应宽度 HTML Markup <div id="left">Left ...