Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/367.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在java.util.concurrent.atomic包中定义的类中实现原子性?_Java_Concurrency_Thread Safety_Atomic_Java.util.concurrent - Fatal编程技术网

如何在java.util.concurrent.atomic包中定义的类中实现原子性?

如何在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

我正在浏览java.util.concurrent.AtomicInteger的源代码,以了解类提供的原子操作是如何实现原子性的。例如,AtomicInteger.getAndIncrement()方法源如下

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(例如)

  • t1获取原子int,它是0
  • t2获取原子int,它是0
  • t1加1
  • t1以原子方式进行测试,以确保其为0、为,并存储1
  • t2加1
  • t2原子测试以确保它是0,不是,所以它必须旋转并重试
  • t2得到原子int,它是1
  • t2加1
  • t2进行原子测试,以确保它是1,是,并存储2
  • 它在Java内存模型(JMM)中是否有任何特殊用途

    不,它服务于类和方法定义的目的,并使用JMM和围绕
    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.
    }