1

Suppose I have

private volatile AtomicInteger atomInt = new AtomicInteger(3);

and in methods my usage is atomInt.incrementAndGet().

Since I am using AtomicInteger, it will avoid "thread interference". And then I am using volatile, so it will guarantee the consistent view of the variable across all threads. Does it mean that I have got complete thread safety or still there are chances of "memory consistency issues"?

I got confused because of usage of "reduce" in tutorial, so it suggests me that there are still chances but I cannot think of it:

Using volatile variables reduces the risk of memory consistency errors, because any write to a volatile variable establishes a happens-before relationship with subsequent reads of that same variable.

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
pjj
  • 2,015
  • 1
  • 17
  • 42
  • 4
    Are you ever reassigning `atomInt` (as in `atomInt = ...`)? If not, make it final, not volatile. The volatile refers to the value of the variable, not to state in the thing the variable points to. – Andy Turner Feb 15 '18 at 19:26
  • @AndyTurner Thank you for your time to reply. Ok, I think then it would guarantee thread safety, right? But still I am looking for answer to my question. – pjj Feb 15 '18 at 19:29
  • The answer to your question is that you shouldn't need to use volatile if you are never reassigning the variable, and you may need to use it if you are. – Andy Turner Feb 15 '18 at 19:31
  • @AndyTurner For sake of my "learning", lets say I am reassigning. – pjj Feb 15 '18 at 19:32
  • 2
    Ditto @AndyTurner. Declare the variable to be `final`, not `volatile`. If you are using an `AtomicInteger` variable and you _can't_ declare it to be `final` then you are either doing something very tricky, or what's more likely, something wrong. – Solomon Slow Feb 15 '18 at 22:15
  • 2
    Re, "Does it mean that I have got complete thread safety...?" Complete thread safety is when your multi-threaded program is guaranteed to always do the right thing. You haven't shown us a complete program, so there's no way to truly answer that question. Thread safety is an attribute of the whole program's architecture. It's not something you can bestow on a program one line at a time. – Solomon Slow Feb 15 '18 at 22:28
  • "Thread safety" is not a very well-defined term, at least it isn't one that is [formally defined in Java](https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4). But @jameslarge is right, you can only reason about a whole program, for example any code, no matter how bad, is "thread-safe" when run in a single thread. What you're really looking for is whether an otherwise correctly synchronised program would become incorrectly synchronised by the introduction of this code. And the answer to that is no. – biziclop Feb 16 '18 at 10:38

2 Answers2

4

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:

  • get has the memory effects of reading a volatile variable.
  • set has the memory effects of writing (assigning) a volatile variable.
Community
  • 1
  • 1
Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
  • But what about this from Java tutorials I have provided in my question - " Atomic actions cannot be interleaved, so they can be used without fear of thread interference. **However, this does not eliminate all need to synchronize atomic actions, because memory consistency errors are still possible.**" – pjj Feb 15 '18 at 19:36
  • I am bit confused because of the description of "java.util.concurrent.atomic" package because without use of volatile or synchronized, "read barrier" and "write barrier" will not execute, and if they do not execute then there is no guarantee about flushing of cache values to main memory. – pjj Feb 15 '18 at 19:39
  • @pjj **The memory effects for accesses and updates of atomics generally follow the rules for volatiles, as stated in The Java Language Specification (17.4 Memory Model)** as pointed out by @Andrew Tobilko But if you need to atomically change several `Atomic`s or use check-then-act then you need additional synchronization – Ivan Feb 15 '18 at 20:20
  • Do I understand correctly that the final is needed to make sure the reference to the AtomicInteger is seen by all threads? – Bernhard Jun 09 '22 at 09:35
1

Volatile does mean that changes to the variable will be visible. But in this case you shouldn’t be changing the reference held by the variable.

It seems very odd that you’d want to make a reference to an Atomic object volatile. The whole point of the atomicinteger class is to provide a way to access and change an integer value safely. The only reason to make some variable volatile is because you intend to overwrite its value. Why overwrite the reference to the AtomicInteger when you can use its instance methods to update its value?

That’s why you are getting advice to make this variable final instead of volatile. Making the variable final nails down the reference so it can’t change, while making sure the reference contained by that variable is visible. The atomicInteger manages its own state in a threadsafe way so you shouldn’t have to overwrite the reference to it.

So it’s not exactly correct to say volatile is redundant here. But it is doing something that typically shouldn’t have to be done. Use volatile when you have to change the value contained in the variable. Use final when you shouldn’t be changing the value contained in the variable.

Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276