线程间的等待与唤醒机制,wait和notify是Object的方法,用于线程的等待与唤醒,必须搭配着synchronized来使用,脱离 synchronized 使用 wait 会直接抛出异常
等待方法
wait
等待方法做的事
1.调用wait方法的前提是获得这个对象的锁(synchronized对象锁,如果有多个线程取竞争这个锁,只有一个线程获得锁,其他线程会处于等待队列)
2.使当前执行代码的线程进行等待 . ( 把线程放到等待队列中 )
3.调用wait方法会释放锁
4.满足一定条件会重新尝试获得这个锁,被唤醒的之后不是立即恢复执行,而是进入阻塞队列,竞争锁
结束等待的三个方式
1.其他线程调用该对象的 notify 方法.
2.wait 等待时间超时 (wait 方法提供一个带有 timeout 参数的版本, 来指定等待时间).
3.其他线程调用该等待线程的 interrupted 方法, 导致 wait 抛出 InterruptedException 异常
唤醒方法
notify
notify()随机唤醒一个处在等待状态的线程
notifyAll()唤醒所有处在等待状态的线程
方法notify()也要在同步方法或同步块中调用,该方法是用来通知那些可能等待该对象的对象锁的 其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。
如果有多个线程等待,则有线程调度器随机挑选出一个呈 wait 状态的线程。(并没有 "先来后到") 在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁。
生产者和消费者案例
public class Baozi {
String name;//包子名称
boolean flag;//包子的状态(TRUE表示存在 false表示不存在)
}
public class Chihuo extends Thread{
Baozi baozi;
public Chihuo(String name,Baozi bz){
super();
this.baozi=bz;
}
public void run(){
String threadName=Thread.currentThread().getName();
int count=0;
while(true){
synchronized (baozi){
count++;
if(count>10){
break;
}
if(baozi.flag){
System.out.println(threadName+"开始吃"+baozi.name);
baozi.flag=false;
baozi.notify();
}else{
try{
baozi.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
public class Zaocandian extends Thread{
Baozi baozi;
public Zaocandian(String name,Baozi bz){
super();
this.baozi=bz;
}
@Override
public void run() {
String threadName=Thread.currentThread().getName();
int count=0;
while(true){
synchronized (baozi){
count++;
if(count>10){
break;
}
if(baozi.flag){
try {
baozi.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
System.out.println(threadName+"开始制作"+baozi.name);
baozi.flag=true;
baozi.notify();
}
}
}
}
}
public class ThreadTest {
public static void main(String[] args) {
Baozi baozi=new Baozi();
baozi.name="韭菜鸡蛋包子";
baozi.flag=true;
Chihuo ch=new Chihuo("猪八戒",baozi);
Zaocandian zcd=new Zaocandian("逍遥镇",baozi);
zcd.start();
ch.start();
}
}