This is the third day of my participation in the August Text Challenge.More challenges in August

introduce

CAS(Compare And Swap/Set) The process of the CAS algorithm is as follows: it contains three parameters CAS(V,A, And B). V represents the variable to be updated (the memory value), A represents the expected value (the original value copied from the main physical memory), and B represents the new value (the value to be updated). The value of V is set to B if and only if the value of V is equal to the value of A. If the value of V is different from the value of A, another thread has done the update, and the current thread does nothing. Finally, CAS returns the true value of the current V.

Let’s start with this code

class MyTask {
    //int tickets;
    static AtomicInteger tickets = new AtomicInteger(5);
    static int num = 5;

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    tickets.getAndIncrement();
                    num++;
                }

            }).start();
        }
        while (Thread.activeCount() > 2) {
            Thread.yield();
        }
        System.out.println("tickets=" + tickets);
        System.out.println("num="+ num); }}Copy the code

Running results:

tickets=10005

num=9505

You can see that AtomicInteger guarantees atomicity

Analyze AtomicInteger’s compareAndSet

The java.util.Concurrent package uses * CAS to implement an optimistic lock, which is different from synchronized synchronization. These classes can ensure the atomicity of some operations. The AtomicInteger class compareAndSet implements CAS operations through atomic operations. The lowest level is implemented in assembly language,CAS has 3 operands, memory value V, old expected value A, and new value B to modify. Change the memory value V to B if and only if the expected value A and the memory value V are the same, otherwise do nothing

Example Modified successfully

class MyTask1 {
    //int tickets;
    static AtomicInteger tickets = new AtomicInteger(5);

    public static void main(String[] args) {
        boolean res = tickets.compareAndSet(5.2021); System.out.println(res); System.out.println(tickets.get()); }}Copy the code

Running results:

true

2021

Example Of the modification failure

class MyTask1 {
    //int tickets;
    static AtomicInteger tickets = new AtomicInteger(5);

    public static void main(String[] args) {
// boolean res = tickets.compareAndSet(5, 2021);
        tickets.getAndIncrement();
        System.out.println(tickets.get());
        boolean res = tickets.compareAndSet(5.123); System.out.println(res); System.out.println(tickets.get()); }}Copy the code

Running results:

6

false

6

The compareAndSet has two parameters: except expectation and update value. When the main thread copies a tickets = 5 from the primary physical memory, the execution of compareAndSet(5, 2021) goes like this:

  1. Compare the value of except to the actual value of tickets in main physical memory
  2. If equal, the copied tickets are updated update=2021 and written back to primary physical memory, returning true
  3. If not, the value in the main physical memory has been modified by another thread during the process, and the new value is copied to the working memory. Returning false indicates that the original update operation failed.

CompareAndSet source code:

public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
Copy the code

compareAndSwapInt

public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
Copy the code

You can see that the compareAndSwapInt method has a native specification that is not implemented in the Java language

  • This: Passed object
  • ValueOffset: The memory offset of the object is valueOffset
  • Expectation except:
  • Update: update the value

Read the value of the passed object var1 at its offset in memory compared to the expected value. If equal, the updated value is assigned to the value at offset. Method returns true. If not, cancel the assignment and return false.

This is also the idea of CAS, and comparison and exchange. Used to ensure data security in the case of multiple threads.