wait()、notify()、notifyAll()原理用法详解sleep()与wait()区别

wait()、notify()、notifyAll()都是Object的方法;

https://github.com/CyC2018/CS-Notes/blob/master/notes/Java%20%E5%B9%B6%E5%8F%91.md#wait-notify-notifyall

wait()

调用 wait() 使得线程等待某个条件满足,线程在等待时会被挂起,当其他线程的运行使得这个条件满足时,其它线程会调用 notify() 或者 notifyAll() 来唤醒挂起的线程。

  1. 在调用wait()之前,线程必须要获得该对象的对象级别锁,因此只能在同步方法或同步块中调用wait()方法,否则会在运行时抛出 IllegalMonitorStateException。

  2. 使用 wait()方法 挂起期间,当前线程会释放锁。
    这是因为,如果没有释放锁,那么其它线程就无法进入对象的同步方法或者同步控制块中,那么就无法执行 notify() 或者 notifyAll() 来唤醒挂起的线程,就会造成死锁

注意

  • 调用 wait()后,线程被挂起后,如果没有notify() 或者 notifyAll() 来唤醒挂起的线程,就会造成死锁
  • notify()或notifyAll()方法调用后,等待线程依旧不会从wait()返回,需要调用notify()或 notifAll()的线程释放锁之后,等待线程才有机会从wait()返回。

wait()原理

monitor

monitor在JVM中是基于C++的实现的,ObjectMonitor中有几个关键属性:

_owner:指向持有ObjectMonitor对象的线程
_WaitSet:存放处于wait状态的线程队列
_EntryList:存放处于等待锁block状态的线程队列
_recursions:锁的重入次数
_count:用来记录该线程获取锁的次数

在这里插入图片描述

    当多个线程同时访问一段同步代码时,首先会进入_EntryList队列中,当某个线程获取到对象的monitor后进入_Owner区域并把monitor中的_owner变量设置为当前线程,同时monitor中的计数器_count加1。即获得锁。
    若持有monitor的线程调用wait()方法,将释放当前持有的monitor,_owner变量恢复为null,_count自减1,同时该线程进入_WaitSet集合中等待唤醒
    若当前线程执行完毕也将释放monitor(锁)并复位变量的值,以便其他线程进入获取monitor(锁)

notify 方法: 从等待队列中唤醒任意一个线程,使该线程退出等待队列,进入可运行状态,也就是notify()方法仅通知一个线程。
notifyAll 方法: 使所有正在等待队列中线程退出等待队列,进入就绪状态。
wait 方法: 阻塞

由此可知wait()原理:

The Owner中的线程,调用wait()后进入Wait Set,调用被notify()或者notifyAll()可以唤醒Wait Set中的一个或者所有线程。

调用wait()的前提是线程获取到了锁,并处于运行态(所以wait()方法必须用在同步方法或者同步代码块中),当调用wait()后,线程由运行态转变为阻塞态,需要被notify() 或者 notifyAll()唤醒


notify()

从等待队列中唤醒任意一个线程,使该线程退出等待队列,进入可运行状态,也就是notify()方法仅通知一个线程。


notifyAll()

使所有正在等待队列中线程退出等待队列,进入就绪状态。

sleep()与wait()区别

  1. sleep()方法可以在任何地方使用;wait()方法则只能在同步方法或同步块中使用;
  2. sleep() 方法是线程类(Thread)的静态方法;wait()是Object对象的方法;
  3. sleep()会占着锁不放;wait()会释放锁;

使用案例

public class WaitNotifyExample {

    public synchronized void before() {
        System.out.println("before");
        notifyAll();
    }

    public synchronized void after() {
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("after");
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值