这种AtomicBoolean的使用是同步块的有效替代吗?

时间:2014-07-30 14:04:03

标签: java locking atomic synchronized atomicboolean

考虑两个方法a()和b()不能同时执行。 同步关键字可用于实现此目的,如下所示。我可以根据下面的代码使用AtomicBoolean实现相同的效果吗?

final class SynchonizedAB {

synchronized void a(){
   // code to execute
}

synchronized void b(){
  // code to execute
}

}

尝试使用AtomicBoolean实现与上述相同的效果:

final class AtomicAB {

private AtomicBoolean atomicBoolean = new AtomicBoolean();

void a(){
   while(!atomicBoolean.compareAndSet(false,true){

  }
  // code to execute
  atomicBoolean.set(false);
}

void b(){
    while(!atomicBoolean.compareAndSet(false,true){

   }
     // code to execute
     atomicBoolean.set(false);
    }

 }

3 个答案:

答案 0 :(得分:3)

不,因为synchronized会阻止,而AtomicBoolean你会忙着等待。

两者都将确保一次只有一个线程可以执行块,但是你想让你的CPU在while块上旋转吗?

答案 1 :(得分:1)

这取决于您计划使用原始同步版本的代码实现的目标。如果在原始代码中添加了synchronized,只是为了确保a或b方法中一次只存在一个线程,那么对我来说,两个版本的代码看起来都相似。

然而,Kayaman提到的差异很小。此外,为了添加更多差异,使用同步块,您将获得内存障碍,您将错过Atomic CAS循环。但是如果方法的主体不需要这样的障碍,那么这种差异也会被消除。

Atomic cas loop是否比同步块更好地执行,只有性能测试可以判断,但这是在并发包中多个位置遵循的相同技术,以避免块级同步。

答案 2 :(得分:1)

从行为的角度来看,这似乎是Java内置同步(监视器锁)的部分替代品。特别是,它似乎提供了正确的互斥,这是大多数人在使用锁时所追求的。

它似乎也提供了正确的内存可见性语义。 Atomic*类的类具有与volatile类似的内存语义,因此释放其中一个"锁定"将提供一个事先发生的关系到另一个线程的"锁定"这将提供您想要的可见性保证。

这与Java的synchronized块不同之处在于它在异常的情况下不提供自动解锁。要获得与这些锁类似的语义,您必须在try-finally语句中包含锁定和用法:

void a() {
    while (!atomicBoolean.compareAndSet(false, true) { }
    try {
        // code to execute
    } finally {
        atomicBoolean.set(false);
    }
}

(和b类似)

这个构造似乎为Java的内置监视器锁提供了类似的行为,但总的来说,我觉得这种努力是错误的。根据您对another answer的评论,您似乎对避免阻塞线程的操作系统开销感兴趣。发生这种情况肯定会产生开销。但是,Java的内置锁已经过大量优化,在短期争用的情况下提供了非常便宜的无竞争锁定,偏置锁定和自适应自旋循环。在许多情况下,最后一次尝试避免操作系统级阻塞。通过实现自己的锁,您可以放弃这些优化。

当然,你应该做基准测试。如果您的性能受到操作系统级阻塞开销的影响,那么您的锁可能太粗糙了。减少锁定或拆分锁定量可能是减少争用开销的一种更有成效的方法,而不是尝试实现自己的锁定。