如何在java.util.concurrent.atomic包中定义的类中实现原子性?
我正在浏览java.util.concurrent.AtomicInteger的源代码,以了解类提供的原子操作是如何实现原子性的。例如,AtomicInteger.getAndIncrement()方法源如下如何在java.util.concurrent.atomic包中定义的类中实现原子性?,java,concurrency,thread-safety,atomic,java.util.concurrent,Java,Concurrency,Thread Safety,Atomic,Java.util.concurrent,我正在浏览java.util.concurrent.AtomicInteger的源代码,以了解类提供的原子操作是如何实现原子性的。例如,AtomicInteger.getAndIncrement()方法源如下 public final int getAndIncrement() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(curren
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
我无法理解在无限for循环中编写操作序列的目的。它在Java内存模型(JMM)中是否有任何特殊用途。请帮我找到一个描述性的理解。提前谢谢
我无法理解在无限for循环中编写操作序列的目的
此代码的目的是确保volatile
字段得到适当更新,而不会产生同步
锁的开销。除非有大量线程竞相更新同一个字段,否则很可能需要旋转几次才能完成此操作
volatile
关键字提供可见性和内存同步保证,但其本身并不能确保原子操作具有多个操作(测试和设置)。如果您正在测试并设置一个volatile
字段,那么如果多个线程试图同时执行相同的操作,则会出现争用条件。在这种情况下,如果多个线程试图同时递增AtomicInteger
,您可能会错过其中一个递增。这里的并发代码使用自旋循环和compareAndSet
底层方法来确保volatile int
仅在仍然等于3时更新为4(例如)
volatile
的语言定义来实现其目的。JMM定义了该语言如何处理synchronized
、volatile
和其他关键字,以及多个线程如何与缓存和中央内存交互。这主要是关于本机代码与操作系统和硬件的交互,很少涉及Java代码
它是compareAndSet(…)
方法,通过调用Unsafe
类,该类主要是带有一些包装的本机方法,从而更接近JMM:
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
我无法理解写这篇文章的目的
无限for循环中的操作
为了理解它为什么处于无限循环中,我发现了解比较数据集的作用以及它如何返回false很有帮助
因此,您阅读了返回的消息,并询问这是怎么可能的
如果两个线程几乎同时调用incrementAndGet
,并且它们都输入并查看值current==1
。两个线程都将创建一个本地线程next==2
,并尝试通过compareAndSet
进行设置。根据记录,只有一个线程将获胜,失败的线程必须重试
这就是CAS的工作原理。如果失败,尝试更改该值,请重试,如果成功,请继续
现在简单地将字段声明为volatile将不起作用,因为递增不是原子的。因此,从我解释的场景来看,这样的情况是不安全的
volatile int count = 0;
public int incrementAndGet(){
return ++count; //may return the same number more than once.
}
Java的compareAndSet基于CPU比较和交换(CAS)指令,请参阅。它将内存位置的内容与给定值进行比较,并且仅当它们相同时,才会将该内存位置的内容修改为给定的新值
在incrementAndGet的情况下,我们读取当前值并调用compareAndSet(current,current+1)
。如果返回false,则表示另一个线程干扰并更改了当前值,这意味着我们的尝试失败,我们需要重复整个循环,直到成功。您似乎忽略了在该循环中调用的方法,该方法的结果是中断循环的条件。谷歌“比较和交换”这是一个典型的goto
使用案例。在goto
less语言中,我们使用无限循环。根据我对Volatile的理解:它在不使用同步或任何显式锁定的情况下解决了可见性问题。因此,volatile可以在没有同步的情况下使用,以实现读/写的一致可见性。那么,为什么要使用这个特殊的for循环进行同步呢?如果您能更多地解释循环和同步之间的关系,这将是一个很大的帮助。感谢您的即时回复。@VaibhavRaj-循环与同步无关。它循环直到CAS操作成功。volatile
是关于可见性的AtomicInteger
是关于无锁原子性的。如果不重试,就无法实现这一点。无限循环=重试。volatile
解决了可见性问题,无需使用synchronized
关键字,但确保内存同步是其工作的一部分。它没有做的是给你一个布尔值的原子访问权。“递增不是原子的”——因为它本质上是两个操作,读和写,在这些操作之间仍然可能发生竞争条件。除非你让它原子化(字面意思=不可分离)
volatile int count = 0;
public int incrementAndGet(){
return ++count; //may return the same number more than once.
}