zoukankan      html  css  js  c++  java
  • ObjectMonitor,ObjectWaiter 实现wait(),notify()

    0、java对象锁监视器

    在JVM的规范中,有这么一些话:
    “在JVM中,每个对象和类在逻辑上都是和一个监视器相关联的”
    “为了实现监视器的排他性监视能力,JVM为每一个对象和类都关联一个锁”
    锁住了一个对象,就是获得对象相关联的监视器

    监视器好比一做建筑,它有一个很特别的房间,房间里有一些数据,而且在同一时间只能被一个线程占据,

    进入这个建筑叫做"进入监视器"

    进入建筑中的那个特别的房间叫做"获得监视器"

    占据房间叫做"持有监视器"

    离开房间叫做"释放监视器"

    离开建筑叫做"退出监视器".
    而一个锁就像一种任何时候只允许一个线程拥有的特权.
    一个线程可以允许多次对同一对象上锁.对于每一个对象来说,java虚拟机维护一个计数器,记录对象被加了多少次锁,没被锁的对象的计数器是0,线程每加锁一次,计数器就加1,每释放一次,计数器就减1.当计数器跳到0的时候,锁就被完全释放了.

    java虚拟机中的一个线程在它到达监视区域开始处的时候请求一个锁.JAVA程序中每一个监视区域都和一个对象引用相关联

    监视器:monitor
    锁:lock(JVM里只有一种独占方式的lock)
    进入监视器:monitorenter
    离开/释放监视器:monitorexit
    (monitorentermonitorexit是JVM的指令)
    拥有者:owner

    在JVM里,monitor就是实现lock的方式。
    monitorenter就是获得某个对象的lock(owner是当前线程)
    monitorexit就是释放某个对象的lock


    在oracle JVM 1.6 里面实现的object的wait 和notify方法是在synchronizer.cpp里实现。 

    先介绍2个对象:

    一. ObjectMonitor  对象 主要用来监视创立的Object 

    在synchronizer.cpp 里定义了,ObjectMonitor 的对象,我们来看ObjectMonitor的对象的结构体

    ObjectMonitor::ObjectMonitor() {
      _header       = NULL;
      _count        = 0;
      _waiters      = 0,
      _recursions   = 0;
      _object       = NULL;
      _owner        = NULL;
      _WaitSet      = NULL;
      _WaitSetLock  = 0 ;
      _Responsible  = NULL ;
      _succ         = NULL ;
      _cxq          = NULL ;
      FreeNext      = NULL ;
      _EntryList    = NULL ;
      _SpinFreq     = 0 ;
      _SpinClock    = 0 ;
      OwnerIsThread = 0 ;
    }

    每个object的对象里 markOop->monitor() 里可以保存ObjectMonitor的对象。

    建立ObjectMonitor的算法:

    如果不存在,可以向Thread 的ObjectMonitor 的对象列表中Allocate free objectMonitor 对象。 

    每个线程都有ObjectMonitor 的free和used的objectMonitor对象列表,如果没有free objectMonitor对象列表,将向global 中ListLock Allocate为了提高效率。

    二.  ObjectWaiter 对象

     ObjectWaiter 对象

    class ObjectWaiter : public StackObj {
     public:
      enum TStates { TS_UNDEF, TS_READY, TS_RUN, TS_WAIT, TS_ENTER, TS_CXQ } ;
      enum Sorted  { PREPEND, APPEND, SORTED } ;
      ObjectWaiter * volatile _next;
      ObjectWaiter * volatile _prev;
      Thread*       _thread;
      ParkEvent *   _event;
      volatile int  _notified ;
      volatile TStates TState ;
      Sorted        _Sorted ;           // List placement disposition
      bool          _active ;           // Contention monitoring is enabled
     public:
      ObjectWaiter(Thread* thread) {
        _next     = NULL;
        _prev     = NULL;
        _notified = 0;
        TState    = TS_RUN ;
        _thread   = thread;
        _event    = thread->_ParkEvent ;
        _active   = false;
        assert (_event != NULL, "invariant") ;
      }
      void wait_reenter_begin(ObjectMonitor *mon) {
        JavaThread *jt = (JavaThread *)this->_thread;
        _active = JavaThreadBlockedOnMonitorEnterState::wait_reenter_begin(jt, mon);
      }
      void wait_reenter_end(ObjectMonitor *mon) {
        JavaThread *jt = (JavaThread *)this->_thread;
        JavaThreadBlockedOnMonitorEnterState::wait_reenter_end(jt, _active);
      }
    };

    ObjectWaiter 对象里存放thread(线程对象) 和 ParkEvent(线程的unpark), 每一个等待锁的线程都会有一个ObjectWaiter对象.

    而objectwaiter是个双向链表结构的对象。

    我们可以看到在ObjectMonitor对象里有2个队列成员_WaitSet 和 _EntryList 存放的就是ObjectWaiter

    _WaitSet:

    主要存放所有wait的线程的对象,也就是说如果有线程处于wait状态,将被挂入这个队列

    _EntryList:

    所有在等待获取锁的线程的对象,也就是说如果有线程处于等待获取锁的状态的时候,将被挂入这个队列。

    三、Wait 方法实现:

    ObjectSynchronizer::wait方法

    通过object的对象中找到ObjectMonitor对象

    调用方法 

    void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS)

    通过ObjectMonitor::AddWaiter调用把新建立的ObjectWaiter对象放入到 _WaitSet 的队列的末尾中

    然后在ObjectMonitor::exit释放锁,接着 thread_ParkEvent->park  也就是wait

    四、Notify方法的实现:

    ObjectSynchronizer::notify方法

    调用ObjectSynchronizer::inflate

    object的对象中找到ObjectMonitor对象 

    然后调用方法ObjectMonitor::notify

    调用ObjectMonitor::DequeueWaiter 摘除第一个ObjectWaiter对象从_WaitSet 的队列中

    并把这个ObjectWaiter对象放入_EntryList中,_EntryList 存放的是ObjectWaiter的对象列表,列表的大小就是那些所有在等待这个对象锁的线程数。

    注意这里并没有调用ObjectMonitor::exit释放锁

    NotifyALL和Notify 的区别就是

    通过遍历调用ObjectMonitor::DequeueWaiter,把所有的_WaitSet的队列中的ObjectWaiter对象放入到_EntryList中

    关于放入到_EntryList的策略大概有4中Policy,其中还涉及到一个_cxq的队列,先不具体介绍了

    notify, 和notifyAll 都没有释放对象的锁,而是在Synchronizer同步块结束的时候释放

    如何释放锁

    调用ObjectMonitor::exit

    从_EntryList里找到一个ObjectWaiter,因为ObjectWaiter里有线程的_event ParkEvent,调用unpark() 通知ObjectWaite里的线程运行(拿到锁),具体实现在ObjectMonitor::ExitEpilog方法里

     Reference

    java 中的 wait 和 notify 实现的源码分析

     http://bbs.csdn.net/topics/80052746

  • 相关阅读:
    linux 查看磁盘空间大小
    Redis内存碎片率
    redis的incr和incrby命令
    redis如何清空当前缓存和所有缓存
    ArcGIS矢量数据批量合并工具
    arcgis 获得工具有多少个
    GoogleEarth二次开发难点和技巧
    ArcGIS 智能批量赋高程工具
    arcgis python支持汉字
    ArcGIS 宗地图批量打印输出
  • 原文地址:https://www.cnblogs.com/549294286/p/3688829.html
Copyright © 2011-2022 走看看