码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2019-06-03 00:11:15      阅读:165      评论:0      收藏:0      [点我收藏+]

标签:result   说明   syn   res   唤醒   message   tac   code   pre   

用一个例子来说明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

 

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

标签:result   说明   syn   res   唤醒   message   tac   code   pre   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!