为什么在java中synchronized很昂贵?

13z8s7eq  于 2021-06-30  发布在  Java
关注(0)|答案(5)|浏览(412)

我对java真的很陌生,我读过 synchronized 在java中是“非常昂贵的”。我只想知道什么东西贵,怎么贵?
谢谢。

41ik7eoe

41ik7eoe1#

这是非常昂贵的,因为如果您使用的是线程,并且许多线程必须经过同步的代码段,那么一次只能执行其中一个线程。
它就像一个瓶颈。
当你使用一个线程时,它甚至是昂贵的,因为它必须检查是否允许他运行。
如果减少同步段的使用,线程就不必停下来查看它们是否可以运行(当然,它们不必共享数据)
同步工作原理的高级概述可以在这里找到
http://img20.imageshack.us/img20/2066/monitor28synchronizatioc.png
java风格的监视器

ogsagwnx

ogsagwnx2#

这并不是java特有的。在任何多线程环境中,如果没有正确地执行同步,同步都可能被认为是“昂贵的”。我不知道java是否特别糟糕。
如果线程使用相同的资源,它会阻止线程并发运行。但是,由于它们使用相同的资源,没有更好的选择(必须这样做)。
问题是人们经常保护范围太大的资源。例如,设计糟糕的程序可能会同步整个对象数组,而不是数组中的每个元素(甚至是数组的一部分)。
这意味着试图读取元素7的线程必须等待读取或写入元素22的线程。没必要。如果同步的粒度是在元素级别而不是数组级别,那么这两个线程就不会相互干扰。
只有当两个线程试图访问同一个元素时,才会出现资源争用。这就是为什么一般规则是只保护尽可能小的资源(当然,受同步数量的限制)。
但是,老实说,如果另一种选择是由于两个线程争夺单个资源而导致的数据损坏,那么代价有多高并不重要。正确编写应用程序,并且只在出现性能问题时才担心性能问题(“先让它工作,然后让它快速工作”是我最喜欢的咒语)。

rfbsl7qr

rfbsl7qr3#

也许没你想的那么糟
它曾经是可怕的(这可能就是为什么你读到它是“非常昂贵”)。这些模因需要很长时间才能消失

同步有多贵?

由于涉及缓存刷新和失效的规则,java语言中的同步块通常比许多平台提供的关键部分工具(通常用原子“测试和设置位”机器指令实现)更昂贵。即使程序只包含在单个处理器上运行的单个线程,同步的方法调用仍然比不同步的方法调用慢。如果同步实际上需要争用锁,那么性能损失会大得多,因为需要几个线程切换和系统调用。
幸运的是,jvm的持续改进既提高了java程序的整体性能,又降低了与每个版本同步的相对成本,未来的改进是可以预期的。此外,同步的性能代价往往被夸大了。一位著名的消息人士曾指出,一个同步的方法调用比一个不同步的方法调用慢50倍之多。虽然这句话可能是真的,但它也相当具有误导性,导致许多开发人员即使在需要同步的情况下也避免同步。
尽管如此,并发编程仍然可能很慢,但现在并不是java的错。在精细锁定和粗糙锁定之间有一个权衡。太粗糙显然是不好的,但也有可能太精细,因为锁的成本不是零。
重要的是要考虑竞争中的特定资源。机械硬盘就是这样一个例子:线程越多,性能就会越差。

dgsult0t

dgsult0t4#

其他的答案给出了一个很好的技术细节,我不会试图复制。
我要做的是建议你检查文章的日期(以及作者隐含的能力和意识)。java中的同步在早期的jvm中非常慢。但是,最近它有了很大的改进,因此无竞争的同步比您想象的要快得多,而且无竞争的同步也得到了改进。
请注意,这个问题可能无关紧要—如果需要同步以确保正确性,则需要同步以确保正确性。我唯一能看到速度是个问题的时候是,如果您正在考虑创建一个无锁实现(使用非常高效但复杂的java.util.concurrent.locks.abstractqueuedsynchronizer),或者考虑使用另一种语言来代替您的任务。
总的来说,我认为最好的结论是同步通常足够快,可以在第一次迭代中使用。与所有性能问题一样,代码首先是为了清晰性和正确性,然后只优化您所度量的应用程序中昂贵的部分。通常,这不会是同步的成本*。

20jt8wwn

20jt8wwn5#

ibm的这篇文章实际上很好地总结了同步背后的要点。
由于涉及缓存刷新和失效的规则,java语言中的同步块通常比许多平台提供的关键部分工具(通常用原子“测试和设置位”机器指令实现)更昂贵。即使程序只包含在单个处理器上运行的单个线程,同步的方法调用仍然比不同步的方法调用慢。如果同步实际上需要争用锁,那么性能损失会大得多,因为需要几个线程切换和系统调用。

相关问题