Consider the snippet from Java Concurrency in Practice-
#ThreadSafe
public class SynchronizedInteger{
#GuardedBy("this") private int value;
public synchronized int getValue() {
return value;
}
public synchronized void setValue(int value) {
this.value = value;
}
}
An extract from the same book-
A good way to think about volatile variables is to imagine that they
behave roughly like the SynchronizedInteger class in Listing above,
replacing reads and writes of the volatile variable with calls to get
and set. Yet accessing a volatile variable performs no locking and so
cannot cause the executing thread to block, making volatile variables
a lighter-weight synchronization mechanism than synchronized.
A special case of thread confinement applies to volatile variables. It is safe to perform read-modify-write operations on shared volatile variables as long as you ensure that the volatile variable is only written from a single thread.
So, if you make the instance variable in the above class as volatile and then remove the synchronized keyword, after that suppose there are 3 threads
Thread A & Thread B are writing to the same volatile variable.
Thread C reads the volatile variable.
Since the volatile variable is now written from 2 threads, why is it unsafe to perform read-modify-write operations on this shared volatile variable?
The keyword volatile is used to ensure that changes to your Object will be seen by other Threads.
This does not enforce, that non-atomic operations on the Object will be performed without an other Thread interfering before the operation is finished.
For enforcing this you will need the keyword synchronized.
It's because read-modify-write operations on volatile variables are not atomic. v++ is actually something like:
r1 = v;
r2 = r1 + 1;
v = r2;
So if you have two threads performing this operation once each, it could possibly result in the variable being incremented only once, as they both read the old value. That's an example of why it's not safe.
In your example it would be not safe if you removed synchronized, made the field volatile and had two threads calling setValue after some conditional logic based on the return of getValue - the value could have been modified by the other thread.
If you want atomic operations look at the java.util.concurrent.atomic package.
If you write volatile variable from multiple threads without using any synchronized constructs, you are bound to get data inconsistency errors.
Use volatile variables without synchronization in case of single write thread and multiple read threads for atomic operations.
Volatile make sure that variable value is fetched from main memory instead of Thread cache. It's safe to use in case of single write and multiple read operations.
Use Atomic variables or synchronization or Lock API to update and read variables from multiple threads.
Refer to related SE question:
What is meant by "thread-safe" code?
If two threads are writing without reading the variable first, there is no problem.. it is safe. Problem arises if a thread first reads, then modifies and then writes. What if second thread is also reading at the same time, reads the same old value as the first thread, and modifies it.. and when it writes, it will simply overwrite the first threads update. BOOM.
val i = 1
-> Thread reads 1 -> Threads 2 reads 1 -> Thread 1 does 1 * .2 = 1.2 -> Thread 2 does 1 * .3 = 1.3 -> Thread 1 writes 1.2 back -> Thread 2 cooly overwrites it to 1.3 instead of doing 1.2 * .3
Related
I was digging inside the source code of hibernate-jpa today and stumbled upon the following code snippet (that you can also find here):
private static class PersistenceProviderResolverPerClassLoader implements PersistenceProviderResolver {
//FIXME use a ConcurrentHashMap with weak entry
private final WeakHashMap<ClassLoader, PersistenceProviderResolver> resolvers =
new WeakHashMap<ClassLoader, PersistenceProviderResolver>();
private volatile short barrier = 1;
/**
* {#inheritDoc}
*/
public List<PersistenceProvider> getPersistenceProviders() {
ClassLoader cl = getContextualClassLoader();
if ( barrier == 1 ) {} //read barrier syncs state with other threads
PersistenceProviderResolver currentResolver = resolvers.get( cl );
if ( currentResolver == null ) {
currentResolver = new CachingPersistenceProviderResolver( cl );
resolvers.put( cl, currentResolver );
barrier = 1;
}
return currentResolver.getPersistenceProviders();
}
That weird statement if ( barrier == 1 ) {} //read barrier syncs state with other threads disturbed me. I took the time to dig into the volatile keyword specification.
To put it simply, in my understanding, it ensures that any READ or WRITE operation on the corresponding variable will allways be performed directly in the memory at the place the value is usually stored. It specifically prevents accesses through caches or registrars that hold a copy of the value and are not necessarily aware if the value has changed or is being modified by a concurrent thread on another core.
As a consequence it causes a drop in performances because every access implies to go all the way into the memory instead of using the usual (pipelined?) shortcuts. But it also ensures that whenever a thread reads the variable it will always be up to date.
I provided those details to let you know what my understanding of the keyword is. But now when I re-read the code I am telling myself "Ok wo we are slowing the execution by ensuring that a value which is always 1 is always 1 (and setting it to 1). How does that help?"
Anybody can explain this?
You understand volatile wrong.
it ensures that any READ or WRITE operation on the corresponding
variable will allways be performed directly in the memory at the place
the value is usually stored. It specifically prevents accesses through
caches or registrars that hold a copy of the value and are not
necessarily aware if the value has changed or is being modified by a
concurrent thread on another core.
You are talking about the implemention, while the implemention may differs from jvm to jvm.
volatile is much like some kind of specification or rule, it can gurantee that
Write to a volatile variable establishes a happens-before relationship
with subsequent reads of that same variable. This means that changes
to a volatile variable are always visible to other threads. What's
more, it also means that when a thread reads a volatile variable, it
sees not just the latest change to the volatile, but also the side
effects of the code that led up the change.
and
Using simple atomic variable access is more efficient than accessing
these variables through synchronized code, but requires more care by
the programmer to avoid memory consistency errors. Whether the extra
effort is worthwhile depends on the size and complexity of the
application.
In this case, volatile is not used to gurantte barrier == 1:
if ( barrier == 1 ) {} //read
PersistenceProviderResolver currentResolver = resolvers.get( cl );
if ( currentResolver == null ) {
currentResolver = new CachingPersistenceProviderResolver( cl );
resolvers.put( cl, currentResolver );
barrier = 1; //write
}
it is used to gurantee that the side effects between the read and write is visible to other threads.
Without it, if you put something in the resolvers in Thread1, Thread2 might not notice it.
With it, if Thread2 read barrier after Thread1 write it, Thread2 is gurantted to see this put action.
And, there are many other synchronization mechanism, such as:
synchronized keyword
ReentrantLock
AtomicInteger
....
Usually, they can also build this happens-before relation ship between different threads.
This is done to make updates done to resolvers map to other threads by establishing happens before relationship (https://www.logicbig.com/tutorials/core-java-tutorial/java-multi-threading/happens-before.html).
In a single thread the following instructions have happens before relation
resolvers.put( cl, currentResolver );
barrier = 1;
But to make change in resolvers visible to other threads we need to read value from volatile variable barrier because write and subsequent read of the same volatile variable establish happens before relation (which is also transitive). So basically this is the overall result:
Update resolvers
Write to volatile barrier
Read from volatile barrier to make update made in step 1 visible to a thread which reads value from barrier
Volatile variables - is lightweight form of synchronization in Java.
Declaring a field volatile will give the following effects:
Compiler will not reorder the operations
Variable will be not cashed in registers
Operations on 64-bit data structures will be executed as atomic one
It will affect visibility synchronization of other variables
Quote from Brian Goetz's Concurrency in practice:
The visibility effects of volatile variables extend beyond the value
of the volatile variable itself. When thread A writes to a volatile
variable and subsequently thread B reads that same variable, the
values of all variables that were visible to A prior to writing to the
volatile variable become visible to B after reading the volatile
variable.
Okay, what is the point of keeping 1 and not declare resolvers as volatile WeakHashMap?
This safe publication guarantee applies only to primitive fields and object references. For the purposes of this visibility guarantee, the actual member is the object reference; the objects referred to by volatile object references are beyond the scope of the safe publication guarantee. Consequently, declaring an object reference to be volatile is insufficient to guarantee that changes to the members of the referent are published to other threads. A thread may fail to observe a recent write from another thread to a member field of such an object referent.
Furthermore, when the referent is mutable and lacks thread safety, other threads might see a partially constructed object or an object in a inconsistent state.
The instance of the Map object is mutable because of its put() method.
Interleaved calls to get() and put() may result in the retrieval of internally inconsistent values from the Map object because put() modifies its state. Declaring the object reference volatile is insufficient to eliminate this data race.
Since volatile variable establishes a happens-before relationship, when one thread has an update, it's just can inform others accessing barrier.
From a memory visibility perspective, writing a volatile
variable is like exiting a synchronized block and reading a volatile
variable is like entering a synchronized block.
This I read from the threads::shared description:
By default, variables are private to each thread, and each newly created thread gets a private copy of each existing variable. This module allows you to share variables across different threads ... (more)
Let's say I have a shared variable like this:
my $var :shared;
$var = 10;
This means the variable exists only once for all the threads I create.
Now about atomicity and visibility:
If thread_A assigns a new value let's say 11:
$var = 11;
Is it guaranteed that thread_B (and all the other threads I might have created) will see the value 11 ?
And is the assignment performed atomically ?
Or do we have like in Java first to acquire a lock and then do the assignment and to release the lock. And only threads using the same lock are guaranteed to see the updated value?
Or this behaves like volatile primitive variables in Java ?
It's always good practice to enforce atomicity in updates. Perl provides lock to allow us to do this. You can lock the variable itself - if the variable is shared with the thread, then so is the lock state.
If you update $var then the other threads will see the new value.
But you do have a potential race condition, depending on when they access it. If that's a problem - lock and if it's not... carry on.
Bear in mind that operations such as $var++ are not guaranteed to be atomic. (http://perldoc.perl.org/perlthrtut.html#Thread-Pitfalls%3a-Races)
I want to write a simple thread-safe class that could be used to set or get an Integer value.
The easiest way is to use the synchronized keyword:
public class MyIntegerHolder {
private Integer value;
synchronized public Integer getValue() {
return value;
}
synchronized public void setValue(Integer value) {
this.value = value;
}
}
I could also try using volatile:
public class MyIntegerHolder {
private volatile Integer value;
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
}
Is the class with the volatile keyword thread-safe?
Consider the following sequence of events:
Thread A sets the value to 5.
Thread B sets the value to 7.
Thread C reads the value.
It follows from the Java Language Specification that
"1" happens-before "3"
"2" happens-before "3"
but I don't see how it could follow from the specification that "1" happens-before "2" so I suspect that "1" doesn't happen-before "2".
I suspect the thread C may read 7 or 5. I think the class with the volatile keyword is not thread-safe and the following sequence is also possible:
Thread A sets the value to 5.
Thread B sets the value to 7.
Thread C reads 7.
Thread D reads 5.
Thread C reads 7.
Thread D reads 5.
...
Am I correct in assuming that MyIntegerHolder with volatile is not thread-safe?
Is it possible to make a thread-safe Integer holder by using AtomicInteger:
public class MyIntegerHolder {
private AtomicInteger atomicInteger = new AtomicInteger();
public Integer getValue() {
return atomicInteger.get();
}
public void setValue(Integer value) {
atomicInteger.set(value);
}
}
?
Here is a fragment of the Java Concurrency In Practice book:
"Reads and writes of atomic variables have the same memory semantics
as volatile variables."
What is the best (preferably non-blocking) way of writing a thread-safe MyIntegerHolder?
If you know the answer, I would like to know why you think it is correct. Does it follow from the specification? If so, how?
The keyword synchronized is saying that if Thread A and Thread B want to access the Integer, they cannot do so simultaneously. A is telling B wait until I'm done with it.
On the other hand, volatile makes threads more "friendly". They start talking to each other and working together to perform tasks. So when B tries to access, A will inform B of everything it has done until that moment. B is now aware of the changes and can continue its job from where A left of.
In Java, you have Atomic for this reason, which under the covers use the volatile keyword, so they are doing pretty much the same thing, but they save you time and effort.
The thing you are looking for is AtomicInteger, you are right about this. For the operation you are trying to perform this is the best choice.
There are two main uses of `AtomicInteger`:
* As an atomic counter (incrementAndGet(), etc) that can be used by many threads concurrently
* As a primitive that supports compare-and-swap instruction (compareAndSet()) to implement non-blocking algorithms.
To answer your question on a general note
It depends on what you need. I'm not saying synchronized is wrong and volatile is good, otherwise the nice Java people would have removed synchronized a long time ago. There is no absolute answer, there are a lot of specific cases and usage scenarios.
A few of my bookmarks:
Concurrency tips
Core Java Concurrency
Java concurrency
Update
From the Java Concurrency specification available here:
Package java.util.concurrent.atomic
A small toolkit of classes that support lock-free thread-safe
programming on single variables.
Instances of classes `AtomicBoolean`, `AtomicInteger`, `AtomicLong`, and `AtomicReference` each provide access and updates to a single variable of the corresponding type.
Each class also provides appropriate utility methods for that type.
For example, classes `AtomicLong` and AtomicInteger provide atomic increment methods.
The memory effects for accesses and updates of atomics generally follow the rules for volatiles:
get has the memory effects of reading a volatile variable.
set has the memory effects of writing (assigning) a volatile variable.
Also from Here
The Java programming language volatile keyword:
(In all versions of Java) There is a global ordering on the reads and writes to a volatile variable. This implies that every thread accessing a volatile field will read its current value before continuing, instead of (potentially) using a cached value. (However, there is no guarantee about the relative ordering of volatile reads and writes with regular reads and writes, meaning that it's generally not a useful threading construct.)
If you need only get / set on a variable it is enough to declare it volatile like you did. If you check how AtomicInteger set / get work you will see the same implementation
private volatile int value;
...
public final int get() {
return value;
}
public final void set(int newValue) {
value = newValue;
}
but you cannot increment a volatile field atomically this simple. This is where we use AtomicInteger.incrementAndGet or getAndIncrement methods .
Chapter 17 of the Java Language Specification defines the happens-before relation on memory operations such as reads and writes of shared variables. The results of a write by one thread are guaranteed to be visible to a read by another thread only if the write operation happens-before the read operation.
The synchronized and volatile constructs, as well as the Thread.start() and Thread.join() methods, can form happens-before
relationships. In particular: Each action in a thread happens-before
every action in that thread that comes later in the program's order.
An unlock (synchronized block or method exit) of a monitor happens-before every subsequent lock (synchronized block or method
entry) of that same monitor. And because the happens-before relation
is transitive, all actions of a thread prior to unlocking
happen-before all actions subsequent to any thread locking that
monitor.
A write to a volatile field happens-before every subsequent read of that same field. Writes and reads of volatile fields have similar
memory consistency effects as entering and exiting monitors, but do
not entail mutual exclusion locking.
A call to start on a thread happens-before any action in the started thread.
All actions in a thread happen-before any other thread successfully returns from a join on that thread.
reference: http://developer.android.com/reference/java/util/concurrent/package-summary.html
from my understanding 3 means: if you write (not based read result) / read is fine. if you write (based on read result, e.g., increment) / read is not fine. Since volatile "do not entail mutual exclusion locking"
Your MyIntegerHolder with volatile is thread safe. But AtomicInteger is preferred if you are doing concurrent program, because it also provides a lot of atomic operations.
Consider the following sequence of events:
Thread A sets the value to 5.
Thread B sets the value to 7.
Thread C reads the value.
It follows from the Java Language Specification that
"1" happens-before "3"
"2" happens-before "3"
but I don't see how it could follow from the specification that "1"
happens-before "2" so I suspect that "1"
doesn't happen-before "2".
I suspect the thread C may read 7 or 5. I think the class with the
volatile keyword is not thread-safe
You are right here that "1" happens-before "3" and "2" happens-before "3". "1" does not happens-before "2", but it doesn't mean that it is not Thread-safe. The thing is that the example you provided is ambiguous. If you are saying "sets the value to 5", "sets the value to 7", "reads the value" happens sequentially, you can always read the value of 7. And it is nonsense to put them in different threads. But if you are saying that 3 threads executes concurrently without sequence, you can even get value of 0, because "reads the value" could happen first. But this is nothing with Thread-safe, there is no order expecting from the 3 actions.
The question was not easy for me, because I thought (incorrectly) that knowing everything about the happens-before relation gives one a complete understanding of the Java Memory Model - and the semantics of volatile.
I found the best explanation in this document:
"JSR-133: JavaTM Memory Model and Thread Specification"
The most relevant fragment of the above document is the section "7.3 Well-Formed Executions".
The Java Memory Model guarantees that all executions of a program are well-formed. An execution is well-formed only if it
Obeys happens-before consistency
Obeys synchronization-order consistency
... (some other conditions must also be true)
Happens-before consistency is usually enough to come to a conclusion about the program behavior - but not in this case, because a volatile write doesn't happen-before another volatile write.
The MyIntegerHolder with volatile is thread-safe, but it's safety comes from the synchronization-order consistency.
In my opinion when Thread B is about to set the value to 7, A doesn't inform B of everything it has done until that moment (as one of the other answers suggested) - it only informs B about the value of the volatile variable. Thread A would inform B about everything (assigning values to other variables) if the action taken by Thread B was read and not write (in that case, there would exist the happens-before relationship between the actions taken by these two threads).
This question already has answers here:
What is the difference between atomic / volatile / synchronized?
(7 answers)
Closed 3 years ago.
I know volatile allows for visibility, AtomicInteger allows for atomicity.
So if I use a volatile AtomicInteger, does it mean I don't have to use any more synchronization mechanisms?
Eg.
class A {
private volatile AtomicInteger count;
void someMethod(){
// do something
if(count.get() < 10) {
count.incrementAndGet();
}
}
Is this threadsafe?
I believe that Atomic* actually gives both atomicity and volatility. So when you call (say) AtomicInteger.get(), you're guaranteed to get the latest value. This is documented in the java.util.concurrent.atomic package documentation:
The memory effects for accesses and updates of atomics generally follow the rules for volatiles, as stated in section 17.4 of The Java™ Language Specification.
get has the memory effects of reading a volatile variable.
set has the memory effects of writing (assigning) a volatile variable.
lazySet has the memory effects of writing (assigning) a volatile variable except that it permits reorderings with subsequent (but not previous) memory actions that do not themselves impose reordering constraints with ordinary non-volatile writes. Among other usage contexts, > - lazySet may apply when nulling out, for the sake of garbage collection, a reference that is never accessed again.
weakCompareAndSet atomically reads and conditionally writes a variable but does not create any happens-before orderings, so provides no guarantees with respect to previous or subsequent reads and writes of any variables other than the target of the weakCompareAndSet.
compareAndSet and all other read-and-update operations such as getAndIncrement have the memory effects of both reading and writing volatile variables.
Now if you have
volatile AtomicInteger count;
the volatile part means that each thread will use the latest AtomicInteger reference, and the fact that it's an AtomicInteger means that you'll also see the latest value for that object.
It's not common (IME) to need this - because normally you wouldn't reassign count to refer to a different object. Instead, you'd have:
private final AtomicInteger count = new AtomicInteger();
At that point, the fact that it's a final variable means that all threads will be dealing with the same object - and the fact that it's an Atomic* object means they'll see the latest value within that object.
I'd say no, it's not thread-safe, if you define thread-safe as having the same result under single threaded mode and multithreaded mode. In single threaded mode, the count will never go greater than 10, but in multithreaded mode it can.
The issue is that get and incrementAndGet is atomic but an if is not. Keep in mind that a non-atomic operation can be paused at any time. For example:
count = 9 currently.
Thread A runs if(count.get() <10) and gets true and stopped there.
Thread B runs if(count.get() <10) and gets true too so it runs count.incrementAndGet() and finishes. Now count = 10.
Thread A resumes and runs count.incrementAndGet(), now count = 11 which will never happen in single threaded mode.
If you want to make it thread-safe without using synchronized which is slower, try this implementation instead:
class A{
final AtomicInteger count;
void someMethod(){
// do something
if(count.getAndIncrement() <10){
// safe now
} else count.getAndDecrement(); // rollback so this thread did nothing to count
}
To maintain the original semantics, and support multiple threads, you could do something like:
public class A {
private AtomicInteger count = new AtomicInteger(0);
public void someMethod() {
int i = count.get();
while (i < 10 && !count.compareAndSet(i, i + 1)) {
i = count.get();
}
}
}
This avoids any thread ever seeing count reach 10.
Answer is there in this code
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/atomic/AtomicInteger.java
This is source code of AtomicInteger.
The value is Volatile.
So,AtomicInteger uses Volatile inside.
Your query can be answered in 2 parts, because there are 2 questions in your query :
1)
Referring to Oracle's tutorial documentation for Atomic variables :
https://docs.oracle.com/javase/tutorial/essential/concurrency/atomicvars.html
The java.util.concurrent.atomic package defines classes that support atomic operations on single variables. All classes have get and set methods that work like reads and writes on volatile variables. That is, a set has a happens-before relationship with any subsequent get on the same variable. The atomic compareAndSet method also has these memory consistency features, as do the simple atomic arithmetic methods that apply to integer atomic variables.
So atomic integer does use volatile inside, as other answers here have mentioned. So there's no point in making your atomic integer volatile. You need to synchronize your method.
You should watch John Purcell's free video on Udemy , where he shows the failure of volatile keyword when multiple threads are trying to modify it. Simple and beautiful example.
https://www.udemy.com/course/java-multithreading/learn/lecture/108950#overview
If you change the volatile counter in John's example into an atomic variable, his code is guaranteed to succeed without using sunchronized keyword like he has done in his tutorial
2) Coming to your code :
Say thread 1 kicks into action and "someMethod" does a get and checks for size. It is possible that before getAndIncrement executes(say, by thread 1) , another thread (say thread 2)kicks in and increases the count to 10, and gets out; after which, your thread 1 will resume and increase count to 11. This is erroneous output. This is because your "someMethod" is not protected in anyway from synhronization problems.
I would still recommend you to watch john purcell's videos to see where volatile fails , so that you have a better understanding of the keyword volatile. Replace it with atomicinteger in his example and see the magic.
Is a volatile int in Java thread-safe? That is, can it be safely read from and written to without locking?
Yes, you can read from it and write to it safely - but you can't do anything compound such as incrementing it safely, as that's a read/modify/write cycle. There's also the matter of how it interacts with access to other variables.
The precise nature of volatile is frankly confusing (see the memory model section of the JLS for more details) - I would personally generally use AtomicInteger instead, as a simpler way of making sure I get it right.
[...] as in being able to be safely read from and written to without locking?
Yes, a read will always result in the value of the last write, (and both reads and writes are atomic operations).
A volatile read / write introduces a so called happens-before relation in the execution.
From the Java Language Specification Chapter 17: Threads and Locks
A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.
In other words, when dealing with volatile variables you don't have to explicitly synchronize (introduce a happens-before relation) using synchronized keyword in order to ensure that the thread gets the latest value written to the variable.
As Jon Skeet points out though, the use of volatile variables are limited, and you should in general consider using classes from the java.util.concurrent package instead.
Access to volatile int in Java will be thread-safe. When I say access I mean the unit operation over it, like volatile_var = 10 or int temp = volatile_var (basically write/read with constant values). Volatile keyword in java ensures two things :
When reading you always get the value in main memory. Generally for optimization purposes JVM use registers or in more general terms local memory foe storing/access variables. So in multi-threaded environment each thread may see different copy of variable. But making it volatile makes sure that write to variable is flushed to main memory and read to it also happens from main memory and hence making sure that thread see at right copy of variable.
Access to the volatile is automatically synchronized. So JVM ensures an ordering while read/write to the variable.
However Jon Skeet mentions rightly that in non atomic operations (volatile_var = volatile + 1) different threads may get unexpected result.
1) If two threads are both reading and writing to a shared variable, then using the volatile keyword for that is not enough. You need to use a synchronized in that case to guarantee that the reading and writing of the variable is atomic. Reading or writing a volatile variable does not block threads reading or writing. For this to happen you must use the synchronized keyword around critical sections.
2) As an alternative to a synchronized block you could also use one of the many atomic data types found in the java.util.concurrent package. For instance, the AtomicLong or AtomicReference or one of the others.
It's thread safe if you have one writer thread and multiple reader threads.
class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null)
helper = new Helper();
}
}
return helper;
}
}
Note : If helper is immutable then no need of volatile keyword.Here singleton will work properly.
In case of counter which is being incremented by multiple threads (reading writing operation) will not give correct answer. This condition is also illustrated by race condition.
public class Counter{
private volatile int i;
public int increment(){
i++;
}
}
NOTE : Here volatile will not help.
Not always.
It's not thread safe if multiple threads are writing and reading the variable. It's thread safe if you have one writer thread and multiple reader threads.
If you are looking for Thread safely, use AtomicXXX classes
A small toolkit of classes that support lock-free thread-safe programming on single variables.
In essence, the classes in this package extend the notion of volatile values, fields, and array elements to those that also provide an atomic conditional update operation of the form:
boolean compareAndSet(expectedValue, updateValue);
Refer to #teto answer in below post:
Volatile boolean vs AtomicBoolean
If a volatile is not dependent on any other volatile variable its thread safe for read operation. In case of write volatile does not guarantee thread safety.
Assume you have a variable i which is volatile and its value is dependent on another volatile variable say j. Now Thread-1 access variable j and increment it and is about to update it in main memory from CPU cache. In case the Thread-2 reads the
variable i before Thread-1 can actually update the j in main memory. The value of i will be as per the old value of j which would be incorrect. Its also called Dirty read.