为什么 Java 中的同步开销很大?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1671089/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why are synchronize expensive in Java?
提问by unj2
I am really new to Java and I read that synchronized
is "very expensive" in Java. All I want to know is what is expensive and how is it expensive?
我对 Java 真的很陌生,我读到 Java 中synchronized
的“非常昂贵”。我只想知道什么是贵的,它是怎么贵的?
Thanks.
谢谢。
采纳答案by John La Rooy
Maybe it's not as bad as you think
It used to be terrible (which is possibly why you read that it was "very expensive"). These memes can take a long time to die out
它曾经很糟糕(这可能就是你读到它“非常昂贵”的原因)。这些模因可能需要很长时间才能消失
How expensive is synchronization?
Because of the rules involving cache flushing and invalidation, a synchronized block in the Java language is generally more expensive than the critical section facilities offered by many platforms, which are usually implemented with an atomic "test and set bit" machine instruction. Even when a program contains only a single thread running on a single processor, a synchronized method call is still slower than an un-synchronized method call. If the synchronization actually requires contending for the lock, the performance penalty is substantially greater, as there will be several thread switches and system calls required.
Fortunately, continuous improvements in the JVM have both improved overall Java program performance and reduced the relative cost of synchronization with each release, and future improvements are anticipated. Further, the performance costs of synchronization are often overstated. One well-known source has cited that a synchronized method call is as much as 50 times slower than an un-synchronized method call. While this statement may be true, it is also quite misleading and has led many developers to avoid synchronizing even in cases where it is needed.
同步有多贵?
由于涉及缓存刷新和失效的规则,Java 语言中的同步块通常比许多平台提供的临界区设施更昂贵,后者通常使用原子“测试和设置位”机器指令实现。即使程序只包含在单个处理器上运行的单个线程,同步方法调用仍然比非同步方法调用慢。如果同步实际上需要争用锁,则性能损失要大得多,因为将需要多个线程切换和系统调用。
幸运的是,JVM 的持续改进既提高了 Java 程序的整体性能,又降低了与每个版本同步的相对成本,预计未来会有所改进。此外,同步的性能成本通常被夸大了。一位知名人士引用了同步方法调用比非同步方法调用慢 50 倍之多。虽然这种说法可能是正确的,但它也具有很大的误导性,并导致许多开发人员即使在需要同步的情况下也避免同步。
Having said that - concurrent programming can still be slow, but not so much of it is purely Java's fault now. There is a trade-off between fine and coarse locking. Too coarse is obviously bad, but it's possible to be too fine too, as locks have a non zero cost.
话虽如此 - 并发编程仍然可能很慢,但现在已经不是 Java 的错了。细锁和粗锁之间存在权衡。太粗显然不好,但也可能太细,因为锁的成本非零。
It's important to consider the particular resource under contention. Mechanical hard disks are an example where more threads can lead to worseperformance.
考虑争用的特定资源很重要。机械硬盘就是一个例子,线程越多,性能越差。
回答by OscarRyz
It is expensive because if you are using threads, and a number of threads have to go through a synchronized section of code, only one of them may be executed at a time.
这是昂贵的,因为如果您使用线程,并且许多线程必须经过同步的代码段,则一次只能执行其中一个。
It is like a bottleneck.
这就像一个瓶颈。
It is even expensive when you use a single thread, because it has to check anyway if he is allowed to run.
当您使用单线程时,它甚至会很昂贵,因为无论如何它都必须检查是否允许他运行。
If you reduce the use of synchronized segments your thread won't have to stop to see if they can run ( of course, they don't have to share data )
如果您减少同步段的使用,您的线程就不必停下来查看它们是否可以运行(当然,它们不必共享数据)
A high level overview of how synchronization works may be found here
可以在此处找到同步工作原理的高级概述
http://img20.imageshack.us/img20/2066/monitor28synchronizatioc.png
http://img20.imageshack.us/img20/2066/monitor28synchronizatioc.png
A Java style monitor
一个 Java 风格的监视器
回答by Vincent Ramdhanie
This articleover at IBM actually summarizes very nicely the main points behind synchronization.
IBM 上的这篇文章实际上很好地总结了同步背后的要点。
Because of the rules involving cache flushing and invalidation, a synchronized block in the Java language is generally more expensive than the critical section facilities offered by many platforms, which are usually implemented with an atomic "test and set bit" machine instruction. Even when a program contains only a single thread running on a single processor, a synchronized method call is still slower than an unsynchronized method call. If the synchronization actually requires contending for the lock, the performance penalty is substantially greater, as there will be several thread switches and system calls required.
由于涉及缓存刷新和失效的规则,Java 语言中的同步块通常比许多平台提供的临界区设施更昂贵,后者通常使用原子“测试和设置位”机器指令实现。即使程序只包含在单个处理器上运行的单个线程,同步方法调用仍然比非同步方法调用慢。如果同步实际上需要争用锁,则性能损失要大得多,因为将需要多个线程切换和系统调用。
回答by paxdiablo
This isn't that specific to Java. Synchronization can be considered "expensive" in any multi-threaded environment if not done correctly. Whether it's particularly bad in Java, I do not know.
这不是 Java 特有的。如果没有正确完成,在任何多线程环境中同步都可以被认为是“昂贵的”。是不是在Java中特别糟糕,我不知道。
It prevents threads from running concurrently if they use the same resource. But, since they douse the same resource, there's no better option (it has to be done).
如果线程使用相同的资源,它会阻止线程并发运行。但是,由于它们确实使用相同的资源,因此没有更好的选择(必须这样做)。
The problem is that people often protect a resource with too big a scope. For example, a badly designed program may synchronize an entire array of objects rather than each individual element in the array (or even a section of the array).
问题是人们经常保护范围太大的资源。例如,一个设计糟糕的程序可能会同步整个对象数组,而不是数组中的每个单独元素(甚至是数组的一部分)。
This would mean that a thread trying to read element 7 must wait for a thread reading or writing element 22. Not necessary. If the granularity of the synchronization were at the element level instead of the array level, those two threads wouldn't interfere with each other.
这意味着尝试读取元素 7 的线程必须等待读取或写入元素 22 的线程。没有必要。如果同步的粒度在元素级别而不是数组级别,那么这两个线程不会相互干扰。
Only when two threads tried to access the sameelement would there be resource contention. That's why the general rule is to only protect as small a resource as possible (subject to limitations on number of synchronizations, of course).
只有当两个线程试图访问同一个元素时,才会出现资源争用。这就是为什么一般规则是只保护尽可能小的资源(当然,受同步数量的限制)。
But, to be honest, it doesn't matter how expensive it is if the alternative is data corruption due to two threads fighting over a single resource. Write your application correctly and only worry about performance problems if and when they appear ("Get it working first thenget it working fast" is a favorite mantra of mine).
但是,老实说,如果替代方案是由于两个线程争夺单个资源而导致数据损坏,那么它的成本有多高并不重要。正确编写您的应用程序,只担心性能问题出现时出现(“先让它工作,然后让它快速工作”是我最喜欢的口头禅)。
回答by Andrzej Doyle
The other answers give a good level of technical detail that I'm not going to attempt to replicate.
其他答案提供了很好的技术细节,我不会尝试复制。
What I will do is advise you to check the dates of the articles (as well as the implied competence and awareness of the author). Synchronization in Java wasvery slow in earlier JVMs. However, it's improved a lot recently, such that uncontended synchronization is a lot faster than you might think, and uncontended synchronization has improved too.
我要做的是建议您检查文章的日期(以及作者的隐含能力和意识)。在早期的 JVM 中,Java中的同步非常慢。但是,它最近改进了很多,因此无竞争同步比您想象的要快得多,而且无竞争同步也得到了改进。
Mind you, this question possibly doesn't matter - if you need to synchronize to ensure correctness, you needto synchronize to ensure correctness. The only times I can see the speed being an issue is if you were considering creating a lockless implementation instead (using the very efficient yet complex java.util.concurrent.locks.AbstractQueuedSynchronizer), or perhaps considering using another language for your task instead.
请注意,这个问题可能无关紧要 - 如果您需要同步以确保正确性,则需要同步以确保正确性。我认为速度是一个问题的唯一时间是,如果您正在考虑创建一个无锁实现(使用非常有效但复杂的java.util.concurrent.locks.AbstractQueuedSynchronizer),或者可能考虑使用另一种语言来代替您的任务。
In general I think the best conclusion is that synchronization is generally fast enough to use on a first iteration. As with all performance concerns, code for clarity and correctness at first and then only optimise what you measure to be an expensive part of your application. Typically, this won't be the cost of synchronization*.
总的来说,我认为最好的结论是同步通常足够快,可以在第一次迭代中使用。与所有性能问题一样,首先编写代码以确保清晰和正确,然后仅优化您衡量的应用程序中昂贵的部分。通常,这不会是同步的成本*。