问题
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? "
回答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
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
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.
回答2:
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
- The write to
object.field1
happens before the lock is acquired. - That happens before the writes to
farAwayObject
and so on. - That happens before the lock is released by thread 1
- That happens before the lock is acquired by thread 2
- That happens before thread 2 reads
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.
回答3:
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.
(JLS 17.4.7)
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:
- Happens before enforces memory consistency when actions happen to come in the particular order (i.e. release/acquire, write/read, etc)
- Happens before depends on stronger guarantees such as program order to produce the correct functionality.
- Happens before does not prevent errors coming from interleaving of nonatomic actions
- Happens before is the transitive relationship between the action and a strong action. (You can put the read of your shared variable outside the
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.
来源:https://stackoverflow.com/questions/42107083/memory-effects-of-synchronized-keyword-in-java