简单了解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
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
本文详细解析wait(), notify()方法在Java并发中的作用,强调了它们与synchronized的关系,包括锁的释放、唤醒机制和性能影响。通过实例演示了线程间的协作过程,以及sleep与wait的区别。
510

被折叠的 条评论
为什么被折叠?



