阅读“Java concurrent in practice”和“OSGI in practice”后,我发现一个特定主题非常有趣;安全出版。以下内容来自JCIP:
要安全地发布对象,必须同时对其他线程显示对象的引用和对象的状态。正确构造的对象可以通过以下方式安全地发布:
- 从静态初始值设定项初始化对象引用。
- 将对它的引用存储到 volatile 字段中。
- 将对它的引用存储到最终字段中。
- 将对它的引用存储到由(同步)锁定正确保护的字段中。
我的第一个问题:有多少java开发人员意识到这个(问题)? 有多少真实世界的Java应用程序真正遵循这个,这真的是一个真正的问题吗?我有一种感觉,99%的已实现的JVM不是那种“邪恶”,即一个线程不能保证(事实上它实际上(几乎)“不可能”)看到陈旧数据只是因为引用不遵循上面的“安全出版成语”。
答案 0 :(得分:20)
按比例,可以说很少有程序员能够充分理解同步和并发性。谁知道现在有多少服务器应用程序正在管理金融交易,医疗记录,警察记录,电话等等,这些都充满了同步错误,基本上是偶然的,或者偶尔会失败(从未听说过任何人得到幻像)电话费被添加到他们的电话账单中?)原因从未真正被调查或深入到底。 p>
对象发布是一个特殊的问题,因为它经常被忽略,而且如果您不了解它,那么编译器进行可能导致意外行为的优化是非常合理的:在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开发人员都知道这个问题?很难说,因为它在很大程度上取决于你的工作地点。