一个线程修改了一个对象的值,而另一个线程感知了变化,然后进行了相应的操作,整个过程开始于一个线程,结束于另一个线程。前者是生产者,后者是消费者,这种模式在功能层面上实现了解耦。
有下面一段代码,大家可以根据执行的结果和注释很清晰的明确这个wait和notify的工作机制,wait等待释放锁。代码如下,不再做具体描述:
package juc.waitsleep;
/**
* @Description 测试notify和wait机制
* @Author DJZ-WWS
* @Date 2019/5/15 11:44
*/
public class WaitNotify {
static Object lock=new Object();
static boolean flag=true;
/**
* 整个的一个执行流程wait线程先执行,执行到wait方法进行等待,进入等待队列,这时候释放锁,主线程休眠,
* notify线程还没有开始进行工作,主线程休眠以后notify开始工作,由于wait已经将锁释放,所以notify会握住锁,
* 执行了notify的业务以后将wait线程唤醒,这时候notify的业务还没有执行完,wait已经被唤醒,将进入阻塞队列,状态变为阻塞状态,
* 后面notify进入二次加锁,等到这个里面的业务执行完以后,wait线程才能继续走后面的逻辑,从而将状态从阻塞变为运行
*
*
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
Thread waitThread = new Thread(new Wait(), "waitThread");
waitThread.start();
Thread.sleep(3000);
Thread notifyThread = new Thread(new Notify(), "notifyThread");
notifyThread.start();
}
static class Wait implements Runnable{
@Override
public void run() {
//当条件不满足时继续wait,同时释放了lock锁
synchronized (lock){
while (flag){
try {
System.out.println(Thread.currentThread().getName()+" falg is true"+" wait 线程进入等待状态");
lock.wait();//执行以后线程变为阻塞状态
System.out.println("wait 被唤醒"+"线程的状态为"+Thread.currentThread().getState());
}catch (Exception e){
e.printStackTrace();
}
}
//条件满足时完成工作
System.out.println(Thread.currentThread().getName()+" flag is false ");
}
}
}
static class Notify implements Runnable{
@Override
public void run() {
synchronized (lock){
//获取lock的锁,然后进行通知,通知不会释放lock的锁
//直到当前线程释放了lock后,WaitThread才能从wait方法中返回
System.out.println("notify 握住了锁");
lock.notifyAll();;
flag=false;
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//再次加锁
synchronized (lock){
//这个地方测试线程不会立马从wait返回,而是需要等待notify或者notifyall的线程释放锁之后,等待线程才有机会从wait返回
System.out.println(Thread.currentThread().getName()+" 再次得到一个锁");
try {
System.out.println(Thread.currentThread().getName()+"我将要睡3秒");
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName()+"睡醒了");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
输出的内容如下:
一些细节的总结
1、wait()、notifyAll()时需要先对调用对象加锁
2、调用wait方法之后线程状态由Running变为waiting,将当前线程放置到对象的等待队列。
3 、notify或者notifyall方法调用后,等待线程不会从wait()方法返回,而是需要等到notify或者notifyall()的线程释放锁之后,等待线程才有机会从wait返回。
4、notify()方法将等待队列中的一个线程从等待队列移到同步队列,notifyall()方法将等待队列中的所有线程全部移到同步队列,被移动的线程状态由waiting变为blocking
5、从wait()返回的前提是获得了调用对象的锁。
工作原理如下图
wait线程首先获得了对象的锁,然后调用对象的wait方法,从而放弃了锁并进入了对象的等待队列WaitQueue,进入等待状态。由于wait线程释放了对象的锁,notify随后获取了对象的锁,并调用对象的notify方法,将等待线程移到SynchronizedQueue队列中,此时wait线程变为组神色状态。Notify释放了锁之后,wait线程再次获取到做并从wait()返回继续执行。