Java多线程&安全出版

时间:2009-04-29 11:49:43

标签: java multithreading safe-publication

阅读“Java concurrent in practice”和“OSGI in practice”后,我发现一个特定主题非常有趣;安全出版。以下内容来自JCIP:

  

要安全地发布对象,必须同时对其他线程显示对象的引用和对象的状态。正确构造的对象可以通过以下方式安全地发布:

     
      
  • 静态初始值设定项初始化对象引用。
  •   
  • 将对它的引用存储到 volatile 字段中。
  •   
  • 将对它的引用存储到最终字段中。
  •   
  • 将对它的引用存储到由(同步)锁定正确保护的字段中。
  •   

我的第一个问题:有多少java开发人员意识到这个(问题)? 有多少真实世界的Java应用程序真正遵循这个,这真的是一个真正的问题吗?我有一种感觉,99%的已实现的JVM不是那种“邪恶”,即一个线程不能保证(事实上它实际上(几乎)“不可能”)看到陈旧数据只是因为引用不遵循上面的“安全出版成语”。

6 个答案:

答案 0 :(得分:20)

按比例,可以说很少有程序员能够充分理解同步和并发性。谁知道现在有多少服务器应用程序正在管理金融交易,医疗记录,警察记录,电话等等,这些都充满了同步错误,基本上是偶然的,或者偶尔会失败(从未听说过任何人得到幻像)电话费被添加到他们的电话账单中?)原因从未真正被调查或深入到底。

对象发布是一个特殊的问题,因为它经常被忽略,而且如果您不了解它,那么编译器进行可能导致意外行为的优化是非常合理的:在JIT编译的代码中,存储一个指针,然后递增它并存储数据是一件非常合理的事情。您可能认为它是“邪恶的”,但在较低的层次上,它实际上是您对JVM规范的期望。 (顺便说一句,我听说JRockit中运行的现实程序遇到了这个问题 - 这不是纯理论上的。)

如果您知道您的应用程序存在同步错误但在您当前的硬件上当前的JVM中没有行为不端,那么(a)恭喜您; (b)现在是时候开始“平静地走向火灾出口”,在需要升级太多组件之前修复代码并教育程序员。

答案 1 :(得分:5)

“这真的是一个真正的问题吗?”

绝对是的。即使是最琐碎的Web应用程序也必须面对并发问题。例如,Servlet由多个线程访问。

另一个问题是线程和并发很难正确处理。这太难了。这就是为什么我们看到趋势出现像事务性内存,以及像Clojure这样的语言,希望能使并发更容易处理。但在这些成为主流之前,我们还有很长的路要走。因此,我们必须尽我们所能。阅读JCiP是一个非常好的开始。

答案 2 :(得分:2)

首先,“安全出版物”并非真正的成语(IMO)。它直接来自语言。

例如,使用NIO时,出现了不安全发布问题。

大多数Java代码编写得非常糟糕。线程代码显然比平均业务代码更难。

答案 3 :(得分:2)

这不是“邪恶”的问题。 是一个真正的问题,随着未来几年多核架构的兴起,它将变得更加明显。由于同步不当,我看到了非常真实的生产错误。回答你的另一个问题,我会说很少有程序员知道这个问题,即使在其他“好”的开发人员中也是如此。

答案 4 :(得分:1)

我想说很少有程序员可以解决这个问题。您看到的最后一个代码示例是什么时候使用了volatile关键字?然而,大多数提到的其他条件 - 我只是理所当然地认为是最佳实践。

如果开发人员完全忽略这些条件,他们很快就会遇到多线程错误。

答案 5 :(得分:1)

我的经验(在许多不同类型的环境中进行短期和咨询 我见过的大多数应用程序都同意这种直觉 - 我从来没有看到整个系统明确地设计来仔细管理这个问题(好吧,我也几乎从未见过整个系统的架构清晰)。我和非常少的开发人员一起工作,他们对线程问题有很好的了解。

特别是对于网络应用,你可以经常逃脱这一点,或者至少似乎侥幸逃脱。如果您有基于Spring的实例化来管理对象创建和无状态servlet,您通常会假装没有同步这样的东西,这就是许多应用程序最终的排序。最终有人开始将一些共享状态放在不属于它的地方,3个月后有人注意到一些奇怪的间歇性错误。对于许多人来说,这通常“足够好”(只要你不写银行交易)。

有多少java开发人员都知道这个问题?很难说,因为它在很大程度上取决于你的工作地点。