翻译:https://www.journaldev.com/1037/java-thread-wait-notify-and-notifyall-example

简述

java中Objct对象包含三个方法用于线程之间对于资源锁状态进行通讯,这三个方法分别是wait()、notify()、notifyAll(),今天我们就来学习一下这三个方法的应用。

任何对象上调用这些方法的当前线程都应该具有对象监视器,否则它将抛出java.lang.IllegalMonitorStateException

方法介绍

wait

wait()方法会让当前线程处于等待状态,同时也会释放当前线程所持有的锁,直到其它线程调用了该对象的notify()或notifyAll()方法,该对象才会被唤醒进入就绪状态,wati有三个重载方法,分别是:

#一直等待,直到被唤醒
public final void wait() throws InterruptedException
#一直等待,直到被唤醒或超超时(毫秒)
public final native void wait(long timeout) throws InterruptedException;
#一直等待,直到被唤醒或超超时(纳秒)
public final void wait(long timeout, int nanos) throws InterruptedException

notify

唤醒等待当前对象的线程,如果有多个对象等待,将唤醒其中的一个

notifyAll

唤醒等待当前对象的所有线程

代码实例

这些方法可用于实现生产者-消费者问题,其中消费者线程正在等待队列中的对象,生产者线程将对象放入队列,并通知等待的线程

让我们来看一个例子,其中多个线程在同一个对象上工作,我们使用wait、notify和notifyAll方法

消息对象:

package com.lkf.mulithread;

public class Message {
private String msg; public Message(String str){
this.msg=str;
} public String getMsg() {
return msg;
} public void setMsg(String str) {
this.msg=str;
}
}

消费者线程

package com.lkf.mulithread;

public class Waiter implements Runnable {
private Message msg; public Waiter(Message m){
this.msg=m;
} @Override
public void run() {
String name = Thread.currentThread().getName();
synchronized (msg) {
try{
System.out.println(name+" 正在等待唤醒:"+System.currentTimeMillis());
msg.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(name+" 已被唤醒:"+System.currentTimeMillis());
//process the message now
System.out.println(name+" 消息处理完成: "+msg.getMsg());
}
} }

生产者线程

package com.lkf.mulithread;

public class Notifier implements Runnable {

    private Message msg;

    public Notifier(Message msg) {
this.msg = msg;
} @Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name+" 已经启动");
try {
Thread.sleep(1000);
synchronized (msg) {
msg.setMsg(name+" 我是一条消息");
msg.notify();
// msg.notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
} } }
package com.lkf.mulithread;

public class WaitNotifyTest {
public static void main(String[] args) {
Message msg = new Message("process it");
Waiter waiter1 = new Waiter(msg);
new Thread(waiter1, "1号线程").start(); Waiter waiter2 = new Waiter(msg);
new Thread(waiter2, "2号线程").start(); Notifier notifier = new Notifier(msg);
new Thread(notifier, "唤醒线程").start();
System.out.println("所有线程启动完毕");
}
}

当我们执行测试程序,会输出以下结果,但是程序执行并没有完成,因为我们调用了notify()方法,只是唤醒了其中的一个线程,另外一个线程在一直等待

1号线程 正在等待唤醒:1521883402227
2号线程 正在等待唤醒:1521883402228
所有线程启动完毕
唤醒线程 已经启动
1号线程 已被唤醒:1521883403230
1号线程 消息处理完成: 唤醒线程 我是一条消息

当我们调用notifyAll()方法时,会唤醒所有等待该对象的线程,会输出以下结果:

1号线程 正在等待唤醒:1521883786348
2号线程 正在等待唤醒:1521883786348
所有线程启动完毕
唤醒线程 已经启动
2号线程 已被唤醒:1521883787353
2号线程 消息处理完成: 唤醒线程 我是一条消息
1号线程 已被唤醒:1521883787353
1号线程 消息处理完成: 唤醒线程 我是一条消息

总结一下:

1.一定要在synchronized中使用wait()/notify()/notifyAll(),先获取对象锁,否则jvm会抛出IllegalMonitorStateException异常。

2.使用wait()时,判断线程是否进入wait状态的条件一定要使用while而不要使用if,因为等待线程可能会被错误地唤醒,所以应该使用while循环在等待前等待后都检查唤醒条件是否被满足,保证安全性。

3.notify()或notifyAll()方法调用后,线程不会立即释放锁,只会将wait中的线程从等待队列移到同步队列,也就是线程状态从waitting变为blocked;

4.wait()方法返回的前提是线程重新获得了对象的锁

