1、定义
等待/通知机制,是指一个线程A调用了对象object的wait()方法进入等待状态,而另一个线程B调用了对象object的notify或者notifyAll()方法,线程A收到通知后从对象O的wait()方法返回,进而还行后续操作。
使用wait和notify方法实现线程之间的通信,这两个方法是Object类的方法。
注意细节:
1.1 调用wait()方法,会释放锁,线程状态由RUNNING->WAITNG,当前线程进入对象等待;
1.2 调用notify()/notifyAll()方法不会立马释放锁,notify()方法是将等待队列中的线程移到同步队列中,而notifyAll()则是全部移到同步队列中,
被移出的线程状态WAITING-->BLOCKED;
重点注意,等待队列和同步队列的转换;wait()后进入等待队列;notify()/notifyAll(),线程进入同步队列;
1.3 当前调用notify()/notifyAll()的线程释放锁了才算释放锁,才有机会唤醒wait线程;
1.4 从wait()返回的前提是必须获得调用对象锁,也就是说notify()与notifyAll()释放锁之后,wait()进入BLOCKED状态,如果其他线程
有竞争当前锁的话,wait线程继续争取锁资格。可以理解为,从同步队列中的线程抢占锁执行;
1.5 使用wait()、notify()、notifyAll()方法时需要先调对象加锁。这就是跟synchronized关键字配置使用;
2、代码运行过程
package hake.waitnotifydemo;
import java.util.ArrayList;
import java.util.List;
/**
* @Author: Liu Yue
* @Descripition:
* @Date; Create in 2021/6/1 10:35
**/
public class Demo {
private static volatile List list=new ArrayList();
public static void main(String[] args) {
final Object lock = new Object();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock){
System.out.println("thread - 1 线程启动 ***************************");
for (int i = 0;i < 10; i++){
list.add("thread - 1 - " + i);
System.out.println("当前线程"+ Thread.currentThread().getName()+"添加了一个元素");
try{
Thread.sleep(500);
if (list.size()==5){
System.out.println("发出唤醒通知********************");
lock.notify();
}
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
},"thread - 1");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock){
System.out.println("thread - 2 启动 -------------------------------");
if(list.size() != 5){
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("当前线程:" + Thread.currentThread().getName() + "收到通知线程停止..");
throw new RuntimeException();
}
}
},"thread - 2");
thread2.start();
thread1.start();
}
}
运行代码结果
"C:\Program Files\Java\jdk1.8.0_45\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.3.2\lib\idea_rt.jar=49600:C:\Program Files\JetBrains\IntelliJ IDEA 2018.3.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_45\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_45\jre\lib\rt.jar;C:\hake\manager\comhake\target\classes;C:\program\maven-repository\org\codehaus\groovy\groovy\2.5.6\groovy-2.5.6.jar" hake.waitnotifydemo.Demo
thread - 2 启动 -------------------------------
thread - 1 线程启动 ***************************
当前线程thread - 1添加了一个元素
当前线程thread - 1添加了一个元素
当前线程thread - 1添加了一个元素
当前线程thread - 1添加了一个元素
当前线程thread - 1添加了一个元素
发出唤醒通知********************
当前线程thread - 1添加了一个元素
当前线程thread - 1添加了一个元素
当前线程thread - 1添加了一个元素
当前线程thread - 1添加了一个元素
当前线程thread - 1添加了一个元素
当前线程:thread - 2收到通知线程停止..
Exception in thread "thread - 2" java.lang.RuntimeException
at hake.waitnotifydemo.Demo$2.run(Demo.java:54)
at java.lang.Thread.run(Thread.java:745)
Process finished with exit code 0
首先启动thread2线程,使得thread2线程处于等待状态,然后当集合等于5的时候,thread1向thread2线程发出通知,但是并不会释放锁,所以当thread1执行 完毕后,thread2线程才会向下执行。
注意:wait()/nofity()/notifyAll()/ 使用前必须加锁;
相似的功能:
Condition配合Lock实现的等待/通知模式(下一步解析)
LockSupport阻塞park与唤醒unpark方式
每天进步一点点!