Hotspot重量级锁ObjectMonitor(一)源码解析

更新时间:2023-05-17 11:36:58 阅读: 评论:0

Hotspot重量级锁ObjectMonitor(⼀)源码解析
⽬录
ObjectMonitor不仅是重量级锁的实现,还是Object的wait/notify/notifyAll⽅法的底层核⼼实现,本篇博客就详细探讨该类的实现。1、定义
ObjectMonitor的定义位于hotspot\src\share\vm\runtime\objectMonitor.hpp中,包含如下属性:
volatile markOop  _header;      // 锁对象oop的原始对象头
void*    volatile _object;      // 关联的锁对象oop
double SharingPad [1] ;          // temp to reduce fal sharing
void *  volatile _owner;          // 占⽤当前锁的线程
volatile jlong _previous_owner_tid; // thread id of the previous owner of the monitor
volatile intptr_t  _recursions;  //记录嵌套(递归)加锁的次数,最外层的锁的_recursions属性为0
int OwnerIsThread ;              // 表明当前owner原来持有轻量级锁
ObjectWaiter * volatile _cxq ;    // cxq链表头元素
ObjectWaiter * volatile _EntryList ;    // EntryList 链表头元素
Thread * volatile _succ ;          // Heir presumptive thread - ud for futile wakeup throttling
Thread * volatile _Responsible ;
int _PromptDrain ;                // rqst to drain cxq into EntryList ASAP蕨菜
volatile int _Spinner ;          // ⽤来记录正在⾃旋的线程数
volatile int _SpinFreq ;          // Spin 1-out-of-N attempts: success rate
volatile int _SpinClock ;
volatile int _SpinDuration ; //⽤来控制⾃旋的总次数
volatile intptr_t _SpinState ;    // MCS/CLH list of spinners
volatile intptr_t  _count;        // 抢占该锁的线程数
93年属什么生肖
volatile intptr_t  _waiters;      // 调⽤wait⽅法后等待的线程数
ObjectWaiter * volatile _WaitSet; // 调⽤wait⽅法后等待的ObjectWaiter链表
volatile int _WaitSetLock;        // 操作WaitSet链表的锁
int _QMix ;                      // Mixed prepend queue discipline
ObjectMonitor * FreeNext ;        // Free list linkage
2、TrySpin_VaryDuration
默认配置下⾃旋的次数是会⾃适应调整的,可以通过参数指定⾃旋固定的次数,注意在⾃旋的过程中会判断是否进⼊安全点同步,如果是则终⽌⾃旋。
int ObjectMonitor::TrySpin_VaryDuration (Thread * Self) {
//Knob_FixedSpin默认是0,表⽰固定⾃旋的次数
int ctr = Knob_FixedSpin ;
if (ctr != 0) {
//每⼀次while循环都是⼀次⾃旋,在指定的次数内抢占成功就是成功,否则失败
while (--ctr >= 0) {
//尝试抢占该锁,如果成功返回1
if (TryLock (Self) > 0) return 1 ;
//抢占失败,该⽅法直接返回0
SpinPau () ;
}
return 0 ;
return 0 ;
}
//Knob_PreSpin的默认值是10
for (ctr = Knob_PreSpin + 1; --ctr >= 0 ; ) {
if (TryLock(Self) > 0) {
//抢占成功
int x = _SpinDuration ;
//Knob_SpinLimit的默认值是5000
if (x < Knob_SpinLimit) {
//增加_SpinDuration
//Knob_Poverty的默认值是1000,Knob_BonusB对的默认值是100
if (x < Knob_Poverty) x = Knob_Poverty ;
//即_SpinDuration的最⼩值是1100,最⼤值是5000
_SpinDuration = x + Knob_BonusB ;
}
return 1 ;
}
SpinPau () ;
}
ctr = _SpinDuration  ;
//Knob_SpinBa的默认值是10
if (ctr < Knob_SpinBa) ctr = Knob_SpinBa ;
if (ctr <= 0) return 0 ;
//Knob_SuccRestrict默认为0
if (Knob_SuccRestrict && _succ != NULL) return 0 ;
小人之过也必文/
/Knob_OState默认为3,NotRunnable⽤于判断⽬标线程是否退出,如果已退出则终⽌⾃旋    if (Knob_OState && NotRunnable (Self, (Thread *) _owner)) {
TEVENT (Spin abort - notrunnable [TOP]);
return 0 ;
}
//Knob_MaxSpinners默认为-1
int MaxSpin = Knob_MaxSpinners ;
if (MaxSpin >= 0) {
if (_Spinner > MaxSpin) {
TEVENT (Spin abort -- too many spinners) ;
return 0 ;
}
//原⼦的将_Spinner属性加1,不断循环直到修改成功
Adjust (&_Spinner, 1) ;
}
int hits    = 0 ;
int msk    = 0 ;
//Knob_CASPenalty默认值是-1
int caspty  = Knob_CASPenalty ;
//Knob_OXPenalty默认值是-1
int oxpty  = Knob_OXPenalty ;
//Knob_SpinSetSucc默认值是1
int sss    = Knob_SpinSetSucc ;
if (sss && _succ == NULL ) _succ = Self ;
Thread * prv = NULL ;
// There are three ways to exit the following loop:
// 1.  A successful spin where this thread has acquired the lock.
// 2.  Spin failure with prejudice
// 3.  Spin failure without prejudice
while (--ctr >= 0) {
if ((ctr & 0xFF) == 0) {
//0xFF就是256,即每⾃旋256次就需要检查是否开启了安全点同步
//0xFF就是256,即每⾃旋256次就需要检查是否开启了安全点同步        if (SafepointSynchronize::do_call_back()) {
//do_call_back返回true,说明进⼊了安全点同步
TEVENT (Spin: safepoint) ;
//跳转到Abort
goto Abort ;
}
招聘背景//Knob_UPau默认值是1
if (Knob_UPau & 1) SpinPau () ;
//SpinCallbackFunction默认为NULL
int (*scb)(intptr_t,int) = SpinCallbackFunction ;
if (hits > 50 && scb != NULL) {
int abend = (*scb)(SpinCallbackArgument, 0) ;
}
}
if (Knob_UPau & 2) SpinPau() ;
if (ctr & msk) continue ;
++hits ;
if ((hits & 0xF) == 0) {
//BackOffMask默认值是0
msk = ((msk << 2)|3) & BackOffMask ;
}
Thread * ox = (Thread *) _owner ;
if (ox == NULL) {
//该锁未被占⽤,通过cas抢占
ox = (Thread *) Atomic::cmpxchg_ptr (Self, &_owner, NULL) ;
if (ox == NULL) {
//抢占成功
if (sss && _succ == Self) {
_succ = NULL ;
摄影基础知识
}
//原⼦的将_Spinner减1
if (MaxSpin > 0) Adjust (&_Spinner, -1) ;
//增加_SpinDuration
int x = _SpinDuration ;
if (x < Knob_SpinLimit) {
if (x < Knob_Poverty) x = Knob_Poverty ;
_SpinDuration = x + Knob_Bonus ;
}
return 1 ;
}
//CAS抢占失败,caspty默认是-1
prv = ox ;
TEVENT (Spin: cas failed) ;
if (caspty == -2) break ;
if (caspty == -1) goto Abort ;
ctr -= caspty ;
continue ;
} //if结束
//如果占有该锁的线程发⽣改变了,oxpty默认值是-1
if (ox != prv && prv != NULL ) {
TEVENT (spin: Owner changed)
if (oxpty == -2) break ;
if (oxpty == -1) goto Abort ;
ctr -= oxpty ;
}
//记录下当前占⽤锁的线程
prv = ox ;
prv = ox ;
//如果占有该锁的线程退出了,则终⽌⾃旋
if (Knob_OState && NotRunnable (Self, ox)) {
TEVENT (Spin abort - notrunnable);
goto Abort ;
offer用法}
if (sss && _succ == NULL ) _succ = Self ;
} //while循环结束
TEVENT (Spin failure) ;
{
int x = _SpinDuration ;
if (x > 0) {
//Knob_Penalty的默认值是200
x -= Knob_Penalty ;
if (x < 0) x = 0 ;
//实际就是将_SpinDuration减去Knob_Penalty
_SpinDuration = x ;
}
}
Abort:
if (MaxSpin >= 0) Adjust (&_Spinner, -1) ;
if (sss && _succ == Self) {
_succ = NULL ;
OrderAccess::fence() ;
//尝试获取锁
if (TryLock(Self) > 0) return 1 ;
}
return 0 ;
}
int ObjectMonitor::TryLock (Thread * Self) {
for (;;) {
void * own = _owner ;
//如果不等于NULL说明某个线程依然占⽤该锁
if (own != NULL) return 0 ;
if (Atomic::cmpxchg_ptr (Self, &_owner, NULL) == NULL) {
//如果交换成功,说明抢占成功
asrt (_recursions == 0, "invariant") ;
asrt (_owner == Self, "invariant") ;
return 1 ;
}
//抢占失败返回-1
if (true) return -1 ;
}
}
extern "C" {
int SpinPau() {
return 0;
}
}
3、ObjectWaiter
ObjectWaiter表⽰⼀个等待获取ObjectMonitor锁的线程,其定义如下:
其中next和prev属性表⽰ ObjectWaiter链表中的前后节点,_thread和_event都是关联的线程属性,TState⽤于描述当前ObjectWaiter 的状态,刚创建时的状态是TS_RUN,加⼊到cxq链表中状态是TS_CXQ,加⼊到EntryList链表后变成TS_ENTER,加⼊到WaitSet链表中的状态就是TS_WAIT,另外两个状态枚举没有调⽤。_active⽤于记录当前线程是否开启了线程监控,如果开启了可以通过jmm接⼝获取线程运⾏的统计数据,⽐如锁抢占的次数和累计耗时。_notified属性⽤于记录该ObjectWaiter是否被某个线程唤醒了⽽不是因为线程中断唤醒的,_notifier_tid⽤于记录执⾏唤醒动作的线程指针。
三个⽅法的实现如下:
ObjectWaiter::ObjectWaiter(Thread* thread) {
_next    = NULL;
_prev    = NULL;
_notified = 0;
//初始状态
TState    = TS_RUN ;
//关联的线程
_thread  = thread;
_event    = thread->_ParkEvent ;
_active  = fal;
asrt (_event != NULL, "invariant") ;
}
void ObjectWaiter::wait_reenter_begin(ObjectMonitor *mon) {
JavaThread *jt = (JavaThread *)this->_thread;
_active = JavaThreadBlockedOnMonitorEnterState::wait_reenter_begin(jt, mon);
}
void ObjectWaiter::wait_reenter_end(ObjectMonitor *mon) {
JavaThread *jt = (JavaThread *)this->_thread;
JavaThreadBlockedOnMonitorEnterState::wait_reenter_end(jt, _active);
}bkill
static bool wait_reenter_begin(JavaThread *java_thread, ObjectMonitor *obj_m) {
自由资本主义
asrt((java_thread != NULL), "Java thread should not be null here");
bool active = fal;
if (is_alive(java_thread) && ServiceUtil::visible_oop((oop)obj_m->object())) {
active = contended_enter_begin(java_thread);
}
return active;
}
static void wait_reenter_end(JavaThread *java_thread, bool active) {
if (active) {
java_thread->get_thread_stat()->contended_enter_end();
}
//修改线程状态
t_thread_status(java_thread, java_lang_Thread::RUNNABLE);

本文发布于:2023-05-17 11:36:58,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/907924.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:线程   是否   抢占   次数   链表   开启   状态   记录
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图