Java线程之wait()、notify()、notifyAll()的更多相关文章

  1. java 多线程之wait(),notify,notifyAll(),yield()

    wait(),notify(),notifyAll()不属于Thread类,而是属于Object基础类,也就是说每个对像都有wait(),notify(),notifyAll()的功能.因为都个对像都 ...

  2. Java多线程之wait(),notify(),notifyAll()

    在多线程的情况下,因为同一进程的多个线程共享同一片存储空间,在带来方便的同一时候,也带来了訪问冲突这个严重的问题.Java语言提供了专门机制以解决这样的冲突,有效避免了同一个数据对象被多个线程同一时候 ...

  3. Java线程之 InterruptedException 异常

    Java线程之 InterruptedException 异常   当一个方法后面声明可能会抛出InterruptedException 异常时,说明该方法是可能会花一点时间,但是可以取消的方法. 抛 ...

  4. JAVA多线程之wait/notify

    本文主要学习JAVA多线程中的 wait()方法 与 notify()/notifyAll()方法的用法. ①wait() 与 notify/notifyAll 方法必须在同步代码块中使用 ②wait ...

  5. java中的wait(),notify(),notifyAll(),synchronized方法

    wait(),notify(),notifyAll()三个方法不是Thread的方法,而是Object的方法.意味着所有对象都有这三个方法,因为每个对象都有锁,所以自然也都有操作锁的方法了.这三个方法 ...

  6. Java多线程的wait(),notify(),notifyAll()

    在多线程的情况下.因为多个线程与存储空间共享相同的过程,同时带来的便利.它也带来了访问冲突这个严重的问题. Java语言提供了一种特殊的机制来解决这类冲突,避免同一数据对象由多个线程在同一时间访问. ...

  7. Java多线程:wait(),notify(),notifyAll()

    1. wait(),notify(),notifyAll() 2. wait() 2.1. wait() 2.2. wait(long timeout) 2.3. wait(long timeout, ...

  8. java 并发——理解 wait / notify / notifyAll

    一.前言 前情简介: java 并发--内置锁 java 并发--线程 java 面试是否有被问到过,sleep 和 wait 方法的区别,关于这个问题其实不用多说,大多数人都能回答出最主要的两点区别 ...

  9. java 多线程(wait/notify/notifyall)

    package com.example; public class App { /* wait\notify\notifyAll 都属于object的内置方法 * wait: 持有该对象的线程把该对象 ...

随机推荐

  1. Spring 容器中 Bean 的生命周期

    Spring 容器中 Bean 的生命周期 1. init-method 和 destory-method 方法 Spring 初始化 bean 或销毁 bean 时,有时需要作一些处理工作,因此 s ...

  2. C# HttpWebRequest请求远程地址获取返回消息

    HttpWebRequest请求远程地址获取返回消息 /// <summary> /// 请求远程Api获取响应返回字符串 /// </summary> /// <par ...

  3. 关于HA(2.102 -2.103 服务器排障)

    关于处理RHCA故障的报告: ,2.102 和 2.103 两台机器在重启之后拉不起来 原因是这两台服务比较怪 先要启动service rpcbind restart 然后再要起service nfs ...

  4. java lesson20homework

    package com.xt.lesson20; /** * 简易自动提款机 1. 创建用户类User(包含卡号.姓名.密码.余额等属性),用户开卡时录入的姓名和密码(自动分配一个卡号.初始金额设置为 ...

  5. C# 使用Emit实现动态AOP框架 进阶篇之优化

    目  录 C# 使用Emit实现动态AOP框架 (一) C# 使用Emit实现动态AOP框架 (二) C# 使用Emit实现动态AOP框架 (三) C# 使用Emit实现动态AOP框架 进阶篇之异常处 ...

  6. dev GridView 的组计和分组计

    /// <summary> /// //添加组计 /// </summary> private void SetGroupSummary(GridView gv, string ...

  7. Struts的相关基础

    为什么要用struts? 1.该框架基予mvc的开发设计模式上的,所以拥有mvc的全部优点,他在M.V.C上都有涉及,但它主要是提供一个好的控制器和一套定制的标签库上,有mvc的一系列优点:层次分明, ...

  8. css中animation和@keyframes 动画

    Animation 使用简写属性,将动画与 div 元素绑定: div { animation:mymove 5s infinite; -webkit-animation:mymove 5s infi ...

  9. linux--mysql 8.0.16--裸机安装

    参考: https://www.cnblogs.com/warmsmile/p/10210739.html https://www.cnblogs.com/yg_zhang/p/10424926.ht ...

  10. 目标检测之车辆行人(tensorflow版yolov3)

    背景: 在自动驾驶中,基于摄像头的视觉感知,如同人的眼睛一样重要.而目前主流方案基本都采用深度学习方案(tensorflow等),而非传统图像处理(opencv等). 接下来我们就以YOLOV3为基本 ...