in an example like this:
...
public void foo() {
...
synchronized (lock) {
varA += some_value;
}
...
}
...
The question is, does varA must be declared volatile in order to prevent per-thread caching or it is enough to access it only within synchronized blocks?
Thanks!
No, you don't need to.
synchronized blocks imply a memory barrier.
From JSR-133:
But there is more to synchronization than mutual exclusion. Synchronization ensures that memory writes by a thread before or during a synchronized block are made visible in a predictable manner to other threads which synchronize on the same monitor. After we exit a synchronized block, we release the monitor, which has the effect of flushing the cache to main memory, so that writes made by this thread can be visible to other threads. Before we can enter a synchronized block, we acquire the monitor, which has the effect of invalidating the local processor cache so that variables will be reloaded from main memory. We will then be able to see all of the writes made visible by the previous release.
So long as every access to it is from within a synchronized block then you are fine.
There is a memory barrier associated with each synchronized block that will make sure the variables accessed within are exposed correctly.
Related
In the following simple scenario:
class A {
int x;
Object lock;
...
public void method(){
synchronized(lock){
// modify/read x and act upon its value
}
}
}
Does x need to be volatile? I know that synchronized guarantees atomicity, but I am not sure about visibility though... does lock -> modify -> unlock -> lock guarantee, that after the second lock the value of x will be "fresh"?
No it does not, because synchronized already has a memory barrier inserted after it, so all threads will see the update that the current thread performs, taking into account that the other threads will synchronize on the same lock.
Volatile, just like synchronized, has memory barriers that are attached to it - depending on the CPU, it is store/load/full barrier that ensures that an update from one thread is visible to the other(s). I assume this is performed with CPU cache invalidation.
EDIT
From what I've just read, the store buffers are flushed to the CPU cache, and this is how the visibility is achieved.
Simplified answer: If thread A updates a field and then releases a lock, then thread B will be guaranteed to see the update after thread B has acquired the same lock.
Note, "release a lock" means exit a synchronized block, and "acquire the same lock" means synchronize on the same object.
I'm trying to understand the need for volatile in double-checked locking (I'm aware there are better ways than DCL though) I've read a few SO questions similar to mine, but none seem to explain what I'm looking for. I've even found some upvoted answers on SO that have said volatile is not needed (even when the object is mutable) however, everything I've read says otherwise.
What I want to know is why volatile is necessary in DCL if synchronized creates a happens-before relationship and prevents reordering?
Here is my understanding of how DCL works and an example:
// Does not work
class Foo {
private Helper helper = null; // 1
public Helper getHelper() { // 2
if (helper == null) { // 3
synchronized(this) { // 4
if (helper == null) { // 5
helper = new Helper(); // 6
} // 7
} // 8
} // 9
return helper; // 10
}
This does not work because the Helper object is not immutable or volatile and we know that
volatile causes every write to be flushed to memory and for every read to come from memory. This is important so that no thread sees a stale object.
So in the example I listed, it's possible for Thread A to begin initializing a new Helper object at Line 6. Then Thread B comes along and see a half initialized object at line 3. Thread B then jumps to line 10 and returns a half initialized Helper object.
Adding volatile fixes this with a happens before relationship and no reordering can be done by the JIT compiler. So the Helper object cannot be written to the helper reference until it is fully constructed (?, at least this is what I think it is telling me...).
However, after reading JSR-133 documentation, I became a bit confused. It states
Synchronization ensures that memory writes by a thread before or
during a synchronized block are made visible in a predictable manner
to other threads which synchronize on the same monitor. After we exit
a synchronized block, we release the monitor, which has the effect of
flushing the cache to main memory, so that writes made by this thread
can be visible to other threads. Before we can enter a synchronized
block, we acquire the monitor, which has the effect of invalidating
the local processor cache so that variables will be reloaded from main
memory. We will then be able to see all of the writes made visible by
the previous release.
So synchronized in Java creates a memory barrier and a happens before relationship.
So the actions are being flushed to memory, so it makes me question why volatile is needed on the variable.
The documentation also states
This means that any memory operations which were visible to a thread
before exiting a synchronized block are visible to any thread after it
enters a synchronized block protected by the same monitor, since all
the memory operations happen before the release, and the release
happens before the acquire.
My guess as to why we need the volatile keyword and why synchronize is not enough, is because the memory operations are not visible to other threads until Thread A exits the synchronized block and Thread B enters the same block on the same lock.
It's possible that Thread A is initializing the object at line 6 and Thread B comes along at Line 3 before there is a flush by Thread A at Line 8.
However, this SO answer seems to contradict that as the synchronized block prevents reordering "from inside a synchronized block, to outside it"
If helper is not null, what ensures that the code will see all the effects of the construction of the helper? Without volatile, nothing would do so.
Consider:
synchronized(this) { // 4
if (helper == null) { // 5
helper = new Helper(); // 6
} // 7
Suppose internally this is implemented as first setting helper to a non-null value and then calling the constructor to create a valid Helper object. No rule prevents this.
Another thread may see helper as non-null but the constructor hasn't even run yet, much less made its effects visible to another thread.
It is vital not to permit any other thread to see helper set to a non-null value until we can guarantee that all consequences of the constructor are visible to that thread.
By the way, getting code like this correct is extremely difficult. Worse, it can appear to work fine 100% of the time and then suddenly break on a different JVM, CPU, library, platform, or whatever. It is generally advised that writing this kind of code be avoided unless proven to be needed to meet performance requirements. This kind of code is hard to write, hard to understand, hard to maintain, and hard to get right.
#David Schwartz's answer is pretty good but there is one thing that I'm not sure is stated well.
My guess as to why we need the volatile keyword and why synchronize is not enough, is because the memory operations are not visible to other threads until Thread A exits the synchronized block and Thread B enters the same block on the same lock.
Actually not the same lock but any lock because locks come with memory barriers. volatile is not about locking but it is around crossing memory barriers while synchronized blocks are both locks and memory barriers. You need the volatile because even though Thread A has properly initialized the Helper instance and published it to helper field, Thread B needs to also cross a memory barrier to ensure that it sees all of the updates to Helper.
So in the example I listed, it's possible for Thread A to begin initializing a new Helper object at Line 6. Then Thread B comes along and see a half initialized object at line 3. Thread B then jumps to line 10 and returns a half initialized Helper object.
Right. It is possible that Thread A might initialize the Helper and publish it before it hits the end of the synchronized block. There is nothing stopping it from happening. And because the JVM is allowed to reorder the instructions from the Helper constructor until later, it could be published to helper field but not be fulling initialized. And even if Thread A does reach the end of the synchronized block and Helper then gets fully initialized, there is still nothing that ensures that Thread B sees all of the updated memory.
However, this SO answer seems to contradict that as the synchronized block prevents reordering "from inside a synchronized block, to outside it"
No, that answer is not contradictory. You are confusing what happens with just Thread A and what happens to other threads. In terms of Thread A (and central memory), exiting the synchronized block makes sure that Helper's constructor has fully finished and published to the helper field. But this means nothing until Thread B (or other threads) also cross a memory barrier. Then they too will invalidate the local memory cache and see all of the updates.
That's why the volatile is necessary.
Lets say I have two threads A and B and inside these both 2 threads I have synchronized block in which an int variable is modified continously.
For example, thread A enter synchronized block modify int variable then call these 2 methods:
notifyall(); //to wake thread B which is in waiting state and
wait():
and after that thread B acquire lock and do same steps as thread A and process keep on repeating. All changes to int variable happens inside synchronized block of both threads.
My question is do I need to make int variable volatile. Do thread flush to main memory before they go to waiting state and reload data in registers when thread acquire lock again as a result of notifyall(); call.
If A and B run alternatively rather than concurrently, and if they switch off via wait() and notifyAll() invocations on the same Object, and if no other threads access the variable in question, then thread safety does not require the variable to be volatile.
Note that o.wait() and o.notifyAll() must be invoked inside a method or block synchronized on o -- that synchronization is sufficient to ensure that the two threads see all each others' writes to any variable before the switch-off.
Do be careful to ensure that the two threads are synchronizing on the same object, which is not clear from your question. You have no effective synchronization at all if, say, the two threads are waiting on and notifying different instances of the same class.
The answer is no you do not need to make the variable volatile. The reasoning being, writes that occur to a variable within a synchronized block will be visible to subsequent threads entering a synchronized block on the same object.
So it has the same memory semantics as a volatile read and write.
Not sure about java. But in C: https://www.kernel.org/doc/Documentation/volatile-considered-harmful.txt
If shared_data were declared volatile, the locking would still be
necessary. But the compiler would also be prevented from optimizing access
to shared_data within the critical section, when we know that nobody else
can be working with it. While the lock is held, shared_data is not
volatile. When dealing with shared data, proper locking makes volatile
unnecessary - and potentially harmful.
When we say we lock on an object using the synchronized keyword, does it mean we are acquiring a lock on the whole object or only at the code that exists in the block?
In the following example listOne.add is synchronized, does it mean if another thread accesses listOne.get it would be blocked until the first thread gets out of this block? What if a second thread accesses the listTwo.get or listTwo.add methods on the instance variables of the same object when the first thread is still in the synchronized block?
List<String> listONe = new ArrayList<String>();
List<String> listTwo = new ArrayList<String>();
/* ... ... ... */
synchronized(this) {
listOne.add(something);
}
Given the methods:
public void a(String s) {
synchronized(this) {
listOne.add(s);
}
}
public void b(String s) {
synchronized(this) {
listTwo.add(s);
}
}
public void c(String s) {
listOne.add(s);
}
public void d(String s) {
synchronized(listOne) {
listOne.add(s);
}
}
You can not call a and b at the same time, as they are locked on the same lock.
You can however call a and c at the same time (with multiple threads obviously) as they are not locked on the same lock. This can lead to trouble with listOne.
You can also call a and d at the same time, as d is no different in this context from c. It does not use the same lock.
It is important that you always lock listOne with the same lock, and allow no access to it without a lock. If listOne and listTwo are somehow related and sometimes need updates at the same time / atomically you'd need one lock for access to both of them. Otherwise 2 separate locks may be better.
Of course, you'd probably use the relatively new java.util.concurrent classes if all you need is a concurrent list :)
The lock is on the object instance that you include in the synchronized block.
But take care! That object is NOT intrinsically locked for access by other threads. Only threads that execute the same synchronized(obj), where obj is this in your example but could in other threads also be a variable reference, wait on that lock.
Thus, threads that don't execute any synchronized statements can access any and all variables of the 'locked' object and you'll probably run into race conditions.
Other threads will block only on if you have a synchronized block on the same instance. So no operations on the lists themselves will block.
synchronized(this) {
will only lock the object this. To lock and work with the object listOne:
synchronized(listOne){
listOne.add(something);
}
so that listOne is accessed one at a time by multiple threads.
See: http://download.oracle.com/javase/tutorial/essential/concurrency/locksync.html
You need to understand that the lock is advisory and is not physically enforced. For example if you decided that you where going to use an Object to lock access to certain class fields, you must write the code in such a way to actually acquire the lock before accessing those fields. If you don't you can still access them and potentially cause deadlocks or other threading issues.
The exception to this is the use of the synchronized keyword on methods where the runtime will automatically acquire the lock for you without you needing to do anything special.
The Java Language specification defines the meaning of the synchronized statement as follows:
A synchronized statement acquires a mutual-exclusion lock (ยง17.1) on behalf of the executing thread, executes a block, then releases the lock. While the executing thread owns the lock, no other thread may acquire the lock.
SynchronizedStatement:`
synchronized ( Expression ) Block`
The type of Expression must be a reference type, or a compile-time error occurs.
A synchronized statement is executed by first evaluating the Expression.
If evaluation of the Expression completes abruptly for some reason, then the synchronized statement completes abruptly for the same reason.
Otherwise, if the value of the Expression is null, a NullPointerException is thrown.
Otherwise, let the non-null value of the Expression be V. The executing thread locks the lock associated with V. Then the Block is executed. If execution of the Block completes normally, then the lock is unlocked and the synchronized statement completes normally. If execution of the Block completes abruptly for any reason, then the lock is unlocked and the synchronized statement then completes abruptly for the same reason.
Acquiring the lock associated with an object does not of itself prevent other threads from accessing fields of the object or invoking unsynchronized methods on the object. Other threads can also use synchronized methods or the synchronized statement in a conventional manner to achieve mutual exclusion.
That is, in your example
synchronized(this) {
listOne.add(something);
}
the synchronized block does treat the object referred to by listOne in any special way, other threads may work with it as they please. However, it ensures that no other thread may enter a synchronized block for the object referred to by this at the same time. Therefore, if all code working with listOne is in synchronized blocks for the same object, at most one thread may work with listOne at any given time.
Also note that the object being locked on gets no special protection from concurrent access of its state, so the code
void increment() {
synchronized (this) {
this.counter = this.counter + 1;
}
}
void reset() {
this.counter = 0;
}
is incorrectly synchronized, as a second thread may execute reset while the first thread has read, but not yet written, counter, causing the reset to be overwritten.
Does the following variable, x, need to be volatile?
Or does the manipulation within a utils.concurrent lock perform the same function as a synchronized block (ensuring it's written to memory, and not stored in cpu cache)?
myMethod(){
myLock.lock();
x++;
myLock.unlock();
}
Such variables only need to be volatile if they're accessed elsewhere without a lock. For example, as a fast read-only access to a size variable. The lock methods do serve the same purpose as a synchronized block. See the "Memory Synchronization" section in the javadoc for the Lock class.