前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一次与印度兄弟就Java10中的Thread-Local Handshakes的探讨

一次与印度兄弟就Java10中的Thread-Local Handshakes的探讨

作者头像
ImportSource
发布2018-05-04 10:48:30
1.8K0
发布2018-05-04 10:48:30
举报
文章被收录于专栏:ImportSourceImportSource

背景

Java10引入了Thread Local Handshake功能。对此功能本人看了JEP312以后还是没有一个比较清晰的认识。为此,问了一些国内的JVM专家也没有获得一个回复。

后来,我就去某特上搜索关键字,然后在相关主题下提交了我的疑问希望获取到他们的回复和帮助。

在以为要石沉大海的时候,最后有一位住在印度南部班加罗尔的兄弟回答了我的问题。

以上大概是一个基本的背景。在正式展开问题和展示回复之前,我们还是要对Java10中的这个新的功能做一个基本的铺垫。

Safepoint及其不足

Safepoint是Hotspot JVM中一种让所有应用程序停止的一种机制。为了要做一些非常之安全的事情,需要让所有人都停下来它才好做。比如广场上,人来人往,有人忽然要清点人数,这时候,最好就是大家都原地不动,这样也好统计。Safepoint起到的就是这样一个作用。

JVM会把设置一个全局的状态值。应用线程去观察这个值,一旦发现JVM把此值设置为了“大家都停下来”。

此时每个应用线程就会得到这个通知,然后各自选择一个point(点)停了下来。

这也是为什么叫safepoint。之所以加safe,是强调JVM要做一些全局的安全的事情了,所以给这个点加了个safe。

待所有的应用线程都停下来了。JVM就开始做一些安全级别非常高的事情了。

比如下面这些事情:

垃圾清理暂停。

代码去优化(Code deoptimization)。

flush code cache。

类文件重新定义时(Class redefinition,比如热更新 or instrumentation)。

偏向锁的取消(Biased lock revocation)。

各种debug操作(比如: 死锁检查或者stacktrace dump等)。

然而,让所有线程都stop了以后才做的一些事情,让所有线程都到就近的safepoint停下来本身就需要较长的时间才能大家都停下来。而且让所有线程都停下来是不是显得太过鲁莽和专断了呢。

为此Java10就引入了一种可以不用stop all threads的方式,就是Thread Local Handshake。

比如以下是不需要stop所有线程就可以搞定的场景:

1、偏向锁撤销。这个事情只需要停止单个线程就可以撤销偏向锁,而不需要停止所有的线程。

2、减少不同类型的可服务性查询的总体VM延迟影响,例如获取具有大量Java线程的VM上的所有线程的stack trace可能是一个缓慢的操作。

3、通过减少对信号(signals)的依赖来执行更安全的stack trace采样。

4、使用所谓的非对称Dekker同步技术,通过与Java线程握手来消除一些内存障碍。 例如,G1和CMS里使用的“条件卡标记码”(conditional card mark code),将不再需要“内存屏障”这个东东。这样的话,G1发送的“写屏障(write barrier)”就可以被优化, 并且那些尝试要规避“内存屏障”的分支也可以被删除了。

note:以上只是四种VM的全局操作的场景,更多VM的全局操作请参阅文末的附录:VM_OPS_DO列表。

有关内存屏障的内容,这里就不赘述了,你可以网上搜索或去虚拟机的书籍里翻阅。总之就是一个针对执行乱序的一种顺序保障机制。英文叫memory barrior,或者叫memory fence。fence就是一个类似围栏的东西,放个图简单的感受下,如下图:

印度兄弟tzj的回复

译文:

我必须得承认当我看到你的消息时,我也是一脸蒙蔽的。然后我就翻了一些资料(是不是很有趣),我想我现在应该是已经大概知道怎么一回事情了。

就我的理解的话,一些操作已经列在了这个链接里了:

http://hg.openjdk.java.net/jdk10/jdk10/hotspot/file/5ab7a67bc155/src/share/vm/runtime/vm_operations.hpp

你可以去看看。

如果我没搞错的话,这些操作是必须要求线程进入safepoint的。比如即使要打印一下某个线程的stack trace,也必须要求所有的线程到达全局的safepoint才可以。

这就意味着操作的延迟,因为此时所有的线程都被stop了(也意味着大量的safepoint被JVM注入到我们的代码中,而“注入”这样的事情是我们在代码层面无法控制的)。

然而,有了ThreadLocal Handshake这个新功能后,就允许上面说的那些操作时只被在线程本地执行就是了,而不用必须要求所有的线程都达到安全点才行。

