Java之Object对象中的wait()和notifyAll()用法

用一个例子来说明Object对象中的wait方法和notifyAll方法的使用。

首先定义一个消息类,用于封装数据,以供读写线程进行操作:

 1 /**
 2  * 消息
 3  *
 4  * @author syj
 5  */
 6 public class Message {
 7
 8     private String msg;
 9
10     public String getMsg() {
11         return msg;
12     }
13
14     public void setMsg(String msg) {
15         this.msg = msg;
16     }
17 }

读线程,从Message对象中读取数据,如果没有数据,就一直阻塞等待:

 1 /**
 2  * 读线程
 3  *
 4  * @author syj
 5  */
 6 public class Reader implements Runnable {
 7
 8     private Message message;
 9
10     public Reader(Message message) {
11         this.message = message;
12     }
13
14     @Override
15     public void run() {
16         synchronized (message) {
17             try {
18                 // 务必加上该判断,否则可能会因某个读线程在写线程的 notifyAll() 之后执行,
19                 // 这将导致该读线程永远无法被唤醒,程序会一直被阻塞
20                 if (message.getMsg() == null) {
21                     message.wait();// 等待被 message.notify() 或 message.notifyAll() 唤醒
22                 }
23             } catch (InterruptedException e) {
24                 e.printStackTrace();
25             }
26             // 读取 message 对象中的数据
27             System.out.println(Thread.currentThread().getName() + " - " + message.getMsg());
28         }
29     }
30 }

写线程,往Message对象中写数据,写入成功就调用 message.notifyAll() 方法来唤醒在 message.wait() 上阻塞的线程(上面的读线程将被唤醒,读线程解除阻塞继续执行):

 1 import java.util.UUID;
 2
 3 /**
 4  * 写线程
 5  *
 6  * @author syj
 7  */
 8 public class Writer implements Runnable {
 9
10     private Message message;
11
12     public Writer(Message message) {
13         this.message = message;
14     }
15
16     @Override
17     public void run() {
18         synchronized (message) {
19             try {
20                 Thread.sleep(1000L);// 模拟业务耗时
21             } catch (InterruptedException e) {
22                 e.printStackTrace();
23             }
24             // 向 message 对象中写数据
25             message.setMsg(Thread.currentThread().getName() + ":" + UUID.randomUUID().toString().replace("-", ""));
26             message.notifyAll();// 唤醒所有 message.wait()
27         }
28     }
29 }

测试类,启动两个读线程,从Message对象中读取数据,启动一个写线程,往Message对象中写数据:

 1 /**
 2  * 测试 Object 对象中的 wait()/notifyAll() 用法
 3  *
 4  * @author syj
 5  */
 6 public class LockApp {
 7     public static void main(String[] args) {
 8         Message message = new Message();
 9         new Thread(new Reader(message), "R1").start();// 读线程 名称 R1
10         new Thread(new Reader(message), "R2").start();// 读线程 名称 R2
11         new Thread(new Writer(message), "W").start();// 写线程 名称 W
12     }
13 }

测试结果:

R2 - W:4840dbd6b312489a9734414dd99a4bcb
R1 - W:4840dbd6b312489a9734414dd99a4bcb

这个特性有什么用?

显然,在同步等待异步处理结果的场景中,这个特性就很有用处了。比如,在RPC框架中,Netty服务器返回结果是异步的,Netty客户端如何拿到这个异步结果呢?

 1 import java.util.UUID;
 2 import java.util.concurrent.ConcurrentHashMap;
 3
 4 /**
 5  * 使用 Object对象的 wait() 和 notifyAll() 实现同步等待异步结果
 6  *
 7  * @author syj
 8  */
 9 public class App {
10
11     public static void main(String[] args) {
12         // 请求唯一标识
13         String requestId = UUID.randomUUID().toString();
14         App app = new App();
15
16         new Thread(new Runnable() {
17             @Override
18             public void run() {
19                 try {
20                     Thread.sleep(2000L);// 模拟业务耗时
21                 } catch (InterruptedException e) {
22                     e.printStackTrace();
23                 }
24                 // 写入数据
25                 app.set(requestId, UUID.randomUUID().toString().replace("-", ""));
26             }
27         }).start();
28
29         String message = app.get(requestId);
30         System.out.println(message);
31     }
32
33
34     // ------------------------ 异步结果 --------------------------
35
36     // 用于存放异步结果, key是请求ID, value是异步结果
37     private static ConcurrentHashMap<String, String> resultMap = new ConcurrentHashMap<>();
38     private Object lock = new Object();
39
40     /**
41      * 写数据到 resultMap,写入成功唤醒所有在 lock 对象上等待的线程
42      *
43      * @param requestId
44      * @param message
45      */
46     public void set(String requestId, String message) {
47         resultMap.put(requestId, message);
48         synchronized (lock) {
49             lock.notifyAll();
50         }
51     }
52
53     /**
54      * 从 resultMap 中读数据,如果没有数据则等待
55      *
56      * @param requestId
57      * @return
58      */
59     public String get(String requestId) {
60         synchronized (lock) {
61             try {
62                 if (resultMap.get(requestId) == null) {
63                     lock.wait();
64                 }
65             } catch (InterruptedException e) {
66                 e.printStackTrace();
67             }
68         }
69         return resultMap.get(requestId);
70     }
71 }

