Java 中同步部分的性能

我对Java中块的性能有一个小争议。这是一个理论问题,不影响现实生活中的应用。synchronized

考虑使用锁和同步节的单线程应用程序。此代码是否比没有同步节的相同代码工作得慢?如果是,为什么?我们不讨论并发性,因为它只是单线程应用程序

更新

发现有趣的基准测试它。但它是从2001年开始的。在最新版本的JDK中,事情可能会发生巨大变化


答案 1

使用块时,单线程代码的运行速度仍然较慢。显然,在等待其他线程完成时,您不会让其他线程停止,但是您将不得不处理同步的其他影响,即缓存一致性。synchronized

同步块不仅用于并发,还用于可见性。每个同步块都是一个内存屏障:JVM可以自由地处理寄存器中的变量,而不是主内存,前提是多个线程不会访问该变量。如果没有同步块,这些数据可以存储在CPU的缓存中,不同CPU上的不同线程将看不到相同的数据。通过使用同步块,可以强制 JVM 将此数据写入主内存,以便其他线程可见。

因此,即使您没有锁争用,JVM 仍然需要在将数据刷新到主内存时进行内务处理。

此外,这还有优化约束。JVM可以自由地对指令进行重新排序以提供优化:考虑一个简单的示例:

foo++;
bar++;

对:

foo++;
synchronized(obj)
{
    bar++;
}

在第一个示例中,编译器可以自由加载并同时递增它们,然后同时递增它们,然后同时保存它们。在第二个示例中,编译器必须执行加载/添加/保存 ,然后执行 加载/添加/保存 。因此,同步可能会影响 JRE 优化指令的能力。foobarfoobar

(关于Java内存模型的一本好书是Brian Goetz的Java Concurrency In Practice


答案 2

热点中有3种类型的锁定

  1. 子:JVM依靠操作系统互斥锁来获取锁。
  2. 精简:JVM 使用 CAS 算法。
  3. 有偏见:CAS在某些架构上的操作相当昂贵。有偏差锁定 - 是针对只有一个线程处理对象的情况而优化的特殊锁定类型。

缺省情况下,JVM 使用锁定。以后如果JVM确定不存在争用,则将瘦锁定转换为有偏差锁定。更改锁类型的操作相当昂贵,因此JVM不会立即应用此优化。有特殊的JVM选项 - XX:BiasedLockingStartupDelay=delay,它告诉JVM何时应该应用这种优化。

一旦有偏差,该线程随后可以锁定和解锁对象,而无需诉诸昂贵的原子指令。

问题的答案:视情况而定。但是,如果存在偏差,则具有锁定和不锁定的单线程代码的平均性能相同。


推荐