同步块可以比Atomics更快吗?

时间:2012-07-18 23:41:12

标签: java concurrency java.util.concurrent

假设有两个计数器实现:

class Counter {
  private final AtomicInteger atomic = new AtomicInteger(0);
  private int i = 0;

  public void incrementAtomic() {
    atomic.incrementAndGet();
  }

  public synchronized void increment() {
    i++;
  }
}
乍一看,原子应该更快,更具可扩展性。我相信他们是。但它们是否比synchronized一直阻塞更快?或者这个规则被破坏时存在某些情况(例如SMP /单CPU机器,不同的CPU ISA,操作系统等)?

5 个答案:

答案 0 :(得分:5)

incrementAndGet可以作为CAS循环实现。在高度满足的情况下,可能导致 n -1的线程失败导致 n 线程的O( n )问题。< / p>

(对于@Geek:

通常getAndIncrement可以实现如下:

 int old;
 do {
     old = value;
 } while (!compareAndSet(value, old, old+1));
 return old;

想象一下,你有一个 n 线程在同一个原子上执行这个代码,它们碰巧彼此同步。第一次迭代 kn 工作。只有一个CAS会成功。其他 n -1个线程将重复练习,直到只剩下一个。所以总工作量是O( n ^ 2)(最差情况)而不是O( n )。 )

话虽如此,获得一个锁将需要做一些类似的事情,并且锁定在争用时并不是最好的。在使用需要在get和compareAndSwap之前进行大量计算的CAS循环之前,您不太可能看到很多优势。

答案 1 :(得分:3)

  

此规则被破坏时存在某些情况(例如SMP /单CPU机器,不同的CPU ISA,OS等)?

我不知道。 (我随时准备纠正......如果有人知道具体的反例。)

然而(这是我的主要观点)没有理论的原因,为什么你不能拥有硬件架构或实现不佳的JVM synchronized速度相同或者比atomic类型更快。 (这两种同步形式的相对速度是实现问题,因此只能对现有实现进行量化。)

当然,这并不意味着你永远不应该使用synchronizedsynchronized构造有许多原子类无法解决的用例。

答案 2 :(得分:2)

它依赖于实现 - 因此最终您需要对您的特定平台/ JVM /配置进行基准测试。

话虽如此,原子应该总是更快,原因如下:

  • Atomics的设计使JVM可以利用原子机器指令,这是大多数平台可以获得的最快的原子操作
  • synchronized使用与监视器对象相对较重的锁定方案,该方案旨在保护潜在的大块代码。这种形式的锁定本质上比原子操作更复杂,因此您可能期望它具有更高的运行时成本。

答案 3 :(得分:0)

正如其他人所说,这是依赖于实现的。但请记住,如果您的程序不变量涉及多个变量,那么必须使用同步来一起更新它们。您不能仅仅因为它们是Atomic类型而对两个相关变量进行原子操作。在这种情况下,你唯一的朋友是同步的。

答案 4 :(得分:-3)

原子变量总是会更快。

你可以看到java.util.concurrent包总是使用原子变量而不是同步块。