[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子類
- 鎖小結
- 堵塞隊列
- 生產者消費者模型
- 線程池