zoukankan      html  css  js  c++  java
  • 对象内置锁ObjectMonitor

    内置锁(ObjectMonitor)

    Monitor可以理解为一个同步工具或一种同步机制,通常被描述为一个对象。每一个Java对象就有一把看不见的锁,称为内部锁或者Monitor锁。

    通常所说的对象的内置锁,是对象头Mark Word中的重量级锁指针指向的monitor对象,该对象是在HotSpot底层C++语言编写的(openjdk里面看),简单看一下代码:

    //结构体如下
    ObjectMonitor::ObjectMonitor() {  
      _header       = NULL;  
      _count       = 0;  
      _waiters      = 0,  
      _recursions   = 0;       //线程的重入次数
      _object       = NULL;  
      _owner        = NULL;    //标识拥有该monitor的线程
      _WaitSet      = NULL;    //等待线程组成的双向循环链表,_WaitSet是第一个节点
      _WaitSetLock  = 0 ;  
      _Responsible  = NULL ;  
      _succ         = NULL ;  
      _cxq          = NULL ;    //多线程竞争锁进入时的单向链表
      FreeNext      = NULL ;  
      _EntryList    = NULL ;    //_owner从该双向循环链表中唤醒线程结点,_EntryList是第一个节点
      _SpinFreq     = 0 ;  
      _SpinClock    = 0 ;  
      OwnerIsThread = 0 ;  
    }  
    

    特别重要的两个属性:

    监控区(Entry Set):锁已被其他线程获取,期待获取锁的线程就进入Monitor对象的监控区

    待授权区(Wait Set):曾经获取到锁,但是调用了wait方法,线程进入待授权区

    ObjectMonitor队列之间的关系转换:

    img

    内置锁状态转换图:

    对象内置锁ObjectMonitor流程

    • 所有期待获得锁的线程,在锁已经被其它线程拥有的时候,这些期待获得锁的线程就进入了对象锁的entry set区域。
    • 所有曾经获得过锁,但是由于其它必要条件不满足而需要wait的时候,线程就进入了对象锁的wait set区域 。
    • wait set区域的线程获得Notify/notifyAll通知的时候,随机的一个Thread(Notify)或者是全部的Thread(NotifyALL)从对象锁的wait set区域进入了entry set中。
    • 在当前拥有锁的线程释放掉锁的时候,处于该对象锁的entryset区域的线程都会抢占该锁,但是只能有任意的一个Thread能取得该锁,而其他线程依然在entry set中等待下次来抢占到锁之后再执行。

    既然提到了_waitSet_EntryList(_cxq队列后面会说),那就看一下底层的waitnotify方法

    wait方法的实现过程:

      //1.调用ObjectSynchronizer::wait方法
    void ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) {
      /*省略 */
      //2.获得Object的monitor对象(即内置锁)
      ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj());
      DTRACE_MONITOR_WAIT_PROBE(monitor, obj(), THREAD, millis);
      //3.调用monitor的wait方法
      monitor->wait(millis, true, THREAD);
      /*省略*/
    }
      //4.在wait方法中调用addWaiter方法
      inline void ObjectMonitor::AddWaiter(ObjectWaiter* node) {
      /*省略*/
      if (_WaitSet == NULL) {
        //_WaitSet为null,就初始化_waitSet
        _WaitSet = node;
        node->_prev = node;
        node->_next = node;
      } else {
        //否则就尾插
        ObjectWaiter* head = _WaitSet ;
        ObjectWaiter* tail = head->_prev;
        assert(tail->_next == head, "invariant check");
        tail->_next = node;
        head->_prev = node;
        node->_next = head;
        node->_prev = tail;
      }
    }
      //5.然后在ObjectMonitor::exit释放锁,接着 thread_ParkEvent->park  也就是wait
    

    总结:通过object获得内置锁(objectMonitor),通过内置锁将Thread封装成OjectWaiter对象,然后addWaiter将它插入以_waitSet为首结点的等待线程链表中去,最后释放锁。

    notify方法的底层实现

      //1.调用ObjectSynchronizer::notify方法
        void ObjectSynchronizer::notify(Handle obj, TRAPS) {
        /*省略*/
        //2.调用ObjectSynchronizer::inflate方法
        ObjectSynchronizer::inflate(THREAD, obj())->notify(THREAD);
    }
        //3.通过inflate方法得到ObjectMonitor对象
        ObjectMonitor * ATTR ObjectSynchronizer::inflate (Thread * Self, oop object) {
        /*省略*/
         if (mark->has_monitor()) {
              ObjectMonitor * inf = mark->monitor() ;
              assert (inf->header()->is_neutral(), "invariant");
              assert (inf->object() == object, "invariant") ;
              assert (ObjectSynchronizer::verify_objmon_isinpool(inf), "monitor is inva;lid");
              return inf 
          }
        /*省略*/ 
          }
        //4.调用ObjectMonitor的notify方法
        void ObjectMonitor::notify(TRAPS) {
        /*省略*/
        //5.调用DequeueWaiter方法移出_waiterSet第一个结点
        ObjectWaiter * iterator = DequeueWaiter() ;
        //6.后面省略是将上面DequeueWaiter尾插入_EntrySet的操作
        /**省略*/
      }
    

    总结:通过object获得内置锁(objectMonitor),调用内置锁的notify方法,通过_waitset结点移出等待链表中的首结点,将它置于_EntrySet中去,等待获取锁。注意:notifyAll根据policy不同可能移入_EntryList或者_cxq队列中,此处不详谈。

    总结:

    每个对象的Object Monitor控制过程相对独立,但是一个线程可以同时拥有一个或者多个对象的操作权限。

    参考:

    Java线程同步与信号量的奥秘

    JVM 管程介绍

    Java并发基石——所谓“阻塞”:Object Monitor和AQS(1)

  • 相关阅读:
    R语言:提取路径中的文件名字符串(basename函数)
    课程一(Neural Networks and Deep Learning),第三周(Shallow neural networks)—— 0、学习目标
    numpy.squeeze()的用法
    课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 4、Logistic Regression with a Neural Network mindset
    Python numpy 中 keepdims 的含义
    课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 3、Python Basics with numpy (optional)
    课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 2、编程作业常见问题与答案(Programming Assignment FAQ)
    课程一(Neural Networks and Deep Learning),第二周(Basics of Neural Network programming)—— 0、学习目标
    课程一(Neural Networks and Deep Learning),第一周(Introduction to Deep Learning)—— 0、学习目标
    windows系统numpy的下载与安装教程
  • 原文地址:https://www.cnblogs.com/hongdada/p/14513036.html
Copyright © 2011-2022 走看看