Search code examples
javaarraysmultithreadingatomicreference

Data Races on individual elements of an AtomicReference


I had a question related to accessing individual elements via an Atomic Reference. If I have an IntegerArray and an atomic reference to it;will reading and writing to individual elements of the array via the AtomicReference variable cause data races?

In the code below: num is an Integer Array with aRnumbers being the atomic reference to the array. In threads 1 and 2; I access aRnumbers.get()[1] and increment it by 1.

I am able to access individual elements via the atomic reference without data races to accurate results each time with 22 as the output of aRnumbers.get()[1] in the main thread after both threads complete.

But,since the atomic reference is defined on the array and not on the individual elements; shouldn't there be a data race in this case leading to 21/22 as the output?

Isn't having data races in this case the motivation for having a AtomicIntegerArray data structure which provides a separate AtomicReference to each element?

Please find below the java code that i am trying to run.Could anyone kindly let me know where I am going wrong.

import java.util.concurrent.atomic.AtomicReference;

public class AtomicReferenceExample {


    private static int[] num= new int[2];
    private static AtomicReference<int[]> aRnumbers;

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new MyRun1());
        Thread t2 = new Thread(new MyRun2());

        num[0]=10;
        num[1]=20;

        aRnumbers = new AtomicReference<int[]>(num);

        System.out.println("In Main before:"+aRnumbers.get()[0]+aRnumbers.get()[1]);

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("In Main after:"+aRnumbers.get()[0]+aRnumbers.get()[1]);
    }

    static class MyRun1 implements Runnable {
        public void run() {
            System.out.println("In T1 before:"+aRnumbers.get()[1]);
            aRnumbers.get()[1]=aRnumbers.get()[1]+1;

        }
    }

    static class MyRun2 implements Runnable {
        public void run() {
            System.out.println("In T2 before:"+aRnumbers.get()[1]);
            aRnumbers.get()[1]=aRnumbers.get()[1]+1;

        }

    }

}

Solution

  • shouldn't there be a data race in this case leading to 21/22 as the output?

    Indeed there is. Your thread are so short lived that most likely they are not running at the same time.

    Isn't having data races in this case the motivation for having a AtomicIntegerArray data structure which provides a separate AtomicReference to each element?

    Yes, it is.

    Could anyone kindly let me know where I am going wrong.

    Starting a thread takes 1 - 10 milli-seconds.

    Incrementing a value like this even without the code being JITed is likely to take << 50 microseconds. If it was optimised it would take about 50 - 200 nano-seconds per increment.

    As starting athread takes about 20 - 200x longer than the operating they won't be running at the same time so there is no race condition.

    Try incrementing the value a few million times, so you have a race condition because both threads are running at the same time.