zoukankan      html  css  js  c++  java
  • wait()、notify、notifyAll()的使用

    wait()、notify、notifyAll()的使用

    参考:https://www.jianshu.com/p/25e243850bd2?appinstall=0

    一)、java 中对象锁的模型

    JVM会为一个使用内部锁(synchronized)的对象维护两个集合,Entry Set和Wait Set,即锁池和等待池。

    二)、Entry Set:*

    如果线程A已经持有了对象锁,此时如果有其他线程也想获得该对象锁的话,它只能进入Entry Set,并且处于线程的BLOCKED状态。

    可能进入Entey Set的线程:

    1).两个抢夺cpu的线程未抢夺到的一方。
    
    2).notify()/notifyAll()唤醒却未抢夺到cpu的线程。
    

    三)、Wait Set:

    如果线程A调用了wait()方法,那么线程A会释放该对象的锁,进入到Wait Set,并且处于线程的WAITING状态。

    可能进入wait状态的线程:

    1).调用wait()方法。
    

    四)、Runnable状态的转变

    Entry Set中的线程的状态为Blocked状态:

    1).当对象锁被释放的时候,JVM会唤醒处于Entry Set中的某一个线程,这个线     程的状态就从BLOCKED转变为RUNNABLE。
    

    Wait Set中的线程状态为Waiting状态:

    1)  .当对象的notify()方法被调用时,JVM会唤醒处于Wait Set中的某一个线程,这个线程的状态就从WAITING转变为RUNNABLE。
    
    2).当notifyAll()方法被调用时,Wait Set中的全部线程会转变为RUNNABLE状态。所有Wait Set中被唤醒的线程会被转移到Entry Set中。
    

    注:只有处于Runnable状态的线程才能去竞争锁,获取资源。

    五)、notify()和notifyAll()的区别

    notify()只唤醒一个线程,notifyAll()唤醒Wati Set的所有线程。

    六)、使用notify()容易发生死锁状态

    举例:生产者和消费者线程

    消费一进行消费,判断buff为空,调用wait()进入等待状态,消费者二进行消费buff为空,调用wait(),进入等待状态,生产者一进行生产,buff满,notify()消费者一,此时生产者二在Entry Set中抢夺到资源,判断buff满,进入到wait状态,消费者一消费资源,notify(),如果唤醒了生产者,继续生产,若此时生产者一退出了生产,唤醒了消费者二,buffer为空,消费者二进入wait状态,此时,生产者二和消费者都进入等待状态,没有Runable状态的线程,生产者2和消费者2在Wait Set中互相等待,发生死锁。

    注: 具体代码参考https://www.jianshu.com/p/25e243850bd2?appinstall=0

    七)、wait()、notify、notifyAll()要配合synchonized使用

    解释一下,这里为什么配合synchonized:

    1).如果线程要调用对象的wait()方法,必须首先获得该对象的监视器锁,调用
     wait()之后当前线程又立即释放掉锁,线程随后进入WAIT_SET(等待池)中。
    
    2).如果线程要调用对象的notify()/notifyAll()方法,也必须先获得对象的    监视器锁调用方法之后,立即释放掉锁然后处于Wait_set的线程被转移到      Entry_set(等锁 池)中去竞争锁资源.。The Winner Thread,也就是    成功获得了对象的锁的线程,就是对象锁的拥有者,会进入runnable状态。
    
    3).由于需要获得锁之后才能够调用wait()/notify()方法,因此必须将它们放    到同步代码块中.
    

    八)、总结

    1).Jvm的内部锁对象(synchonized)维护两个集合Entry Set 和 Wait Set。

    2).未抢占到cpu资源或被唤醒却未抢占到cpu资源的线程会放置在Entry Set中。

    3).调用wait()方法的线程进入Wait Set。

    4).Entry Set集合的线程为Blocked状态,Wait Set集合中的线程为Waiting状态。

    5).当锁资源被释放时,Entry Set的某一个线程状态会变成Runnable状态。

    6).当调用notify()方法时,Wait Set的的某一线程被唤醒,由waiting状态转为Runable状态,调用 notifyAll()时,Wait Set的所有线程都被唤醒,线程状态由waiting转为Runable状态,并移入Entry Set中。

    金麟岂能忍一世平凡 飞上了青天 天下还依然
  • 相关阅读:
    .net core使用EasyNetQ做EventBus
    .NET Core DI 手动获取注入对象
    设置Jexus开机启动
    centos7开放关闭防火墙端口
    linux防火墙开放端口
    转 Jexus-5.6.3使用详解
    Mysql存储过程
    Reids笔记
    Lucene笔记
    Spring Junit 测试用例
  • 原文地址:https://www.cnblogs.com/Auge/p/11712564.html
Copyright © 2011-2022 走看看