是否有其他方法可以使用CAS操作在Java中编写同步块?

是否有其他方法可以使用CAS操作在Java中编写同步块?,java,multithreading,concurrency,java.util.concurrent,Java,Multithreading,Concurrency,Java.util.concurrent,我有两个同步块,两个并发线程将大量访问它们。我希望减少争用和上下文切换。有没有一种方法可以在AtomicBoolean上使用CAS(CompareAndSet)操作来实现这一点 例: 我不想使用java.util.concurrent.locks.Lock类,因为我认为它没有什么区别。我想使用CAS。您可以通过以下方式替换同步块: private final AtomicBoolean flag = new AtomicBoolean(); while (!flag.compareAndSet

我有两个同步块,两个并发线程将大量访问它们。我希望减少争用和上下文切换。有没有一种方法可以在
AtomicBoolean
上使用CAS(CompareAndSet)操作来实现这一点

例:


我不想使用
java.util.concurrent.locks.Lock
类,因为我认为它没有什么区别。我想使用CAS。

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

private final AtomicBoolean flag = new AtomicBoolean();

while (!flag.compareAndSet(false, true));
try {
  //your code here
} finally {
  flag.set(false);
}
您应该在争用场景下测试这两者,以确保它确实提高了性能。CAS在小到轻微的争用下工作得最好


正如@yshavit所评论的,因此再次测试非常重要。

根据实际情况,使用CAS的自旋锁可能会提高性能,也可能不会提高性能。如果块中的代码有点长且耗时,那么synchronized仍然是您最安全的选择


您是否可以尝试使数据不可变,以便不同的线程使用不同的数据副本,而不需要锁定?

您是否确定(例如,通过分析)这是实际的瓶颈,或者您只是猜测?我个人对此相当怀疑“我想用这个非常具体的解决方案来解决这个含糊不清的未明确说明的问题;这行得通吗?“这是一类问题,但也许其他人可以提供帮助(或者你可以提供有关函数实际功能的更多细节)。让我引用Brian Goetz在同一主题的另一个SE问题(CAS vs Locks):“操作的相对速度基本上不是问题。相关的是基于锁和非阻塞算法之间的可伸缩性差异。如果你运行的是1核或2核系统,不要再考虑这些事情。非阻塞算法通常具有更好的扩展性,因为它们的“关键部分”比基于锁的算法更短。“是什么让你认为这是瓶颈?如果你是通过采样模式下的分析(而不是检测)得到的,您应该知道几乎所有的采样器都强烈偏向于同步点。请参阅。您应该(a)验证锁是否真的没有竞争(例如,通过使用
j.u.c.lock
使用
tryLock
重新播放,然后(b)添加诸如
System.nanoTime
之类的工具,以确认它确实像您所想的那样慢。您当然不能减少争用,因为争用是由等式的需求端定义的。此外,您不知道运行时将使用什么技术来获取原子监视器,但您可以放心地打赌它将是一个非常优化的方法。像这样试图智胜JVM可能是一种学习体验;否则这是徒劳的。有没有确凿的证据表明这比
同步的
块快(或在某些条件下快)?lock只是原子布尔变量的一个名称,chill:)@具体来说,它被用作锁,因此命名在+1中是有意义的,但我还要补充一点,如果无法获得锁,线程将进入一个繁忙的等待循环,从而阻止线程调度程序在该内核上进行其他更高效的工作。如果锁几乎从未被争用,这只是一个优势。我非常确定(但不是100%确定)HotSpot无论如何都会找到这些点,并将它们变成一个“繁忙循环”几个周期,然后停止线程并尝试获取互斥锁,“在这种情况下,这段代码只是JIT可以做的事情的一个简单版本。@RichardBradley我不这么认为,不。
AtomicBoolean::compareAndSet
的规范说,如果成功,它将返回
true
。这意味着如果它出于任何原因抛出异常,它不可能成功(因为抛出异常与返回
true
)不兼容。在这种情况下,该线程从未获取过锁,并且没有必要取消设置它(事实上,您不应该这样做,因为这可能意味着您已经释放了某个其他线程获取的锁)。
private final AtomicBoolean flag = new AtomicBoolean();

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