Reputation: 337
This might have been answered before, but because of the complexity of the issue, I need a confirmation. So I rephrase the question
Question 1 : When a thread enters a synchronized block, the memory barrier will include any fields touched, not just fields of the object that I synchronized on? So if many many objects are modified inside a synchronized block, that's a lot of memory moves between thread memory caches.
Thread 1
object.field1 = "";
synchronized (lock) {
farAwayObject.field1 = "";
farAwayObject.evenFarther.field2 = "";
}
Thread 2. assuming thread ordering is correct
synchronized (lock) {
//thread 2 guaranteed to see all fields above as ""
//even object.field1 ?
}
Question 2 : Is object.field1 = "";
in thread 1 implicitly part of the happens-before relationship?
I hope it is but It might not. If not is there a trick to make it so without putting it into the sync block? It is hard to reason on the program otherwise and it is not practical to put everything under the synchronized { }.
EDIT: clarification: object.field1 is not volatile and the question is "will thread 2 guaranteed to see the write of thread 1, at least ". My question is about memory visibility. For the sake of the argument, let's say only thread 1 writes to non volatile object.field1.
The question 2 can be rephrased as
"Will a synchronized block on a lock push changes made before to be seen by other threads synchronizing on the same lock? "
Upvotes: 4
Views: 1090
Reputation: 15212
When a thread enters a synchronized block, the memory barrier will include any fields touched, not just fields of the object that I synchronized on
Assuming that the fields of farAwayObject
and evenFarther
are always modified and accesed by obtaining a lock
on the same object all around your application, all threads will always see the updates made to farAwayObject
and evenFarther
since synchronized
enforces a happens-before condition.
//thread 2 guaranteed to see all fields above as ""
The same cannot be said for object.field1
without knowing how it was declared. Assuming that field1
is a reference not marked as volatile
, it will not be a part of the happens before relationship and threads may see stale values for it.
I hope it is but It might not. If not is there a trick to make it so without putting it into the sync block?
Yes. Mark object.field1
as volatile
.
Addresing your edit :
The question 2 can be rephrased as
"Will a synchronized block on a lock push changes made before to be seen by other threads synchronizing on the same lock? "
AFAIK the answer is Yes, provided that the writing threads acquire the lock before the reading threads. Unfortunately, this is something you generally can't guarantee and that's why object.field1
needs to be marked as volatile
or the statement needs to moved inside the synchronized
block.
Take a look at JSR 133 which talks about the cache being flushed to main memory when the thread exits a syncronized
block. This should clarify things further.
Upvotes: 2
Reputation:
the memory barrier will include any fields touched, not just fields of the object that I synchronized on?
Yes.
Is object.field1 = ""; in thread 1 implicitly part of the happens-before relationship?
Yes, even if it is not volatile.
The happens-before order is a partial order.
The happens-before order is given by the transitive closure of synchronizes-with edges and program order. It must be a valid partial order: reflexive, transitive and antisymmetric.
Actions before a synchronization edge (i.e. The release of the synchronized lock) are ordered by program order and thus synchronized with the release. Transitivity says that actions that are ordered by an acquire of the same lock in another thread therefore has a happens-before order with both the release of that lock AND the actions preceding the release of that lock, whether or not it is inside the body of the synchronized
block. The important thing to remember about this is that ordering occurs on actions (i.e. Acquire/release of a lock) not a block such as implied by the brackets of the synchronized keyword. The brackets indicate the position of the acquire/release actions as well as where a set of actions cannot be interleaved.
Finally, remember that happens-before is a "partial" order. It means:
synchronized
block as long as the write comes before the block and the read comes after the block). Stronger ordering guarantees also follow happens before ordering, but they also provide additional effects described in the spec.Upvotes: 1
Reputation: 718788
1) When a thread enters a synchronized block, the memory barrier will include any fields touched, not just fields of the object that I synchronized on?
Correct. (Assuming that thread 1 and thread 2 synchronize on the same lock.)
So if many many objects are modified inside a synchronized block, that's a lot of memory moves between thread memory caches.
Potentially, yes. However, it is (probably) not movement between caches. More likely, it is a movement from one processor's cache to memory, and from memory to a second processor's cache. Of course, that depends on how the hardware implements the memory hierarchy.
2) Is object.field1 = ""; in thread 1 implicitly part of the happens-before relationship?
There is a chain of happens-before relations
object.field1
happens before the lock is acquired.farAwayObject
and so on.object.field1
.The problem is what happens if there is an intervening write to object.field1
, either before the lock
is acquired by thread 1, or by some other thread. In either of those cases, the happens-before chain is not sufficient to ensure that thread 2 sees the value that was written by thread 1.
Upvotes: 3