Java 中同步部分的性能
我对Java中块的性能有一个小争议。这是一个理论问题,不影响现实生活中的应用。synchronized
考虑使用锁和同步节的单线程应用程序。此代码是否比没有同步节的相同代码工作得慢?如果是,为什么?我们不讨论并发性,因为它只是单线程应用程序
更新
发现有趣的基准测试它。但它是从2001年开始的。在最新版本的JDK中,事情可能会发生巨大变化
我对Java中块的性能有一个小争议。这是一个理论问题,不影响现实生活中的应用。synchronized
考虑使用锁和同步节的单线程应用程序。此代码是否比没有同步节的相同代码工作得慢?如果是,为什么?我们不讨论并发性,因为它只是单线程应用程序
更新
发现有趣的基准测试它。但它是从2001年开始的。在最新版本的JDK中,事情可能会发生巨大变化
使用块时,单线程代码的运行速度仍然较慢。显然,在等待其他线程完成时,您不会让其他线程停止,但是您将不得不处理同步的其他影响,即缓存一致性。synchronized
同步块不仅用于并发,还用于可见性。每个同步块都是一个内存屏障:JVM可以自由地处理寄存器中的变量,而不是主内存,前提是多个线程不会访问该变量。如果没有同步块,这些数据可以存储在CPU的缓存中,不同CPU上的不同线程将看不到相同的数据。通过使用同步块,可以强制 JVM 将此数据写入主内存,以便其他线程可见。
因此,即使您没有锁争用,JVM 仍然需要在将数据刷新到主内存时进行内务处理。
此外,这还有优化约束。JVM可以自由地对指令进行重新排序以提供优化:考虑一个简单的示例:
foo++;
bar++;
对:
foo++;
synchronized(obj)
{
bar++;
}
在第一个示例中,编译器可以自由加载并同时递增它们,然后同时递增它们,然后同时保存它们。在第二个示例中,编译器必须执行加载/添加/保存 ,然后执行 加载/添加/保存 。因此,同步可能会影响 JRE 优化指令的能力。foo
bar
foo
bar
(关于Java内存模型的一本好书是Brian Goetz的Java Concurrency In Practice。
热点中有3种类型的锁定
缺省情况下,JVM 使用瘦锁定。以后如果JVM确定不存在争用,则将瘦锁定转换为有偏差锁定。更改锁类型的操作相当昂贵,因此JVM不会立即应用此优化。有特殊的JVM选项 - XX:BiasedLockingStartupDelay=delay,它告诉JVM何时应该应用这种优化。
一旦有偏差,该线程随后可以锁定和解锁对象,而无需诉诸昂贵的原子指令。
问题的答案:视情况而定。但是,如果存在偏差,则具有锁定和不锁定的单线程代码的平均性能相同。