Java之Object对象中的wait()和notifyAll()用法
Posted jun1019
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
以上是关于Java之Object对象中的wait()和notifyAll()用法的主要内容,如果未能解决你的问题,请参考以下文章