- 调用notify后线程还运行吗?会立即释放锁吗?wait的线程会立即并发运行吗?
- 为什么wait、notify的线程,需要持有锁?
分析
java 将wait、notify与锁机制融合,所以分析起来会比较懵逼。我们将其分解开。
Demo
仿照生产者、消费者,一个线程 吃苹果,一个 线程生产苹果。代码见最下。
问题1 为什么融合锁
假设没有锁机制:
- A线程判断是否有苹果
- 没有苹果,准备进入wait
- B线程生产苹果
- 没有苹果,生产苹果
- B线程notify,执行完毕
- A线程进入wait (已经有苹果,但是notify已经错过,无限wait)
也就是不持有lock,wait线程错过了notify就永远等待了。
问题2
B线程notify后,是否立即停止?是否立即释放了锁?A线程是否立即启动?
答案
B线程正常运行,锁仍旧持有,直至B线程 执行出 synchronized修饰的方法区。
A线程不会执行,A线程在synchronize内,所以必须等B线程释放锁。
A线程执行的条件
- 被notify,线程从wait状态进入Runnable状态
- 依赖于持有该锁的线程 notify,且系统随机选中了 A线程notify(如果有C、D、E线程都在wait下,选择哪个依系统指定)
- 持有锁
- 依赖于B线程走出synchronized,释放锁
总结
- 同步区 synchronized(synchronize)内的线程,必须获取同步区的锁 才可执行。
- 失去锁
- 走出同步区 失去锁
- wait失去锁
- notify和锁没一分钱关系,只是将 wait的线程激活
- wait线程必须满足 1.被notify激活 2.持有锁
从Demo代码可以看出,生产线程 阻塞5s,消费线程必须在 生产线程5s后走出同步区 才能执行。不会并发
Demo Code
public class WaitNotifyDemo {
int appleCount = 0;
public synchronized void eatApple() {
while (appleCount <= 0) {
try {
System.out.println("------ while wait ------");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("------ while eat apple-- ------");
appleCount--;
System.out.println("------ eat apple done ------");
}
public synchronized void productApple() {
if (appleCount <= 0) {
appleCount++;
System.out.println("+++++ while notify app count++ +++++");
notify();
}
try {
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("------ produce apple done ------");
}
public static void main(String[] args) {
WaitNotifyDemo demo = new WaitNotifyDemo();
new Thread() {
@Override
public void run() {
demo.eatApple();
}
}.start();
new Thread() {
@Override
public void run() {
demo.productApple();
}
}.start();
}
}