轻松理解Java并发wait() 方法,notify() 方法和notifyAll()方法

简单了解wait 方法和 notify方法

wait() 使得线程进入阻塞状态,它有两种形式,一种允许 指定以毫秒为单位的一段时间作为参数,另一种没有参数,前者当对应的 notify() 被调用或者超出指定时间时线程重新进入可执行状态,后者则必须对应的 notify() 被调用。

他们是Object类的方法,也就是说每个对象都有这一对方法,可能初看不太好理解,但是,因为每个对象都有锁,调用任意对象的 wait() 方法导致线程阻塞,并且该对象上的锁被释放。而调用任意对象的notify()方法则导致因调用该对象的 wait() 方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后才真正可执行)。

notify()的作用是唤醒随机一个因为这个锁wait()进入阻塞状态的线程(冷知识:实际上在hotspot虚拟机中是以先进先出的形式唤醒的),而notifyAll()顾名思义,就是唤醒所有被这个锁阻塞的线程.

总结一下是这样:

lock对象维护了一个等待队列list

线程A中执行lockwait方法,把线程A保存到list中;

线程B中执行locknotify方法,从等待队列中取出线程A继续执行

特点:

①必须在同步代码块中调用(即synchronized修饰的)。

②而且会释放占用的锁

注意:notify()或者notifyAll()调用时并不会真正释放对象锁, 必须等到synchronized方法或者语法块执行完才真正释放锁。而wait是直接释放锁。

几个问题

问题一: 为何waitnotify必须要加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状态,释放锁.......循环下去。

思考题:sleepwait的区别在哪里?**

答案:

sleep()方法是Thread的静态方法,而waitObject实例方法

②wait()方法必须要在同步方法或者同步块中调用,也就是必须已经获得对象锁。而sleep()方法没有这个限制可以在任何地方使用。另外,wait()方法会释放占有的对象锁,使得该线程进入等待池中,等待下一次获取资源。而sleep()方法只是会让出CPU并不会释放掉对象锁;

sleep()方法在休眠时间达到后如果再次获得CPU时间片就会继续执行,而wait()方法必须等待Object.notify/Object.notifyAll通知后,才会离开等待池,并且再次获得CPU时间片才会继续执行。


作者:yswdqz
链接:https://juejin.cn/post/7006665359067447309
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值