为什么在Java中同步昂贵?

时间:2009-11-04 00:45:59

标签: java synchronized

我是Java的新手,我读到synchronized在Java中“非常昂贵”。我想知道的是什么是昂贵的,它是如何昂贵的?

感谢。

5 个答案:

答案 0 :(得分:34)

Maybe it's not as bad as you think

过去很糟糕(这可能就是为什么你读到它“非常昂贵”)。这些模因可能需要很长时间才能消亡

  

同步有多贵?

     

由于涉及缓存刷新和失效的规则,Java语言中的同步块通常比许多平台提供的关键部分设施更昂贵,这些平台通常使用原子“测试和设置位”机器指令来实现。即使程序仅包含在单个处理器上运行的单个线程,同步方法调用仍然比未同步的方法调用慢。如果同步实际上需要争用锁定,则性能损失会大大增加,因为需要多个线程切换和系统调用。

     

幸运的是,JVM的持续改进既提高了整体Java程序的性能,又降低了与每个版本同步的相对成本,并且预计将来会有所改进。此外,同步的性能成本经常被夸大。一个众所周知的消息来源指出,同步方法调用比未同步的方法调用慢50倍。虽然这种说法可能是正确的,但它也具有很大的误导性,并导致许多开发人员避免同步,即使在需要它的情况下也是如此。

话虽如此 - 并发编程仍然可能很慢,但现在并非如此纯粹是Java的错误。精细锁定和粗锁定之间存在权衡。太粗糙显然是坏的,但也可能太精细,因为锁具有非零成本。

考虑争用中的特定资源非常重要。机械硬盘是一个例子,其中更多的线程可以导致更差的性能。

答案 1 :(得分:13)

这很昂贵,因为如果你正在使用线程,并且许多线程必须通过代码的同步部分,那么一次只能执行其中一个。

这就像一个瓶颈。

使用单个线程时甚至会很昂贵,因为无论如何都必须检查是否允许他运行。

如果减少同步段的使用,您的线程将不必停下来查看它们是否可以运行(当然,它们不必共享数据)

可以找到同步工作原理的高级概述here

http://img20.imageshack.us/img20/2066/monitor28synchronizatioc.png

Java样式监视器

答案 2 :(得分:7)

这不是Java特有的。如果没有正确完成,任何多线程环境中的同步都可能被认为是“昂贵的”。在Java中它是否特别糟糕,我不知道。

如果线程使用相同的资源,它会阻止线程并发运行。但是,因为他们使用相同的资源,所以没有更好的选择(必须这样做)。

问题是人们经常保护范围太大的资源。例如,设计糟糕的程序可能会同步整个对象数组,而不是数组中的每个单独元素(甚至是数组的一部分)。

这意味着尝试读取元素7的线程必须等待线程读取或写入元素22.没有必要。如果同步的粒度是在元素级别而不是数组级别,那么这两个线程不会相互干扰。

只有当两个线程试图访问相同的元素时才会出现资源争用。这就是为什么一般规则只是保护尽可能小的资源(当然,受限于同步数量)。

但是,说实话,如果由于两个线程争夺单个资源而导致数据损坏,那么它的价格是多么昂贵并不重要。正确编写应用程序并且只在出现性能问题时担心(“先让它工作然后让它快速运行”是我最喜欢的口头禅)。

答案 3 :(得分:5)

IBM的这个article实际上很好地总结了同步背后的要点。

  

由于涉及缓存刷新和失效的规则,Java语言中的同步块通常比许多平台提供的关键部分设施更昂贵,这些平台通常使用原子“测试和设置位”机器指令来实现。即使程序只包含在单个处理器上运行的单个线程,同步方法调用仍然比非同步方法调用慢。如果同步实际上需要争用锁定,则性能损失会大大增加,因为需要多个线程切换和系统调用。

答案 4 :(得分:2)

其他答案提供了一个很好的技术细节,我不会试图复制。

我将做的是建议您检查文章的日期(以及作者的隐含能力和意识)。在早期的JVM中,Java 中的同步非常慢。但是,它最近有了很大改进,因此无竞争同步比你想象的要快得多,并且无竞争同步也得到了改善。

请注意,这个问题可能并不重要 - 如果您需要同步以确保正确性,您需要进行同步以确保正确性。我唯一能看到速度是一个问题的是,如果你正在考虑创建一个无锁实现(使用非常高效但复杂的java.util.concurrent.locks.AbstractQueuedSynchronizer),或者考虑使用另一种语言代替你的任务。

总的来说,我认为最好的结论是同步通常足够快,可以在第一次迭代时使用。与所有性能问题一样,首先要编写清晰度和正确性的代码,然后仅优化您测量的应用程序中昂贵的部分。通常,这不会是同步成本*。