是否有另一种使用CAS操作在Java中编写同步块的方法?

Ric*_*ley 2 java concurrency multithreading java.util.concurrent

我有两个同步块,将被两个并发线程大量访问.我想减少争用和上下文切换.有没有办法在一个AtomicBoolean?上使用CAS(CompareAndSet)操作来实现?

例如:

private final Object lock = new Object();

// Thread A executing this
public final void methodA() {
   synchronized(lock) {
       ...
   }
}

// Thread B executing this
public final void methodB() {
    synchronized(lock) {
       ...
    }
}
Run Code Online (Sandbox Code Playgroud)

我不想使用该java.util.concurrent.locks.Lock课程,因为我认为它不会有所作为.我想用CAS.

ass*_*ias 6

您可以通过以下方式替换synchronized块:

private final AtomicBoolean flag = new AtomicBoolean();

while (!flag.compareAndSet(false, true));
try {
  //your code here
} finally {
  flag.set(false);
}
Run Code Online (Sandbox Code Playgroud)

您应该在争用场景下测试它们,以确保它确实提高了性能.CAS在小到轻微的争用下效果最好.

正如@yshavit评论的那样,JIT可能已经为您执行了这种优化,因此再一次测试很重要.

  • @specalizt它被用作锁定,所以命名是有意义的IMO. (3认同)
  • +1,但我还要补充一点,如果无法获取锁,线程将进入忙等待循环,从而阻止线程调度程序在该核心上进行其他更高效的工作.如果锁几乎从不争用,这只是一个优势.我非常肯定(但不是100%肯定)HotSpot会找到那些点然后将它们变成"忙循环几个周期,然后停放线程并尝试获取互斥锁",在这种情况下,此代码是只是JIT可以做的更简单的版本. (2认同)
  • @RichardBradley我不这么认为,不."AtomicBoolean :: compareAndSet"的规范表示如果成功则返回"true".这意味着如果它因任何原因抛出异常,它就不会成功(因为抛出异常与返回`true`不兼容).在这种情况下,锁定从未被这个线程获取,并且没有必要取消它(事实上,你_should not_,因为这可能意味着你已经释放了一些其他线程获得的锁). (2认同)