忙等待没有对运行等待线程的 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()的用法的更多相关文章

  1. Java多线程_wait/notify/notifyAll方法

    关于这三个方法,我们可以查询API得到下列解释: wait():导致当前的线程等待,直到其他线程调用此对象的notify( ) 方法或 notifyAll( ) 方法或者指定的事件用完 notify( ...

  2. java 为什么wait(),notify(),notifyAll()必须在同步方法/代码块中调用?

    在Java中,所有对象都能够被作为"监视器monitor"——指一个拥有一个独占锁,一个入口队列和一个等待队列的实体entity.所有对象的非同步方法都能够在任意时刻被任意线程调用 ...

  3. 线程中wait/notify/notifyAll的用法

    前言 多线程时,最关注的就是线程同步,线程间的同步一般用锁来实现,常见的锁就是synchronized和lock.用了synchronized,就不得不提到wait/notify/notifyAll. ...

  4. 多线程-wait/notify/notifyAll

    引言 在Java中,可以通过配合调用Object对象的wait,notify和notifyAll来实现线程间的通信. 在线程中调用wait方法,将阻塞带带其他线程的通知(其他线程调用notify或no ...

  5. 玩转java多线程(wait和notifyAll的正确使用姿势)

    转载请标明博客的地址 本人博客和github账号,如果对你有帮助请在本人github项目AioSocket上点个star,激励作者对社区贡献 个人博客:https://www.cnblogs.com/ ...

  6. [转]java 为什么wait(),notify(),notifyAll()必须在同步方法/代码块中调用?

    在 Java中,所有对象都能够被作为"监视器monitor"——指一个拥有一个独占锁,一个入口队列和一个等待队列的实体entity. 所有对象的非同步 方法都能够在任意时刻被任意线 ...

  7. java多线程wait notify join

    wait notify 几个注意点: wait 与 notify/notifyAll 方法必须在同步代码块中使用,即要先对调用对象加锁. 当线程执行wait()时,会把当前的锁释放,然后让出CPU,进 ...

  8. java使用wait(),notify(),notifyAll()实现等待/通知机制

    public class WaitNotify { static boolean flag=true; static Object lock=new Object(); static class Wa ...

  9. java 为什么wait(),notify(),notifyAll()必须在同步(Synchronized)方法/代码块中调用?

    wait()作用:该方法用来将当前线程置入休眠状态,直到接到通知或被中断为止.条件:在调用wait()之前,线程必须要获得该对象的对象级别锁,即只能在同步方法或同步块中调用wait()方法.进入wai ...

随机推荐

  1. 找回Win8.1(windows server 2012 R2)的双拼

    一.微软拼音的选项,只能在metro界面修改: 鼠标移动到屏幕右下,出现metro的菜单,选"设置"然后选最下面的"更改电脑设置" 时间和设置->区域和语 ...

  2. sudo 使用不了, the permissions on the /etc/sudoers file are changed to something other than 0440

    sudo 使用不了,报错: the permissions on the /etc/sudoers file are changed to something other than 0440 how ...

  3. oracle中分组排序函数用法 - 转

    项目开发中,我们有时会碰到需要分组排序来解决问题的情况,如:1.要求取出按field1分组后,并在每组中按照field2排序:2.亦或更加要求取出1中已经分组排序好的前多少行的数据 这里通过一张表的示 ...

  4. UNIX环境高级编程笔记之高级I/O

    本章说明了很多高级I/O功能: 非阻塞I/O——发一个I/O操作,不使其阻塞,记录锁,STREAMS机制 I/O多路转接——select和poll函数 readv和writev函数,以及存储映射I/O ...

  5. FileZilla FTP Server 高级防火墙例外

    在防火墙中: 在“例外”中,添加端口21,TCP 添加端口50000,TCP (或添加一组端口,一个一个的也行,如果你在软件中选择的是50000-51000,而在这里只打开了50000的单个端口,登录 ...

  6. MFC的消息管理

    一般而言,与视图状态和用户输入有关的命令由视图类来处理,与文件操作有关的命令由文档类来处理,与窗口布局有关的命令由主框架类来处理,与程序的运行状态有关的命令由APP类来处理.

  7. Oracle 物化视图 说明

    一.    物化视图概述 Oracle的物化视图是包括一个查询结果的数据库对像,它是远程数据的的本地副本,或者用来生成基于数据表求和的汇总表.物化视图存储基于远程表的数据,也可以称为快照. 物化视图可 ...

  8. cocos2d-x开发: 整合apache http,用于自己检索多项目svn文件

    本来我的项目都是放在自己的虚拟机svn仓库中,随着仓库越来越多,有的时候需要去查看项目文件.check out到本地之后,挨个查看也是可以的,可是check out也是需要时间的,就想起了apache ...

  9. Git 文件比较

    Git 的三个作业场: 工作区(Work Tree) 项目根目录下 .git 目录以外所有区域,是编辑项目文件的地方. 缓存区(Index) 工作区文件必须先保存在缓存区,之后从缓存区保存到仓库. 仓 ...

  10. 【翻译】C# Tips & Tricks: Weak References - When and How to Use Them

    原文:C# Tips & Tricks: Weak References - When and How to Use Them Sometimes you have an object whi ...