这一点也在JEP312中的“Motivation”的第二点中被提到(http://openjdk.java.net/jeps/312)

那个第二点的含义似乎是,这样就不再要求所有线程都必须进入到安全点,而且还可以减少JVM任意注入的safepoint的总数,就像我前面说到那样。

这意味着整体延迟会大幅降低。有趣的是这个博客(http://epickrram.blogspot.in/2015/08/jvm-guaranteed-safepoints.html …)提到了一个-XX:+PrintSafePointStatistics参数,可以使用它来检查在程序执行期间被事实上插入了多少个safepoint(不过我本人从来没用过这个参数)。貌似是一个迷人的功能,谢谢你让我知道了这个功能。

原文:

I must confess that I didn't have any idea myself when I saw your message. I dug around a bit though (it's very interesting, isn't it?), and I think I kind of get the picture now. From my understanding, certain operations (as listed in the VM_OPS_DO macro here: http://hg.openjdk.java.net/jdk10/jdk10/hotspot/file/5ab7a67bc155/src/share/vm/runtime/vm_operations.hpp … (if I am not mistaken) require the operations to be carried out at a "safeppint", which the JVM places at its own discretion. For instance, even printing a Stack Trace for a thread requires all threads to be at a global safepoint set by the JVM. This would imply latency during the operation (and also imply a large number of safepoints injected by the JVM at locations beyond our control). However, with this new feature of ThreadLocal Handshake, they will now allow such operations to be performed on threads without requiring all the threads to be at a global safepoint. This is also mentioned in the second point under "Motivation" in the JEP - http://openjdk.java.net/jeps/312 . The implication appears to be that this would not only eliminate the requirement for all threads to be at a global safepoint, but also reduce the total number of global safepoints arbitrarily injected, as mentioned before, by the JVM. This means that overall latency would reduce substantially. Interestingly, this blog (http://epickrram.blogspot.in/2015/08/jvm-guaranteed-safepoints.html …) mentions -XX:+PrintSafePointStatistics as a way to check how many safepoints are actually inserted during program execution (never tried it myself though). Sounds like a fascinating feature though - thanks for introducing me to it! :-)

附VM_OPS_DO列表:

#define VM_OPS_DO(template) template(Dummy) template(ThreadStop) template(ThreadDump) template(PrintThreads) template(FindDeadlocks) template(ClearICs) template(ForceSafepoint) template(ForceAsyncSafepoint) template(Deoptimize) template(DeoptimizeFrame) template(DeoptimizeAll) template(ZombieAll) template(UnlinkSymbols) template(Verify) template(PrintJNI) template(HeapDumper) template(DeoptimizeTheWorld) template(CollectForMetadataAllocation) template(GC_HeapInspection) template(GenCollectFull) template(GenCollectFullConcurrent) template(GenCollectForAllocation) template(ParallelGCFailedAllocation) template(ParallelGCSystemGC) template(CGC_Operation) template(CMS_Initial_Mark) template(CMS_Final_Remark) template(G1CollectFull) template(G1CollectForAllocation) template(G1IncCollectionPause) template(DestroyAllocationContext) template(EnableBiasedLocking) template(RevokeBias) template(BulkRevokeBias) template(PopulateDumpSharedSpace) template(JNIFunctionTableCopier) template(RedefineClasses) template(UpdateForPopTopFrame) template(SetFramePop) template(GetOwnedMonitorInfo) template(GetObjectMonitorUsage) template(GetCurrentContendedMonitor) template(GetStackTrace) template(GetMultipleStackTraces) template(GetAllStackTraces) template(GetThreadListStackTraces) template(GetFrameCount) template(GetFrameLocation) template(ChangeBreakpoints) template(GetOrSetLocal) template(GetCurrentLocation) template(EnterInterpOnlyMode) template(ChangeSingleStep) template(HeapWalkOperation) template(HeapIterateOperation) template(ReportJavaOutOfMemory) template(JFRCheckpoint) template(Exit) template(LinuxDllLoad) template(RotateGCLog) template(WhiteBoxOperation) template(ClassLoaderStatsOperation) template(DumpHashtable) template(DumpTouchedMethods) template(MarkActiveNMethods) template(PrintCompileQueue) template(PrintClassHierarchy) template(ThreadSuspend) template(CTWThreshold) template(ThreadsSuspendJVMTI) template(ICBufferFull) template(ScavengeMonitors)

特别鸣谢:

以上是我对此功能的一个学习整理,如有不正之处还望大家共同讨论指正。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-04-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 ImportSource 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档