And then I am using volatile, so it will guarantee the consistent view of the variable across all threads.
Thread-safety is already guaranteed by atomic variables. volatile is redundant if you won't reassign the variable. You can replace volatile with final here:
private final AtomicInteger atomInt = new AtomicInteger(3);
Does it mean that I have got complete thread safety or still there are chances of "memory consistency issues"?
At this moment, it's absolutely thread-safe. No "memory consistency issues" might happen with the variable. But using proper thread-safe components doesn't mean that the whole class/program is thread-safe. Problems might take place if interactions between them are incorrect.
Using volatile variables reduces the risk of memory consistency errors ...
volatile variables can only guarantee visibility. They don't guarantee atomicity.
As Brian Goetz writes (emphasis mine):
volatile variables are convenient, but they have limitations. The most common use for volatile variables is as a completion, interruption, or status flag. Volatile variables can be used for other kinds of state information, but more care is required when attempting this. For example, the semantics of volatile are not strong enough to make the increment operation (count++) atomic, unless you can guarantee that the variable is written only from a single thread.
You can use volatile variables only when all the following criteria are met:
- Writes to the variable do not depend on its current value, or you can ensure that only a single thread ever updates the value;
- The variable does not participate in invariants with other state variables;
- Locking is not required for any other reason while the variable is being accessed.
From the docs of the java.util.concurrent.atomic package:
- gethas the memory effects of reading a- volatilevariable.
- sethas the memory effects of writing (assigning) a- volatilevariable.