- 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 理论与实践: JDK 5.0 中更灵活、更具可伸缩性的锁定机制
多线程和并发性并不是什么新内容,但是 Java 语言设计中的创新之一就是,它是第一个直接把跨平台线程模型和正规的内存模型集成到语言中的主流语言。核心类库包含一个 Thread 类,可以用它来构建、启动和操纵线程,Java 语言包括了跨线程传达并发性约束的构造 —— synchronized 和 volatile 。在简化与平台无关的并发类的开发的同时,它决没有使并发类的编写工作变得更繁琐,只是使它变得更容易了。
synchronized 快速回顾
把代码块声明为 synchronized,有两个重要后果,通常是指该代码具有 原子性(atomicity)和 可见性(visibility)。 原子性意味着一个线程一次只能执行由一个指定监控对象(lock)保护的代码,从而防止多个线程在更新共享状态时相互冲突。可见性则更为微妙;它要对付内 存缓存和编译器优化的各种反常行为。一般来说,线程以某种不必让其他线程立即可以看到的方式(不管这些线程在寄存器中、在处理器特定的缓存中,还是通过指 令重排或者其他编译器优化),不受缓存变量值的约束,但是如果开发人员使用了同步,如下面的代码所示,那么运行库将确保某一线程对变量所做的更新先于对现 有 synchronized 块所进行的更新,当进入由同一监控器(lock)保护的另一个 synchronized 块时,将立刻可以看到这些对变量所做的更新。类似的规则也存在于 volatile 变量上。(有关同步和 Java 内存模型的内容,请参阅 参考资料。)
synchronized (lockObject) {
// update object state
}
所以,实现同步操作需要考虑安全更新多个共享变量所需的一切,不能有争用条件,不能破坏数据(假设同步的边界位置正确),而且要保证正确同步的其他线程可 以看到这些变量的最新值。通过定义一个清晰的、跨平台的内存模型(该模型在 JDK 5.0 中做了修改,改正了原来定义中的某些错误),通过遵守下面这个简单规则,构建“一次编写,随处运行”的并发类是有可能的:
不论什么时候,只要您将编写的变量接下来可能被另一个线程读取,或者您将读取的变量最后是被另一个线程写入的,那么您必须进行同步。
不过现在好了一点,在最近的 JVM 中,没有争用的同步(一个线程拥有锁的时候,没有其他线程企图获得锁)的性能成本还是很低的。(也不总是这样;早期 JVM 中的同步还没有优化,所以让很多人都这样认为,但是现在这变成了一种误解,人们认为不管是不是争用,同步都有很高的性能成本。)
回页首
对 synchronized 的改进
如此看来同步相当好了,是么?那么为什么 JSR 166 小组花了这么多时间来开发 java.util.concurrent.lock 框架呢?答案很简单-同步是不错,但它并不完美。它有一些功能性的限制 —— 它无法中断一个正在等候获得锁的线程,也无法通过投票得到锁,如果不想等下去,也就没法得到锁。同步还要求锁的释放只能在与获得锁所在的堆栈帧相同的堆栈 帧中进行,多数情况下,这没问题(而且与异常处理交互得很好),但是,确实存在一些非块结构的锁定更合适的情况。
ReentrantLock 类
java.util.concurrent.lock 中的 Lock 框架是锁定的一个抽象,它允许把锁定的实现作为 Java 类,而不是作为语言的特性来实现。这就为 Lock 的多种实现留下了空间,各种实现可能有不同的调度算法、性能特性或者锁定语义。 ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和内存语义,但是添加了类似锁投票、定时锁等候和可中断锁等候的一些特性。此外,它还提供了在激烈争用情况下更佳的性能。(换句话说,当许多线程都想访问共享资源时,JVM 可以花更少的时候来调度线程,把更多时间用在执行线程上。)
reentrant 锁意味着什么呢?简单来说,它有一个与锁相关的获取计数器,如果拥有锁的某个线程再次得到锁,那么获取计数器就加1,然后锁需要被释放两次才能获得真正释放。这模仿了 synchronized 的语义;如果线程进入由线程已经拥有的监控器保护的 synchronized 块,就允许线程继续进行,当线程退出第二个(或者后续) synchronized 块的时候,不释放锁,只有线程退出它进入的监控器保护的第一个 synchronized 块时,才释放锁。
在查看清单 1 中的代码示例时,可以看到 Lock 和 synchronized 有一点明显的区别 —— lock 必须在 finally 块中释放。否则,如果受保护的
原创力文档


文档评论(0)