【问题标题】:synchronized vs ReentrantLock vs AtomicInteger execution timesynchronized vs ReentrantLock vs AtomicInteger 执行时间
【发布时间】:2014-02-01 20:47:07
【问题描述】:

我可以看到 ReentrantLocksynchronized 快 50% 左右,AtomicInteger 快​​ 100%。为什么这三种同步方法的执行时间会有如此大的差异:synchronized 块、ReentrantLockAtomicInteger(或 Atomic 包中的任何类)。

除了这些之外,还有其他流行和扩展的同步方法吗?

【问题讨论】:

  • 您究竟是如何获得这些性能数据的?由于 JIT 和 GC,Java 中的微基准测试非常棘手。您很容易得到误导性结果。
  • 我认为你的意思是 java.util.concurrent
  • 我只是使用System.nanoTime(),这不是一个详尽的测试,我给出的百分比只是指示性的。
  • 除了这些之外,还有其他流行和扩展的同步方法吗? - 是的 - 在 Java 8 中有 StampedLock

标签: java multithreading concurrency synchronization mutex


【解决方案1】:

AtomicInteger 在您的硬件上比其他两种同步方法快得多,因为它是无锁的。在 CPU 为无锁并发提供基本设施的架构上,AtomicInteger 的操作完全在硬件中执行,关键通常采用单个 CPU 指令。相比之下,ReentrantLocksynchronized 使用多条指令来执行它们的任务,因此您会看到与它们相关的一些相当大的开销。

【讨论】:

  • 无锁是什么意思?
  • @dabadaba 表示对AtomicInteger的操作不会无限期阻塞其他线程,让你的线程作为一个组总是有一些进展。
  • 所以或多或少意味着它不能与其他线程一起工作,而是在另一个层面,在硬件层面?
  • @dabadaba 好吧,锁最终也会在硬件级别进行处理。不同之处在于两者如何使用硬件来实现其结果。比如说,AtomicIntegerincrementAndGet 发出一条 CPU 指令,用增加的值替换旧值,并取回旧值。然后它检查旧值与它期望看到的值。通常,此检查会立即成功。如果不成功,代码会循环返回,并尝试再次执行相同的操作,直到成功。这里不涉及等待或交还控制 - 您的线程认为它是单独存在的。
【解决方案2】:

许多因素会影响这一点。

  • Java 的版本。 Java 5.0 的 ReentrantLock 速度要快得多,Java 7 没那么快
  • 争用级别。在竞争率较低的情况下,同步的效果最好(通常锁定也是如此)。 ReentrantLock 在争用率较高的情况下效果更好。 YMWV
  • JIT 可以做多少优化。 JIT 优化以 ReentrantLOck 不同步的方式同步。如果这不可能,您将看不到优势。
  • synchronized 在其操作中是免费的。 ReentrantLock 会产生垃圾,使其变慢并根据使用方式触发 GC。

AtomicInteger 使用与锁定相同的原语,但会忙于等待。 CompareAndSet 也称为 CompareAndSwap,即它的作用要简单得多(而且也更有限)

ConcurrentXxxx、CopyOnWriteArrayXxxx 集合非常流行。这些提供并发而不需要直接使用锁(在某些情况下根本不需要锁)

【讨论】:

  • 争用是什么意思?您的回答符合 ReentrantLock 比同步慢,我在结果中看到了相反的情况,请再次查看我的帖子。或者我误解了你的回答。
  • @dabadaba 是的,有时 ReentrantLock 更快,有时更慢。这完全取决于我上面列出的因素。甚至您的 CPU 架构也可以有所作为。我已经看到了在不同型号的 CPU 上运行相同 JVM 的相同代码(在 PC 上和另一台笔记本电脑上)的示例,在哪个更快时得到明显不同的结果。
  • @dabadaba 争用意味着有多少 CPU 试图同时使用相同的资源。每个资源只使用一个线程来尝试您的测试。
  • 我对多线程的性能感兴趣,而不是单线程;但是谢谢,我一定会检查一下并查看结果。但一般来说,考虑到多线程(嗯,我的意思是,每个处理器核心一个线程 => 高争用率?),ReentrantLock 会更快吗?
  • 你完全没有抓住重点。想想你的系统中有多少可锁定的对象。想想你有多少个 CPU。这意味着一般来说,您有一些很热的锁,但大多数都很冷,甚至是纯单线程的。
【解决方案3】:

我认为您在评估这 3 个元素进行比较时犯了一个常见错误。

基本上,与同步密钥相比,当您同步块时,ReentrantLock 可以让您更加灵活。 Atomic 是采用基于 CAS(比较和交换)的不同方法来管理并发上下文中的更新的东西。

我建议你深入阅读 Java 平台的并发圣经。

Java Concurrency in Practice - Brian Göetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes & Doug Lea

对并发有深入的了解,知道一门语言可以为您提供什么来解决并发问题和利用多线程,这两者之间有很大的不同。

在性能方面,取决于当前的场景。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-15
    • 1970-01-01
    • 2012-09-05
    • 1970-01-01
    • 2015-03-25
    • 1970-01-01
    相关资源
    最近更新 更多