Master Series Concurrent Programming-7. Atomic Concurrent Classification

Master high concurrency, high availability architecture

Lesson 2 Concurrent Programming

Learn concurrent programming from this lesson. This paper mainly introduces the basic knowledge of concurrent programming, lock, memory model, thread pool and the use of various concurrent containers.

Section 7 Concurrent Classification of Atoms

Atomic CAS ABA

The Famous ABA Problem

For example, a full glass of water on the table is knocked over, cleaned and cleaned, then poured a glass, which others think is the same as before. Thread 1 is the party, thread 2 is someone else, and shared variable V is the glass of water. Thread 1 and thread 2 get the initial value A of shared variable V at the same time, and deal with it separately. Thread 1 updates the value to B and A. Thread 2 finds that it is A when it takes value again, and then does its processing. This scenario is incorrect in some cases, such as a shopping mall launching activities, where the residual amount of membership card is less than 100 yuan, the shopping mall will recharge 20 yuan for two days. As a result, because the membership card had been recharged once 20 yuan, he spent 50 yuan, the balance is less than 100 yuan, which will recharge 20 yuan again, resulting in one. Membership cards are recharged many times.

The following code demonstrates an ABA problem

public void aba() {
    AtomicInteger abaInt = new AtomicInteger(100);

    Thread t1 = new Thread() {

        public void run() {
            abaInt.compareAndSet(100, 101);
            System.out.println(String.format("thread t1, abaInt: %s", abaInt.get()));

            abaInt.compareAndSet(101, 100);
            System.out.println(String.format("thread t1, abaInt: %s", abaInt.get()));
        }
    };

    Thread t2 = new Thread() {
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            boolean success = abaInt.compareAndSet(100, 101);
            System.out.println(String.format("thread t2, abaInt: %s, isSuccess: %s", abaInt.get(), success));
        }
    };

    t1.start();
    t2.start();
}
thread t1, abaInt: 101
thread t1, abaInt: 100
thread t2, abaInt: 101, isSuccess: true

The value of 100 compared in thread t2 is actually no longer the previous value of 100. Variables in memory addresses have undergone changes in A-> B-> A.

The root cause of ABA problem is that it is impossible to judge whether the variables have been changed, so the solution is to add state to the shared variables to record whether the shared variables have been modified.

Atomics

Under the java.util.concurrent.atomic package, atomic classes have the following classes:

AtomicBoolean Atoms Update Boolean Values
 The Value of Atomic Integer Atomic Addition and Decrease Numbers
 AtomicLong Atoms Update Long Number Type Values
 AtomicReference Atom Updates Reference Type Value

Atomic Integer Array Atom Updates Elements of Digital Array
 Atomic Long Array Atoms Update Elements of Long Digital Arrays
 AtomicReference Array Atom Updates Elements of Reference Type Array

The value of the numeric type field of the Atomic IntegerField Updater atomic update class
 The Value of Long Number Type Field of Atomic LongField Updater Atomic Update Class
 The value of the reference type field of the Atomic Reference Field Updater atomic update class

Atomic StampedReference Atom updates the value of reference type with version number to solve ABA problem

The steps of atom updating field:

  1. Since the classes of atomic update fields are abstract classes, you need to use the static method newUpdater() to create updates and specify the classes and fields to be updated.
AtomicIntegerFieldUpdater<User> upd = AtomicIntegerFieldUpdater.newUpdater(User.class, 'age');
  1. The field to be updated must be public volatile

The foundation of atomic operation is CAS, which gives the operation to the atomicity of hardware bottom layer.

Here's a code to avoid ABA problems:

public void noAba() {
    AtomicStampedReference<Integer> noAbaInt = new AtomicStampedReference<Integer>(100, 0);

    Thread t1 = new Thread() {
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            noAbaInt.compareAndSet(100, 101, noAbaInt.getStamp(), noAbaInt.getStamp() + 1);
            System.out.println(String.format("thread t1, noAbaInt: %s", noAbaInt.getReference()));

            noAbaInt.compareAndSet(101, 100, noAbaInt.getStamp(), noAbaInt.getStamp() + 1);
            System.out.println(String.format("thread t1, noAbaInt: %s", noAbaInt.getReference()));
        }
    };

    Thread t2 = new Thread() {
        public void run() {
            int stamp = noAbaInt.getStamp();
            System.out.println("before stamp " + stamp);

            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("after stamp " + noAbaInt.getStamp());
            boolean success = noAbaInt.compareAndSet(100, 101, stamp, stamp + 1);
            System.out.println(String.format("thread t2, noAbaInt: %s, isSuccess: %s", noAbaInt.getReference(), success));
        }
    };

    t1.start();
    t2.start();
}
before stamp 0
thread t1, noAbaInt: 101
thread t1, noAbaInt: 100
after stamp 2
thread t2, noAbaInt: 100, isSuccess: false

You can see that the thread t2 update failed because the version number is not the expected value, so the update failed.

Keywords: Java Programming less

Added by natasha_thomas on Mon, 12 Aug 2019 06:17:31 +0300