简单了解wait
方法和 notify
方法
wait()
使得线程进入阻塞状态,它有两种形式,一种允许 指定以毫秒为单位的一段时间作为参数,另一种没有参数,前者当对应的 notify() 被调用或者超出指定时间时线程重新进入可执行状态,后者则必须对应的 notify() 被调用。
他们是Object
类的方法,也就是说每个对象都有这一对方法,可能初看不太好理解,但是,因为每个对象都有锁,调用任意对象的 wait()
方法导致线程阻塞,并且该对象上的锁被释放。而调用任意对象的notify()
方法则导致因调用该对象的 wait()
方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后才真正可执行)。
notify()
的作用是唤醒随机一个因为这个锁wait()
进入阻塞状态的线程(冷知识:实际上在hotspot
虚拟机中是以先进先出的形式唤醒的),而notifyAll()
顾名思义,就是唤醒所有被这个锁阻塞的线程.
总结一下是这样:
lock
对象维护了一个等待队列list
;
线程A
中执行lock
的wait
方法,把线程A
保存到list中;
线程B
中执行lock
的notify
方法,从等待队列中取出线程A
继续执行
特点:
①必须在同步代码块中调用(即synchronized
修饰的)。
②而且会释放占用的锁。
注意:notify()
或者notifyAll()
调用时并不会真正释放对象锁, 必须等到synchronized
方法或者语法块执行完才真正释放锁。而wait
是直接释放锁。
几个问题
问题一: 为何wait
,notify
必须要加synchronized锁?
wait方法的源码的注释中,有这么一段:
This method should only be called by a thread that is the owner of this object's monitor. See the notify method for a description of the ways in which a thread can become the owner of a monitor
表示线程执行lock.wait()
方法时,必须持有该lock
对象的monitor
.
问题二: notify
执行之后立刻唤醒线程吗?
在hotspot
的实现是 退出代码块的时候才会真正的唤醒线程。
问题三:wait
的线程是否会影响性能?
当线程进入到wait
状态的时候其实是会放弃cpu的,也就是说这类线程是不会占用cpu资源。
下面来看一个小例子
package com.yswdqs.list;
class NumberPrint implements Runnable{
private int number;
public Object res;
public static int count = 5;
public NumberPrint(int number,Object a){
this.number = number;
res = a;
}
@Override
public void run(){
synchronized (res){
while(count-- > 0){
try {
res.notify();//唤醒等待res资源的线程,把锁交给线程(该同步锁执行完毕自动释放锁)
System.out.println(" "+number);
res.wait();//释放CPU控制权,释放res的锁,本线程阻塞,等待被唤醒。
System.out.println("------线程"+Thread.currentThread().getName()+"获得锁,wait()后的代码继续运行:"+number);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class test {
public static void main(String args[]){
Object a = new Object();//以该对象为共享资源
new Thread(new NumberPrint((1),a),"1").start();
new Thread(new NumberPrint((2),a),"2").start();
}
}
输出:
1
2
------线程1获得锁,wait()后的代码继续运行:1
1
------线程2获得锁,wait()后的代码继续运行:2
2
------线程1获得锁,wait()后的代码继续运行:1
1
------线程2获得锁,wait()后的代码继续运行:2
复制代码
首先某个线程执行到wait
方法,进入阻塞状态。直到另一个线程执行notify
方法执行后,他才能运行wait
后的代码。
顺序就是:线程1获得了synchronized
的锁,线程2因此阻塞,然后线程1都到达了wait
处。执行wait
方法等待。执行wait
方法会释放锁,这时线程2进入synchronized
区,线程2执行notify
解除线程1的阻塞。然后线程2进入wait
状态,释放锁.......循环下去。
思考题:sleep
和wait
的区别在哪里?**
答案:
①sleep()
方法是Thread
的静态方法,而wait
是Object
实例方法
②wait()
方法必须要在同步方法或者同步块中调用,也就是必须已经获得对象锁。而sleep()
方法没有这个限制可以在任何地方使用。另外,wait()
方法会释放占有的对象锁,使得该线程进入等待池中,等待下一次获取资源。而sleep()
方法只是会让出CPU并不会释放掉对象锁;
③sleep()
方法在休眠时间达到后如果再次获得CPU时间片就会继续执行,而wait()
方法必须等待Object.notify
/Object.notifyAll
通知后,才会离开等待池,并且再次获得CPU时间片才会继续执行。
作者:yswdqz
链接:https://juejin.cn/post/7006665359067447309
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。