- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
Java理论和实践Mustang中的同步优化.doc
Java 理论与实践: Mustang 中的同步优化
Escape 分析有助于优化同步
在 9 月份的 Java 理论与实践 中,专栏作家 Brian Goetz 研究了 Escape 分析,这是许多 JVM 在相当一段时间内已经放入日程表的一项优化,也是预计会在 Mustang (Java? SE 6)发行版的 HotSpot 中出现的优化。可以用 Escape 分析把基于堆的对象分配转换成不太昂贵的基于堆栈的分配,也可以用它做其他优化决策,包括对同步的运用进行优化。这个月,Brian 将介绍一些为 Mustang 安排的同步优化。请在本文附带的 讨论组 中与作者和其他读者分享您对本文的想法。(可以选择文章顶部或底部的 讨论 访问讨论组。)请注意:这一期描述的是 Sun 的 HotSpot JVM 实现未来版本的特性。这里讨论的具体特性可能出现在 Java SE 6 (“Mustang”)中,也可能不出现;有些可能会推迟到 Java SE 7 (“Dolphin”)。
每当易变的变量在线程间共享时,都必须使用同步来确保一个线程所做的更新,能够及时地被其他线程看到。同步的主要方式就是使用 synchronized 块,它既提供了互斥又提供了可见性保证。(其他的同步形式包括 volatile 变量、java.util.concurrent.locks 中的 Lock 对象,以及原子变量。)当两个线程都想访问共享的易变变量时,这两个线程不仅必须使用同步,而且如果它们正在使用 synchronized 块,那么这些 synchronized 块还必须使用同一个锁对象。
在实践中,锁定分为两类:多数竞争锁和多数非竞争锁。多数竞争锁是应用程序中的“热”锁,例如保护线程池的共享工作队列的锁。不断地会有许多线程需要这些锁保护的数据,所以可以想象,当要取得这个锁的时候,可能不得不等候其他人用完它。而多数非竞争锁保护的数据被访问得不那么频繁,所以多数时候,当线程要取得锁时,不会有其他线程正在持有这个锁。大多数锁都不是频繁争用的,所以改善非竞争锁定的性能可以实际地改善应用程序的整体性能。
JVM 对于竞争锁请求和非竞争锁请求有不同的代码路径,分别是“慢路径”和“快路径”。在快路径的优化上,已经做了许多工作;Mustang 进一步改善了快路径和慢路径,并添加了许多能够完全清除某些锁定的优化。
锁省略
Java 内存模型规定,在另一个线程进入由同一个锁保护的同步块之前,一个线程应该退出同步块;这就意味着线程 A 在退出锁 M 保护的 synchronized 块时所能看到的所有内存操作,线程 B 进入 M 保护的 synchronized 块时都会看到,如图 1 所示。对于使用不同锁的 synchronized 块,没法估计它们的顺序 —— 就像根本没有同步一样。
图 1. Java 内存模型中的同步和可见性
毫无疑义,如果线程进入由一个没有任何其他线程在其上同步的锁保护的 synchronized 块,那么这个同步就没有效果,因而可以被优化器删除。(Java 语言规范 明确地允许这种优化。)这种场景听起来好像不太可能,但是确实存在这种场景对编译器属实的情况。清单 1 展示了一个线程本地锁对象的简化示例:
清单 1. 用线程本地对象作为锁
synchronized (new Object()) {
doSomething();
}
因为对锁对象的引用在其他线程可以使用它之前就消失了,所以编译器就可以认为以上同步可以删除,因为不可能有两个线程用这同一个锁进行同步。虽然没有人会直接使用清单 1 中的形式,但是与这个代码非常类似的情况是:可以证实与 synchronized 块关联的锁是一个线程本地变量。“线程本地”并不一定意味着变量由 ThreadLocal 类实现;它可以是任何变量,只要编译器能够证实没有其他线程访问这个变量即可。由本地变量引用的对象以及从来不会离开自己定义范围的对象,都满足这个测试 —— 如果对象局限在某些线程的堆栈内,那么其他线程就看不到这个对象的引用。(可以跨线程共享对象的惟一方式就是把对象的引用发布到堆中。)
碰巧的是,我们 上个月 讨论的 Escape 分析为编译器提供了需要的确切信息,以优化掉使用线程本地锁对象的 synchronized 块。如果编译器能够证实(使用 Escape 分析)某个对象从未发布到堆中,那么它肯定是个线程本地对象,所以任何使用这个对象作为锁的 synchronized 块在 Java 内存模型(JMM)下就都不会有效果,所以可以被清除掉。这个优化叫做锁省略,是为 Mustang 安排的另一个 JVM 优化。
用线程本地对象进行锁定的情况要比想像的出现得更频繁。
文档评论(0)