Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does atomic variables guarantee memory visibility?

Small question about memory visibility.

CodeSample1:

class CustomLock {

    private boolean locked = false;

    public boolean lock() {
        if(!locked) {
            locked = true;
            return true;
        }
        return false;
    }
}

This code is prone to bugs in a multi-threaded environment, first because of the "if-then-act" which is not atomic, and second because of potential memory visibility issues where for example threadA sets the field to true, but threadB that later wishes to read the field's value might not see that, and still see the value false.

The simplest solution is to use the synchronized keyword, as in CodeSample2.

CodeSample2:

class CustomLock {

    private boolean locked = false;

    public synchronized boolean lock() {
        if(!locked) {
            locked = true;
            return true;
        }
        return false;
    }
}

Now what if I wish to use an atomic variable, and for the example, an AtomicBoolean (question applies to all atomic variables),

CodeSample3:

   public static class CustomLock {
    private AtomicBoolean locked = new AtomicBoolean(false);

    public boolean lock() {
        return locked.compareAndSet(false, true);
    }
}

Better performance considerations aside, we can see that now we've implemented similar logic to the "if-then-act" from CodeSample1, using AtomicBoolean. It doesn't really matter what the code does logically, the question I have is what if 2 threads invoke the lock() method in CodeSample3 right about the same time, while it's clear that any write operation to the field will now be done atomically, does the use of AtomicBoolean also guarantees memory visibility?

Sorry for the long story, just wanted to make sure I'm coming across as clear as possible, Thanks guys...

like image 942
JamesJenkins Avatar asked Mar 17 '17 22:03

JamesJenkins


People also ask

What is the purpose of using atomic variables?

Atomic Variable Atomic variables minimize synchronization and help avoid memory consistency errors. Hence, it ensures synchronization. The atomic package provides the following five atomic variables: AtomicInteger.

What is the difference between volatile and atomic variables?

Volatile and Atomic are two different concepts. Volatile ensures, that a certain, expected (memory) state is true across different threads, while Atomics ensure that operation on variables are performed atomically.

Are memory reads Atomic?

Storing values to memory and reading values from memory are atomic operations. ¹ If a competing processor writes to or reads the same memory, the result will be completely one value or the other, never a mix of the two. This atomicity does not extend by default to read-modify-write operations, however.

How do atomic variables work in Java?

An atomic variable can be one of the alternatives in such a scenario. Java provides atomic classes such as AtomicInteger, AtomicLong, AtomicBoolean and AtomicReference. Objects of these classes represent the atomic variable of int, long, boolean, and object reference respectively.


2 Answers

Yes, according to the javadocs it guarantees:

compareAndSet and all other read-and-update operations such as getAndIncrement have the memory effects of both reading and writing volatile variables.

like image 101
Iłya Bursov Avatar answered Sep 20 '22 21:09

Iłya Bursov


the question I have is what if 2 threads invoke the lock() method in CodeSample3 right about the same time, while it's clear that any write operation to the field will now be done atomically, does the use of AtomicBoolean also guarantees memory visibility?

For AtomicBoolean to handle multiple operations from different threads at the same time it has to guarantee memory visibility. It can make the guarantee because it wraps a volatile field. It is the language semantics of the volatile which ensures that memory barriers are crossed so that multiple threads see the most up to date value and that any updates will be published to main memory.

Btw, your lock(...) method should ready be tryLock(...) because it might not get the lock.

like image 37
Gray Avatar answered Sep 20 '22 21:09

Gray