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 ...
随机推荐
- Swift: 深入理解Core Animation(一)
如果想在底层做一些改变,想实现一些特别的动画,这时除了学习Core Animation之外,别无选择. 最近在看<iOS Core Animation:Advanced Techniques&g ...
- JS/React 判断对象是否为空对象
JS一般判断对象是否为空,我们可以采用: if(!x)的方式直接判断,但是如果是一个空对象,比如空的JSON对象,是这样的:{},简单的判断是不成功的,因为它已经占用着内存了,如果是JQuery的话, ...
- Mac OSX Versions输入username按1下都会出现2个字符,并且不能create,解决方法
我的系统,安装的versions1.3.2,下载地址:http://www.jb51.net/softs/193467.html 安装好了以后Versions输入username按1下都会出现2个字符 ...
- Python 之 MySQL 操作库 lazy_mysql
TOC Intro Installation Tutorial API Engine Pool Column Table Intro lazy_mysql 是一个非常简单易用,用来操作 MySQL 的 ...
- C10K问题渣翻译
The C10K problem [Help save the best Linux news source on the web -- subscribe to Linux Weekly News! ...
- Entity Framework增删改之通用精简方法
用EF用了好长一段时间了,从EF4.0的版本开始接触,感觉这个ORM不能说性能是最好的,但是我个人感觉功能实现以及和mvc的结合还是一个不错的企业级网站的解决方案,在此写个简易的通用扩展方法来方便大家 ...
- Android 布局之TableLayout
Android 布局之TableLayout 1 TableLayout简介 TableLayout是表格布局.TableLayout 可设置的属性包括全局属性及单元格属性. 1.1 全局属性 有以下 ...
- WhatFontIs - 字体百科全书,没有不认识的字体
我敢肯定,我不是唯一一个曾经特别想知道图片上使用的某个字体,然后特别无奈的到字体网站大海捞针似的的找类似的字体.如今,一个强大的软件字体识别——WhatFontIs,让我们的生活更轻松. 您可能感兴趣 ...
- 分享一套精美的现代 UI PSD 工具包【免费下载】
艾库特·耶尔马兹,是土耳其伊斯坦布尔的一位高级艺术总监,他向大家分享了一套美丽的现代 UI 工具包,你可以免费下载.所以,你可以使用这个优秀的素材设计视觉互动和有吸引力的用户界面. 此 UI 套件提供 ...
- 使用即时文件初始化提高SQL Server性能
今天我想谈下SQL Server里的一个特别话题——即时文件初始化(Instant File Initialization).对于你的SQL Server实例,如果你启用了即时文件初始化,在特定情况下 ...