在上一篇文章中,小编为您详细介绍了关于《为什么样电脑的时间闹不准?魔术官方晒出了一张图片》相关知识。本篇中小编将再为您讲解标题object的wait方法的原理是使用的阻塞队列还是一直轮询变量呀?java的gc为什么样要分代。
我自己测试感觉应该是类似于阻塞队列的形式,把线程挂起了~求大佬给个明确的答案。
参照HotSpot VM的实现,源码参考:
将当前调用wait方法的线程包装成ObjectWaiter对象节点,加入状态为TS_WAIT的阻塞线程队列_WaitSet中去,这是①个环形双向链表的数据结构;然后调用ObjectMonitor::exit()函数释放当前锁对象——将对象所属线程_owner置成NULL:
OrderAccess::release_store_ptr (
之后根据JVM配置参数QMode从等待获取对象锁的线程列表中选择①个Wakee,这是①个ObjectWaiter指针,最后调用os::PlatformEvent::unpark()唤醒之(以下代码为os_bsd平台下的实现):
void os::PlatformEvent::unpark() { // Transitions for _Event: // ⓪ :=> ① // ① :=> ① // -① :=> either ⓪ or ①; must signal target thread // That is, we can safely transition _Event from -① to either // ⓪ or ①. Forcing ① is slightly more efficient for back-to-back // unpark() calls. // See also: \"Semaphores in Plan ⑨\" by Mullender // Wait for the thread associated with the event to vacate int status = pthread_mutex_lock(_mutex); assert_status(status == ⓪ · status, \"mutex_lock\"); int AnyWaiters = _nParked; assert(AnyWaiters == ⓪ || AnyWaiters == ① · \"invariant\"); if (AnyWaiters != ⓪ pthread_cond_signal(_cond); } status = pthread_mutex_unlock(_mutex); assert_status(status == ⓪ · status, \"mutex_unlock\"); if (AnyWaiters != ⓪) { status = pthread_cond_signal(_cond); assert_status(status == ⓪ · status, \"cond_signal\"); } // Note that we signal() _after dropping the lock for \"immortal\" Events. // This is safe and avoids a common class of futile wakeups. In rare // circumstances this can cause a thread to return prematurely from // cond_{timed}wait() but the spurious wakeup is benign and the victim will // simply re-test the condition and re-park itself.}
做完这些之后,就要将当前线程挂起了,调用os::PlatformEvent::park()函数实现,仍然贴出os_bsd版本的实现代码:
void os::PlatformEvent::park() { // AKA \"down()\" // Invariant: Only the thread associated with the Event/PlatformEvent // may call park(). // TODO: assert that _Assoc != NULL or _Assoc == Self int v ; for (;;) { v = _Event ; if (Atomic::cmpxchg (v-① · } guarantee (v >= ⓪ · \"invariant\") ; if (v == ⓪) { // Do this the hard way by blocking ... int status = pthread_mutex_lock(_mutex); assert_status(status == ⓪ · status, \"mutex_lock\"); guarantee (_nParked == ⓪ · \"invariant\") ; ++ _nParked ; while (_Event < ⓪) { status = pthread_cond_wait(_cond, _mutex); // for some reason, under ②.⑦ lwp_cond_wait() may return ETIME ... // Treat this the same as if the wait was interrupted if (status == ETIMEDOUT) { status = EINTR; } assert_status(status == ⓪ || status == EINTR, status, \"cond_wait\"); } -- _nParked ; _Event = ⓪ ; status = pthread_mutex_unlock(_mutex); assert_status(status == ⓪ · status, \"mutex_unlock\"); // Paranoia to ensure our locked and lock-free paths interact // correctly with each other. OrderAccess::fence(); } guarantee (_Event >= ⓪ · \"invariant\") ;}
通过上述两段代码,可以看出线程的挂起和唤醒是通过UNIX(对应BSD版本)线程库函数pthread_cond_wait和pthread_cond_signal实现的。
这就是典型的根据个体过往行为的统计来预测它未来的行为
然后根据预测的结果 把他们划分到不同的组中 根据每个组代表的群体的行为特点来选择不同的策略
这个用的地方太多太多了
举①些例子
比如cpu的分支预测 就是根据统计之前这个分支处哪个分支执行的次数多来决定指令缓存的策略
比如银行办信用卡 会评估你的信用 方法就是利用你以往的消费习惯 社交圈 社会地位等等来决定给你多少额度
这个分代也是①样的 你要知道扫描①遍所有对象来确定可达性 标记出无用对象是非常慢的 因为对象数量可能极其庞大 而且每个个体的存活时间差别很大 有些对象可能会长期存在 有些可能只存在①小会
很显然把它们①视同仁肯定不是最好的办法
对于存活时间短的对象和长的对象 应该用不同的策略
第①个问题就是如何知道谁比较可能活的长呢
当然是已经活的很长的对象比较有可能活的更长
然后我们把所有刚出生的对象都放到①个叫新生代的组里 并持续扫描它们 如果①个对象在n次扫描时都还存活 就很有理由相信它可能会活很久了吧 这时就能把它放到老年代中了
为什么要分组呢 因为对不同组做扫描的成本和收益有很大区别 这里例子是两组 实际可以分成任意组
新生代会以较高的频率执行可达性扫描 来标记无用对象
只有当新生代中无用对象全释放后仍然不能得到足够的空间 才会考虑看看老年代里是否有对象可以释放
所以内存还足够时gc只会扫描新生代 新生代的特点是瞬时数量较少 但“流动性”大 很多对象可能只存活①小会 而存活时间长的会转入老年代 所以扫描这些对象成本小且收益高(因为有比较大的概率找到可以释放的对象)
老年代则完全相反 数量多(因为只要不是因为内存不足触发full gc 就不会去释放其中对象 久而久之会累积大量对象)而且里面的对象根据过往行为统计(其实就是当某个新生代对象在n个普通gc过程中 都①直存活 就可以有理由相信这个对象可能会活很久 就会进入老年代)来看 他们寿命长的概率很高 所以扫描老年代 成本高收益却低(因为有比较大概率它们仍然还存活 无法释放)
再举个形象的例子
试想城市住房分配管理该怎么做
首先城市住房数量是①定的
城市中有大量流动人口和常住人口
当城市住房不足时
你应该去把你的人力花费去跟踪流动人口住房 还是常驻人口住房呢
很显然你应该跟踪流动人口 第①他们的瞬时数量远比常驻人口少
第②因为他们中大部分很可能只在这个城市呆①会 就走了 然后你就能把他们本来占有的住房资源给需要的人 你花了很小的代价 基本每次都能有很大收获
你去跟踪常住人口 显然收益很小 首先他们数量大 第②他们可能①辈子都住在这个城市 你无法回收他们的住房资源 你花了大力气 结果基本每次都没收获 只有在流动人口处真的完全找不到足够的空房的情况下 才会来这里碰碰运气 看看有没有人搬走了
当然在你跟踪流动人口的过程中 如果你发现某个人①⓪年①直都住在这个城市 那么你有理由相信 可能未来很长时间 他都不会走了 那么你就应该把它划入常驻人口中 来减少跟踪成本
编后语:关于《object的wait方法的原理是使用的阻塞队列还是一直轮询变量呀?java的gc为什么样要分代》关于知识就介绍到这里,希望本站内容能让您有所收获,如有疑问可跟帖留言,值班小编第一时间回复。 下一篇内容是有关《请问高玩们游戏本aorus x7 dt v6还有ROG Strix GL702VS咋选?请问游戏本6000左右买哪一款好一些》,感兴趣的同学可以点击进去看看。
小鹿湾阅读 惠尔仕健康伙伴 阿淘券 南湖人大 铛铛赚 惠加油卡 oppo通 萤石互联 588qp棋牌官网版 兔牙棋牌3最新版 领跑娱乐棋牌官方版 A6娱乐 唯一棋牌官方版 679棋牌 588qp棋牌旧版本 燕晋麻将 蓝月娱乐棋牌官方版 889棋牌官方版 口袋棋牌2933 虎牙棋牌官网版 太阳棋牌旧版 291娱乐棋牌官网版 济南震东棋牌最新版 盛世棋牌娱乐棋牌 虎牙棋牌手机版 889棋牌4.0版本 88棋牌最新官网版 88棋牌2021最新版 291娱乐棋牌最新版 济南震东棋牌 济南震东棋牌正版官方版 济南震东棋牌旧版本 291娱乐棋牌官方版 口袋棋牌8399 口袋棋牌2020官网版 迷鹿棋牌老版本 东晓小学教师端 大悦盆底 CN酵素网 雀雀计步器 好工网劳务版 AR指南针 布朗新风系统 乐百家工具 moru相机 走考网校 天天省钱喵 体育指导员 易工店铺 影文艺 语音文字转换器