Question

The atomic integer, long, boolean etc are used to do any atomic updates to the respective types since there may be a race condition when we execute any manipulation on them, e.g ++. But what are the different cases with references where there may be such race conditions?

Best Regards,
Keshav

Was it helpful?

Solution

AFAIK references are not subject to race condition because the JVM guarantees that the reference update is an atomic operation (unlike e.g. updating a long, where the lower and upper 4 bytes are updated in two distinct steps). The only critical case, as SLaks noted, is compareAndSet which is not atomic by nature. That is very rarely used with native references, but it is a known idiom with AtomicReference when there is a need to update two (or more) logically codependent variables at once. Java Concurrency in Practice, section 15.3.1 publishes an example for this, using an AtomicReference to update two variables (stored in a simple class) in one atomic operation.

The main reason for the existence of AtomicReference - apart from consistency of interfaces - is visibility and safe publication. In this sense, an atomic variable is a "better volatile".

OTHER TIPS

Operations like ++ are subject to race conditions because they involve multiple discreet operations (fetch, increment, store).

Setting a reference (a = b) is a single operation and is thus not subject to race conditions.

Operations on reference types (a.someMethod()) can do anything they want to and may or may not be subject to race conditions.

For learning purpose i wrote a ConcurrentLinkQueue using AtomicReference.

      package concurrent.AtomicE;

      import java.util.concurrent.atomic.AtomicReference;

     public class ConcurrentLinkQueue<V> {
       private final AtomicReference<Node> firstNodePointer = new AtomicReference<Node>();

   public void fastOffer(final V data){
    final Node<V> newNode = new Node<V>(data,Thread.currentThread().getName());
    System.out.println(newNode);
    AtomicReference<Node> pointer = firstNodePointer;
    for(;;){
        if(pointer.get() == null){
            if(pointer.compareAndSet(null,newNode)){
                return;
            }
        }
        pointer = pointer.get().getNext();
    }
}

private static class Node<V>{
    private AtomicReference<Node> next = new AtomicReference<Node>();
    private volatile V data = null;
    private String threadName = "";

    Node(V data1,String threadName){
        this.data = data1;
        this.threadName = threadName;
    }

    @Override
    public String toString() {
        return  "threadName=" + threadName +
                ", data=" + data;
    }

    private AtomicReference<Node> getNext() {
        return next;
    }

    private void setNext(AtomicReference<Node> next) {
        this.next = next;
    }

    private V getData() {
        return data;
    }

    private void setData(V data) {
        this.data = data;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top