[TOC]
## 简介
Java Object对象中的wait,notify,notifyAll是定义在Object类的实例方法,用于**控制线程状态**。
**三个方法都必须在synchronized 同步关键字所限定的作用域中调用**,否则会报错java.lang.IllegalMonitorStateException ,意思是因为没有同步,所以线程对对象锁的状态是不确定的,不能调用这些方法。
**wait**
表示持有对象锁的线程A准备释放对象锁权限,释放cpu资源并进入等待。
**notify**
表示持有对象锁的线程A准备释放对象锁权限,通知jvm唤醒某个随机竞争该对象锁的线程X。
线程A synchronized 代码作用域结束后,线程X直接获得对象锁权限,其他竞争线程继续等待(即使线程X同步完毕,释放对象锁,其他竞争线程仍然等待,直至有新的notify ,notifyAll被调用)。
**notifyAll**
表示持有对象锁的线程A准备释放对象锁权限,通知jvm唤醒所有竞争该对象锁的线程
线程A synchronized 代码作用域结束后,jvm通过算法将对象锁权限指派给某个线程X,所有被唤醒的线程不再等待。线程X synchronized 代码作用域结束后,之前所有被唤醒的线程都有可能获得该对象锁权限,这个由JVM算法决定
## Demo
~~~
ublic class WaitNotifyCase {
public static void main(String[] args) {
final Object lock = new Object();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("thread A is waiting to get lock");
synchronized (lock) {
try {
System.out.println("thread A get lock");
TimeUnit.SECONDS.sleep(1);
System.out.println("thread A do wait method");
lock.wait();
System.out.println("wait end");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("thread B is waiting to get lock");
synchronized (lock) {
System.out.println("thread B get lock");
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.notify();
System.out.println("thread B do notify method");
}
}
}).start();
}
}
~~~
## 进入wait/notify方法之前,为什么要获取synchronized锁
我们知道wait/notify是为了线程间协作而设计的,当我们执行wait的时候让线程挂起,当执行notify的时候唤醒其中一个挂起的线程,**那需要有个地方来保存对象和线程之间的映射关系**(可以想象一个map,key是对象,value是一个线程列表)
当调用这个对象的wait方法时,将当前线程放到这个线程列表里,当调用这个对象的notify方法时从这个线程列表里取出一个来让其继续执行
这样看来是可行的,也比较简单,那现在的问题这种映射关系放到哪里?
lock.wait()方法通过调用native方法wait(0)实现,其中接口注释中有这么一句:
```
The current thread must own this object’s monitor.
```
表示线程执行lock.wait()方法时,必须持有该lock对象的ObjectMonitor(前文已经提及,每个锁对象(这里指已经升级为重量级锁的对象)都有一个ObjectMonitor(对象监视器)。也就是说每个线程获取锁对象都会通过ObjectMonitor)
如果wait方法在synchronized代码中执行,该线程很显然已经持有了monitor。
从而包含了“ 进入wait/notify方法之前,为什么要获取synchronized锁”,synchronized代码块通过javap生成的字节码中包含 *monitorenter 和 monitorexit指令。其中执行monitorenter指令可以获取对象的monitor
## 参考资料
[Java并发编程:Object.wait/notify](https://blog.csdn.net/fei20121106/article/details/83268434)
- Java
- Object
- 内部类
- 异常
- 注解
- 反射
- 静态代理与动态代理
- 泛型
- 继承
- JVM
- ClassLoader
- String
- 数据结构
- Java集合类
- ArrayList
- LinkedList
- HashSet
- TreeSet
- HashMap
- TreeMap
- HashTable
- 并发集合类
- Collections
- CopyOnWriteArrayList
- ConcurrentHashMap
- Android集合类
- SparseArray
- ArrayMap
- 算法
- 排序
- 常用算法
- LeetCode
- 二叉树遍历
- 剑指
- 数据结构、算法和数据操作
- 高质量的代码
- 解决问题的思路
- 优化时间和空间效率
- 面试中的各项能力
- 算法心得
- 并发
- Thread
- 锁
- java内存模型
- CAS
- 原子类Atomic
- volatile
- synchronized
- Object.wait-notify
- Lock
- Lock之AQS
- Lock子类
- 锁小结
- 堵塞队列
- 生产者消费者模型
- 线程池