Java – why does atomicreference CAS return false with a value of 128?

I use atomicreference to implement atomicinteger However, in testing, I noticed that even in a single threaded environment, CAS operations get stuck once the value reaches 128 What did I do wrong or have a warning in the atomicreference (possibly CPU related)? This is my code:

public class MyAtomInt {
  private final AtomicReference<Integer> ref;

  public MyAtomInt(int init) {
    ref = new AtomicReference<Integer>(init);
  }

  public MyAtomInt() {
    this(0);
  }

  public void inc() {
    while (true) {
      int oldVal = ref.get();
      int nextVal = oldVal + 1;
      boolean success = ref.compareAndSet(oldVal,nextVal); // false once oldVal = 128
      if (success) {
        return;
      }
    }
  }

  public int get() {
    return ref.get();
  }

  static class Task implements Runnable {

    private final MyAtomInt myAtomInt;
    private final int incCount;

    public Task(MyAtomInt myAtomInt,int cnt) {
      this.myAtomInt = myAtomInt;
      this.incCount = cnt;
    }

    @Override
    public void run() {
      for (int i = 0; i < incCount; ++i) {
        myAtomInt.inc();
      }
    }
  }

  public static void main(String[] args) throws Exception {
    MyAtomInt myAtomInt = new MyAtomInt();
    ExecutorService exec = Executors.newSingleThreadExecutor();
    exec.submit(new Task(new MyAtomInt(),150)).get();
    System.out.println(myAtomInt.get());
    exec.shutdown();
  }
}

Solution

The reason for this is that when you load int into integer, you may or may not create a new integer instance If you do this, the new instance may not be equal to other integer instances, even if they share the same value AtomicReference. Compareandset() uses reference equality (identity) for comparison

The key is how the compiler handles the auto boxing of int values: it issues a call to integer Call to valueof() As an optimization, integer Valueof() has a cache of boxed integers. By default, the cache contains up to 128 values If you wrap the integer n twice, if the value is very small, you will get the same integer reference each time, which is enough to enter the cache; Otherwise, you will get two separate instances

At present, you cancel loading the old value, calculate the new value, and load the old value again when you call compareandset() Once 128 is reached, fetching the cache value is stopped, so the second boxed copy is no longer the same as the copy in the atomicreference

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>