参考文章:https://cloud.tencent.com/developer/article/1155102

原文地址:https://www.cnblogs.com/jun1019/p/10965133.html

时间: 2024-11-07 23:11:55

Java之Object对象中的wait()和notifyAll()用法的相关文章

Java Object对象中的wait,notify,notifyAll的理解

wait,notify,notifyAll 是定义在Object类的实例方法,用于控制线程状态,在线程协作时,大家都会用到notify()或者notifyAll()方法,其中wait与notify是java同步机制中重要的组成部分,需要结合与synchronized关键字才能使用,在调用一个Object的wait与notify/notifyAll的时候,必须保证调用代码对该Object是同步的,也就是说必须在作用等同于synchronized(object){......}的内部才能够去调用ob

java的Object类中hashCode()和equals()方法-----转载

JAVA代码:    public static void main(String[] args)    {        Object obj1 = new Object();        Object obj2= new Object();        Object obj3 = obj2;        System.out.println("obj1==obj2 ?"+obj1.equals(obj2));        System.out.println("o

Java的Object对象

Object对象是除了基础对象之外,所有的对象都需要继承的父对象,包括数组也继承了Object Object里面的关键函数罗列如下: clone();调用该函数需要实现 Cloneable,否则会抛出  CloneNotSupportedException的异常. equals();用来判断两个对象是否相等的函数,默认的是两个对象的地址比较,在使用Compare计算的时候,往往需要重写这个函数. finalize();这个函数在对象被消解的时候,例如垃圾回收的时候等,会被调用,如果对象使用了不可

java.long.object类中的重要方法

一:概念 java.long.object Object类是所有Java类的祖先.每个类都使用 Object 作为超类. 二:方法概览 clone() 创建并返回此对象的一个副本. equals(Object obj) 指示某个其他对象是否与此对象“相等”. finalize() 当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法.(JVM中自带的垃圾回收机制只能回收new出的对象) getClass() 返回一个对象的运行时类. hashCode() 返回该对象的哈希码值

java 数组的 toString 方法和 equals 方法以及 java.lang.Object 对象的 toString 方法和 equals 方法

1 public class Test { 2 public static void main(String[] args) { 3 int[] a = {1, 2, 4, 6}; 4 int[] b = a; 5 int[] c = {1, 2, 4, 6}; 6 7 //下面这个方法打印的是a数组的引用地址 8 System.out.println(a.toString()); 9 //下面这个方法比较的是两个数组的引用是否相等 10 System.out.println("a.equals

Java Object 对象上的wait(),notify(),notifyAll()方法理解

第一阶段理解(2017-7-27): Java 将wait(),notify(),notifyAll()方法放在Object对象上,也就是说任何一个对象都可以调用这个方法,这与”任何一个对象都有一个内置锁,可以用于线程同步“是照应的.因此,当某个线程要释放cpu争夺权,让自己进入等待状态时,调用 某个锁(对象)上的wait()方法,也就是让当前线程等待其它线程调用该锁上的notify()或notify()方法.线程间通过同步锁来实现等待与唤醒协作.简单例子: 1 package com.lyyc

Java关于Object类中equal方法的理解

话不多说,先上例题 1 package Ch_11; 2 3 public class Test { 4 public static void main(String[] args) { 5 Object circle1 = new Circle(); 6 Object circle2 = new Circle(); 7 System.out.println(circle1.equals(circle2)); 8 } 9 } 10 11 class Circle { 12 double radi

如何向java后台的对象中传数组

1.后台对象的参数需要是是list对象 1 /* 2 * copyright : GLOBALROAM Ptd Ltd 3 * VmCreateInfo.java 4 * Author: 5 * zhangpengyangming 6 * Date: 7 * 2015/11/12 0012 8 * Version: 9 * 1.0 10 * Revisions: 11 * This class is used for load information to create VM 12 */ 13

Java多线程 同步 对象锁

多线程.同步: https://www.cnblogs.com/GarfieldEr007/p/5746362.html Java对象锁和类锁全面解析(多线程synchronized关键字): http://blog.csdn.net/u013142781/article/details/51697672 Java Object对象中的wait,notify,notifyAll通俗理解 http://blog.csdn.net/vk5176891/article/details/53945677