I want to keep track of a position inside a queue that gets modified inside a synchronized block. Therefore I need a counter variable. Normally I would use AtomicInteger but do I need that here?
PriorityBlockingQueue<TfIdfScore> allScores = sharedFeatureNameToScores.get(featureName);
synchronized (allScores) {
AtomicInteger position = positionCounterMap.get(featureName);
position.getAndAdd(1);
// Do other stuff..
}
Or could I use int or Integer as well? Does the synchronized block protect all my actions inside the block?
In this example position and allScores depend on the same featureName.
If you are writing all of the code (and taking appropriate care) then you don't need to to use both synchronized and an atomic type. Just make sure that all operations on a given map and the counters it contains synchronize on the same object while they do that ... and that part of the code should thread-safe.
On the other hand, if you are worried that someone will forget to synchronize, then an atomic type probably won't solve the problem. A better solution is to make sure that the map and the counters well encapsulated, to reduce the scope for mistakes. (If you can reduce the amount of code can access the state, that reduces the number of places you need to check for thread safety.)
Does the synchronized block protect all my actions inside the block?
Not necessarily.
You can still have thread-safety problems if there is other code accessing or updating the data structures, and that code is not synchronizing on the right mutex; e.g. the same allScores instance.
Synchronized is a more strict then atomic or volatile. Thus you have no need to use atomic in synchronized
Synchronized
Synchronized methods enable a simple strategy for preventing thread interference and memory consistency errors: if an object is visible to more than one thread, all reads or writes to that object's variables are done through synchronized methods.
Volatile
volatile field means that variable won't be cached in processors core/threads. Thus you will have only one copy of variable per all cores/threads
atomic
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.
In your code you are using two different object using featureName: sharedFeatureNameToScores and positionCounterMap.
In order to guarantee that your code is thread safe you need to ensure that the modifications to both of them is made using the same lock (synchronized (allScores) in you code). Once you satisfy this requirement there is no need to user AtomicInteger since the synchronized block protects both so the access to positionCounterMap is made in exclusive mode.
Related
This question already has answers here:
What is the difference between atomic / volatile / synchronized?
(7 answers)
Closed 3 years ago.
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.
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.
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.
Let's consider the following standard synchronization in Java:
public class Job {
private Lock lock = new ReentrantLock();
public void work() {
lock.lock();
try {
doLotsOfWork();
} finally {
lock.unlock();
}
}
}
I understand, based on Javadoc, that this is equivalent to synchronized block. I am struggling to see how this is actually enforced on the lower-level.
Lock has a state which is a volatile, upon call to lock() it does a volatile read, then upon release it performs a volatile write. How can a write to a state of one object ensure, that none of the instruction of doLotsOfWork, which might touch lots of different objects, will not be executed out of order?
Or imagine that doLotsOfWork is actually substituted with 1000+ lines of code. Clearly the compiler cannot know in advance that there is a volatile somewhere inside the lock, therefore it needs to stop re-ordering the instructions. So, how is happens-before guaranteed for lock/unlock, even though it is built around volatile state of a separate object?
Well, if I understood correctly then your answer is here. volatile writes and reads introduce memory barriers : LoadLoad, LoadStore, etc. that forbid re-orderings. At the CPU level this is translated to actual memory barriers like mfence or lfence (the CPU forces the non-reordering via some other mechanisms too, so you might see something else in the machine code as-well).
Here is a small example:
i = 42;
j = 53;
[StoreStore]
[LoadStore]
x = 1; // volatile store
i and j assignments can be re-ordered between then, but they can not with x=1 or in other words i and j can not go below x.
Same applies to the volatile reads.
For your example every operation inside doLotsOfWork can be re-ordered as the compiler pleases, but it can not be re-ordered with lock operations.
Also when you say that the compiler can not know that there is a volatile read/write, you are slightly wrong. It has to know that, otherwise there would be no other way to prevent those re-orderings.
Also, last note: since jdk-8 you can enforce non re-orderings via the Unsafe that provides ways to that besides volatile.
From Oracle's documentation:
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.
Java Concurrency in Practice states it even more clearly:
The visibility effects of volatile variables extend beyond the value
of the volatile variable itself. When a 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.
Applied to ReentrantLock it means that everything executed before lock.unlock() (doLotsOfWork() in your case) will be guaranteed to happen before subsequent call to lock.lock(). Instructions inside doLotsOfWork() still can be reordered among themselves. The only thing that is guaranteed here is that any thread which will subsequently acquire the lock calling lock.lock() will see all changes done in doLotsOfWork() before calling lock.unlock().
When Synchronization is used there is a performance impact. Can volatile be used in combination with synchronized to reduce the performance overhead ? For example, instance of Counter will be shared among many threads and each thread can access Counter's public methods. In the below code volatile is used for getter and synchronized is used for setter
public class Counter
{
private volatile int count;
public Counter()
{
count = 0;
}
public int getCount()
{
return count;
}
public synchronized void increment()
{
++count;
}
}
Please let me know in which scenario this might break ?
Yes, you definitely can. In fact, if you look at the source code of AtomicInteger, it's essentially what they do. AtomicInteger.get simply returns value, which is a volatile int (link). The only real difference from what you've done and what they do is that they use a CAS for the increment instead of synchronization. On modern hardware, a CAS can eliminate any mutual exclusion; on older hardware, the JVM will put some sort of mutex around the increment.
Volatile reads are about as fast as non-volatile ones, so the reads will be quite fast.
Not only that, but volatile fields are guaranteed not to tear: see JLS 17.7, which specifies that volatile longs and doubles are not subject to word tearing. So your code would work with a long just as well as an int.
As Diego Frehner points out, you might not see the result of an increment if you get the value "right as" the increment happens -- you'll either see the before or the after. Of course, if get were synchronized you'd have exactly the same behavior from the read thread -- you'd either see the before-increment or post-increment value. So it's really the same either way. In other words, it doesn't make sense to say that you won't see the value as it's happening -- unless you meant word tearing, which (a) you won't get and (b) you would never want.
1. I have personally used this mechanism of volatile combined with synchronized.
2. You can alone use synchronized, and you will always get a consistent result, but using
only volatile alone will Not yield the same result always.
3. This is because volatile keyword is not a synchronization primitive. It merely prevents caching of the value on the thread, but it does not prevent two threads from modifying the same value and writing it back concurrently.
4. volatile give concurrent access to threads without lock, but then using synchronized will allow only one thread to get access to this and all the synchronized methods in the class.
5. And using both volatile and synchronized will do this....
volatile - will reflect the changed values to thread, and prevent caching,
synchronized - But using synchronized keyword, will make sure that only one thread gets the access to the synchronized methods of the class.
You will not always get the most actual count when calling getCount(). An AtomicInteger could be appropriate for you.
There wouldn't be a performance gain from using both. Volatile guarantees that the value of a variable will be consistent when reading/writing to the variable across threads executing in parallel by preventing caching. Synchronized, when applied to a method (as you do in your example), only allows a single thread to enter that method at a time and blocks others until execution is complete.
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.
Does a variable that is accessed by multiple threads, but only inside synchronized blocks, need the volatile modifier? If not, why?
You do not need to use volatile inside of synchronized, synchronized already guarantees the correct behavior for local caching of variables when used consistently (on every access).
volatile works on primitive values, and can be a nice shortcut for atomic accesses to a primitive type. Note that the behavior of volatile has changed in JDK 5 from 1.4.
More information can be found here
No. When you work within a synchronized block, all cached variables are synchronized on access, since it creates a memory barrier.
For details, see this comparison (with discussion) of volatile to synchronized.
Blocks that synchronize on the same object (or method) are guaranteed to not be run at the same time. So as long as you synchronize to the same object, your variable will never have concurrent accesses, so it doesn't need special treatment.
If your accesses aren't synchronized, then you have a race condition. Making the variable volatile can be correct for some primitive variables (I defer to other posts for better info on volaitle). If that isn't useful, you almost certainly have a bug.