【java并发】 --wait与notify原理

重量级锁通过对象内部的监视器(monitor)实现,其中monitor的本质是依赖于底层操作系统的Mutex Lock实
现,操作系统实现线程之间的切换需要从用户态到内核态的切换,切换成本非常高。前面我们在讲Java对象头的时候,讲到了monitor这个对象,在hotspot虚拟机中,通过ObjectMonitor类来实现monitor。他的锁的获取过程的体现会简单很多.
在这里插入图片描述

wait 和notify

wait和notify是用来让线程进入等待状态以及使得线程唤醒的两个操作
wait()必须被synchronized来使用,

public class ThreadWait extends Thread{
private Object lock;
public ThreadWait(Object lock) {
   this.lock = lock;
} 

@Override
public void run() {
	
	synchronized (lock){
	System.out.println("开始执行 thread wait");
	
	try {
	lock.wait();
	   } catch (InterruptedException e) {
	e.printStackTrace();
	   } 
	   System.out.println("执行结束 thread wait");
	}
 }
}
public class ThreadNotify(Object lock) {
  this.lock = lock;
} 

@Override
public void run() {
	synchronized (lock){
		System.out.println("开始执行 thread notify");
		lock.notify();
		System.out.println("执行结束 thread notify");
	}
  }
}

wait 和notify的原理

  1. 调用wait() 首先会获取监视器锁,获得成功后,会让线程进入等待状态进入等待队列并且释放锁;
  2. 然后当其他线程调用notify或者notifyall以后,会选择从等待队列中唤醒任意一个线程
  3. 而执行完notify方法以后,并不会立马唤醒线程,原因是当前线程仍然持有这把锁,处于等待状态的线程无法获得锁。必须要等到当前的线程执行完按monitorexit指令之后,也就是被释放之后,处于等待队列的线程就可以开始竞争锁了。
    在这里插入图片描述

wait和notify为什么要放在synchronized里面

wait方法的语义有两个,

  • 释放当前的对象锁、
  • 使得当前线程进入阻塞队列,

而这些操作都和监视器是相关的,所以wait必须要获得一个监视器锁。
notify也一样,它是唤醒一个线程,所以需要知道待唤醒的线程在哪里,就必须找到这个对象获取这个对象的锁然后去到这个对象的等待队列去唤醒一个线程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章