ABA Problems and Solutions

Keywords: Java

What is the ABA problem?

In a word, the civet cat changes for the prince.
In CAS, we compare before we operate on an object. Now add A to get a variable 10 in main memory and B to get it at the same time, while A thread runs slowly, assuming 10 s, B thread runs faster, assuming 2 s, so B thread can operate on 10 first, say + 1, and write to main memory, but A has not responded, B can continue to operate, then - 1, so that The main memory variable is still 10. At this time, the thread A finally runs and operates on 10. A compares the value it gets with the value of main memory first, and can continue to operate. But until we reach the point that the 10 of A is not the same as the 10 of main memory, so the problem is ABA.

package cn.edu.cas;

import java.util.concurrent.atomic.AtomicInteger;

public class ABADemo {
    public static void main(String[] args) {
        AtomicInteger a=new AtomicInteger(10);

        new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"\t"+a);
            a.compareAndSet(10,13);
            System.out.println(Thread.currentThread().getName()+"\t"+a);
        },"AA").start();

        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"\t"+a);
            a.compareAndSet(10,12);
            System.out.println(Thread.currentThread().getName()+"\t"+a);
            a.compareAndSet(12,10);
            System.out.println(Thread.currentThread().getName()+"\t"+a);
        },"BB").start();
    }
}


You can see that two threads A and B operate variable a at the same time, but because of the slow execution speed of thread A, when A goes to perform operation on a, B has operated a many times, but because the result happens to be unchanged, when A is compared again, it is assumed that there is no change and the operation is performed. So how to avoid this problem?

Time stamp, version number

This involves atomic references.

public static void main(String[] args) {
        AtomicStampedReference<Integer> a=new AtomicStampedReference<>(10,1);
        new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"\t"+a.getReference()+"\t"+a.getStamp());
            a.compareAndSet(10,2019,1,2);
            System.out.println(Thread.currentThread().getName()+"\t"+a.getReference()+"\t"+a.getStamp());
        },"AA").start();

        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"\t"+a.getReference()+"\t"+a.getStamp());
            a.compareAndSet(10,12,1,2);
            System.out.println(Thread.currentThread().getName()+"\t"+a.getReference()+"\t"+a.getStamp());
            a.compareAndSet(12,10,2,3);
            System.out.println(Thread.currentThread().getName()+"\t"+a.getReference()+"\t"+a.getStamp());
        },"BB").start();
}


Perfect problem solving!

Posted by manishdugar on Fri, 04 Oct 2019 08:42:56 -0700