忙等待没有对运行等待线程的 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. 尝试在tensorflow上运行facenet

    上一篇装好了tensorflow的运行环境,开始尝试运行一些实例代码,在github上找到了一个tensorflow实现的facenet的代码,还是遇到了很多坑! 坚持看完,有重要总结! 代码:htt ...

  2. 物料分类账 [COML] PART 1 - 概览

    物料分类账 [COML] PART 1 - 概览 一).原理 1). •实际成本/物料分类帐是产品成本控制模块的一个子模块,产品成本控制包括三个子模块,产品成本计划,成本对象控制,实际成本/物料分类帐 ...

  3. Windows下移动MariaDB数据目录 (转!)

    Windows下移动MariaDB数据目录: http://www.xue163.com/news/940/9403312.html [环境]OS:Windows Server 2008 R2 x64 ...

  4. linux下 C++ 读取mat文件 MATLAB extern cyphon scipy 未完待续

    1.使用Matlab的C扩展,需要用户安装matlab. g++ -L/media/exsoftware/MATLAB/R2013b/bin/glnxa64 -Wl,-rpath,/media/exs ...

  5. SQL1159 Initialization error with DB2 .NET Data Provider, reason code 7(问题补充)

    SQL1159 Initialization error with DB2 .NET Data Provider, reason code 7 需要注册GAC,修改注册表 IBM官方方案: http: ...

  6. 全中国的省市县镇乡村数据获取以及展示java源代码

    第一步.准备工作(数据源+工具): 数据源(截止目前最全面权威的官方数据):http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2013/ 爬取数据的工具 ...

  7. 实战android菜单项之XML加载菜单与动态菜单项[转]

    原文地址:http://blog.csdn.net/kaiwii/article/details/7767225 自定义android应用程序的菜单项首先要知道切入点.经过学习,知道主要是两个Acti ...

  8. SNF开发平台WinForm之十三-单独从服务器上获取PDF文件进行显示-SNF快速开发平台3.3-Spring.Net.Framework

    1运行效果: 2开发实现: 如果需要单独显示PDF文件时用下面代码去实现,指定url地址. 地址: . 获取附件管理的实体对象: List<KeyValuePair<string, obj ...

  9. 扩展 IEnumerable<T>,让它根据另一个集合的顺序来排列

    假如我有两个集合: public class Teacher { public int Id { get; set; } public string Name { get; set; } } publ ...

  10. SplayTree伸展树的非递归实现(自底向上)

    Splay Tree 是二叉查找树的一种,它与平衡二叉树.红黑树不同的是,Splay Tree从不强制地保持自身的平衡,每当查找到某个节点n的时候,在返回节点n的同时,Splay Tree会将节点n旋 ...