同步速度与正常速度
我有一个为单线程编写的类,没有同步方法。
class MyClass implements MyInterface{
//interface implementation methods, not synchronized
}
但我们还需要该类的同步版本。因此,我们创建了一个包装类,它实现相同的接口,但有一个采用 MyClass 实例的构造函数。对同步类方法的任何调用都会委托给 MyClass 的实例。这是我的同步类。
class SynchronizedMyClass implements MyInterface{
//the constructor
public SynchronizedMyClass(MyInterface i/*this is actually an instance of MyClass*/)
//interface implementation methods; all synchronized; all delegated to the MyInterface instance
}
毕竟,我对这两个类进行了大量的测试运行。测试涉及读取日志文件并计算每行中的 URL。问题在于类的同步版本始终花费更少的时间进行解析。我只使用一个线程进行测试,因此不会出现死锁、条件竞争等情况。每个日志文件包含超过 500 万行,这意味着调用方法超过 500 万次。谁能解释为什么该类的同步版本可能比正常版本花费更少的时间?
I have a class which is written for a single thread with no methods being synchronized.
class MyClass implements MyInterface{
//interface implementation methods, not synchronized
}
But we also needed a synchronized version of the class. So we made a wrapper class that implements the same interface but has a constructor that takes an instance of MyClass. Any call to the methods of the synchronized class are delegated to the instance of MyClass. Here is my synchronized class..
class SynchronizedMyClass implements MyInterface{
//the constructor
public SynchronizedMyClass(MyInterface i/*this is actually an instance of MyClass*/)
//interface implementation methods; all synchronized; all delegated to the MyInterface instance
}
After all this I ran numerous amounts of test runs with both the classes. The tests involve reading log files and counting URLs in each line. The problem is that the synchronized version of the class is consistently taking less time for the parsing. I am using only one thread for the teste, so there is no chance of deadlocks, race around condition etc etc. Each log file contains more than 5 million lines which means calling the methods more than 5 million times. Can anyone explain why synchronized versiuon of the class migt be taking less time than the normal one?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,您应该阅读有关在 Java 中制定基准的信息:How do我用 Java 编写了正确的微基准测试?
假设基准测试良好,那么以下是一些可能的原因:
锁省略:如果 JVM 发现该方法只能从一个线程调用,它可能会优化同步。
锁粗化:JVM 可能会组合多个将同步块合并为一个块,从而提高性能。也许 JVM 能够更好地优化该方法的同步版本。
Java 中的非竞争同步块速度很快,因此可能很难注意到差异(尽管无论如何应该有一些开销),并且性能差异的原因可能是由其他原因引起的。当存在争用时(即许多线程尝试同时访问它),同步块会变慢,在这种情况下,java.util.concurrent.locks 和其他同步机制可能会更快。
原因也可能是其他原因。也许 JVM 以不同的方式优化这些方法。要了解到底发生了什么,请查看 JIT 生成的本机代码: 如何查看 JVM 中 JIT 编译的代码?
First you should read about making benchmarks in Java: How do I write a correct micro-benchmark in Java?
Assuming that the benchmark is good, then here are some possible reasons:
Lock elision: If the JVM can notice that the method can only be called from one thread, it may optimize away the synchronization.
Lock coarsening: The JVM may combine multiple synchronized blocks into one block, which improves performance. Maybe the JVM is able to optimize your synchronized version of the method a bit better.
Non-contending synchronized blocks in Java are fast, so it might be hard to notice the difference (although there should anyways be some overhead) and the reason for performance difference could be caused by something else . Synchronized blocks become slow when there is contention (i.e. many threads try to access it at the same time), in which case java.util.concurrent.locks and other synchonization mechanisms might be faster.
The reason could also be something else. Maybe the JVM optimizes the methods differently. To see what is really happening, have a look at what native code the JIT generates: How to see JIT-compiled code in JVM?
正如已经指出的,微基准测试对于 Java 来说并不是那么简单。
IMO 没有理由担心同步本身的开销,即使在这种情况下,我也会将优化保存到您发现实际上存在瓶颈的时候。
同步的有趣部分是您的代码如何在多线程环境中工作。我肯定会专注于确保同步在正确的地方正确使用。
坦率地说,需要同一个类的完全同步和非同步版本听起来有点奇怪。
As already pointed out, micro-benchmarking is not that trivial with Java.
IMO There's no reason to be worried about the overhead of synchronization itself and even in that case I would save the optimizations to the time when you find out you actually have a bottleneck.
The interesting part of synchronization is how your code works in a multithreaded environment. I'd definitely focus on making sure the synchronization is used correctly in the right places.
Frankly it sounds a bit odd to need both fully synchronized and unsynchronized versions of the same class.