CAS-Problem mit AtomicInteger – Stapelüberlauf
我想大声告诉你
我想大声告诉你 2017-06-28 09:24:31
0
1
793
 public final int incrementAndGet() {
        for (;;) {
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))
                return next;
        }
    }

Dies ist eine automatische Inkrementierungsoperation, Definition: CAS hat 3 Operanden, den Speicherwert V, den alten erwarteten Wert A und den neuen zu ändernden Wert B. Nur wenn der erwartete Wert A und der Speicherwert V gleich sind, ändern Sie den Speicherwert V in B, andernfalls tun Sie nichts
Ist der erwartete Wert der nächste? Der Speicherwert ist aktuell?
Wenn es beim Inkrementieren eines Threads keine Konkurrenz durch andere Threads gibt, sollte der erwartete Wert um 1 größer sein als der Speicherwert. Wie kommt es, dass der erwartete Wert und der Speicherwert gleich sind?

我想大声告诉你
我想大声告诉你

Antworte allen(1)
刘奇

泻药~
可能题主这里理解有点偏差

  1. current是预期值,不是内存值

  2. next是修改的新值不是预期值

方法compareAndSet的源码就可以看得出来,里面注释已经很明白了

/**
     * Atomically sets the value to the given updated value
     * if the current value {@code ==} the expected value.
     *
     * @param expect the expected value
     * @param update the new value
     * @return {@code true} if successful. False return indicates that
     * the actual value was not equal to the expected value.
     */
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

CAS的操作是按照题主所说,用预期值和内存值比较,只有当相等时,才会把新值写入,否则会不断重试,是一种乐观的态度,而真正的内存值其实是AtomicInteger.value这个属性(其实最关键也不是这个属性,只是个引用而已,真正的boss后面会提到),注意这个value的有关键字volatile修饰

private volatile int value;

所以这个value值其实是一个共享变量,代表着这个变量的可见性,也就是线程之间的可见性,

=======================话多随便扯了哈可见性,不喜可以直接略过================================

简单点说,Java内存模型规定了变量是存在主存中(类似物理内存)的,各个线程都有自己的工作缓存,在对某个变量操作时,不是直接修改主存中的值,而是在自己的工作缓存中执行,最后在同步到主存中,并且线程相互之间的是不能访问对方的工作缓存的

这里说到的可见性,就是指,线程在操作有关键字volatile修饰的变量时,当成功修改了这个变量并写入了主存,那么其他线程的工作缓存中的变量会失效,所以此时其他线程再次去读取变量时会直接从主存中去读,而不会再用自己工作缓存中的值了

==========================================扯完==============================================

刚才说到AtomicInteger.value这个属性对于数据本身而言,只是一个引用,在调用compareAndSet方法时,可以注意到第二个参数,valueOffset,其实这才是关键...真正的Boss,真正的内存的值,因为涉及到在java语言里很少听到的一个词,指针,这个valueOffset其实就是对象内的偏移量啦,这才是真正的内存值

(之所以这个方法compareAndSet里调用的是Unsafe类的方法,Unsafe这其实就是封装了一些类似指针的操作,指针才不安全嘛)

Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage