简体   繁体   English

Java中synchronized关键字的记忆效应

[英]Memory effects of synchronized keyword in Java

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?问题 1 :当一个线程进入一个同步块时,内存屏障将包括任何触及的字段,而不仅仅是我同步的对象的字段? 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 = "";问题2 :是object.field1 = ""; in thread 1 implicitly part of the happens-before relationship?在线程 1 中隐含地是发生之前关系的一部分?

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 ".编辑:澄清:object.field1 不是易失性的,问题是“线程 2 至少会保证看到线程 1 的写入”。 My question is about memory visibility.我的问题是关于内存可见性。 For the sake of the argument, let's say only thread 1 writes to non volatile object.field1.为了论证,假设只有线程 1 写入非易失性 object.field1。

The question 2 can be rephrased as问题2可以改写

"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? 1)当一个线程进入一个同步块时,内存屏障将包括任何触及的字段,而不仅仅是我同步的对象的字段?

Correct.正确的。 (Assuming that thread 1 and thread 2 synchronize on the same lock.) (假设线程 1 和线程 2 在同一个锁上同步。)

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 = ""; 2) 是 object.field1 = ""; in thread 1 implicitly part of the happens-before relationship?在线程 1 中隐含地是发生之前关系的一部分?

There is a chain of happens-before relations有一连串发生在之前的关系

  1. The write to object.field1 happens before the lock is acquired.object.field1的写入发生在获取锁之前。
  2. That happens before the writes to farAwayObject and so on.这发生在写入farAwayObject等之前。
  3. That happens before the lock is released by thread 1这发生在线程 1 释放锁之前
  4. That happens before the lock is acquired by thread 2这发生在线程 2 获取锁之前
  5. That happens before thread 2 reads object.field1 .这发生在线程 2 读取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.问题是如果在线程 1 或其他线程获取lock之前对object.field1进行干预写入会发生什么情况。 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.在任何一种情况下,happens-before 链都不足以确保线程 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当一个线程进入一个同步块时,内存屏障将包括任何接触的字段,而不仅仅是我同步的对象的字段

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.假设farAwayObjectevenFarther的字段总是通过在应用程序周围的同一个对象上获得lock来修改和访问,所有线程将始终看到对farAwayObjectevenFarther所做的更新,因为synchronized强制发生先发生条件。

//thread 2 guaranteed to see all fields above as ""

The same cannot be said for object.field1 without knowing how it was declared.如果不知道object.field1是如何声明的,就不能object.field1说同样的话。 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.假设field1是一个没有标记为volatile的引用,它不会是关系和线程可能看到它的陈旧值之前发生的一部分。

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 .object.field1标记为volatile


Addresing your edit :解决您的编辑:

The question 2 can be rephrased as问题2可以改写为

"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. AFAIK 答案是肯定的,前提是写入线程在读取线程之前获取锁。 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.不幸的是,这是您通常无法保证的,这就是为什么object.field1需要标记为volatile或者语句需要移动到synchronized块中的原因。

Take a look at JSR 133 which talks about the cache being flushed to main memory when the thread exits a syncronized block.看看JSR 133 ,它讨论了当线程退出syncronized块时缓存被刷新到主内存。 This should clarify things further.这应该进一步澄清事情。


the memory barrier will include any fields touched, not just fields of the object that I synchronized on?内存屏障将包括任何触及的字段,而不仅仅是我同步的对象的字段?

Yes.是的。

Is object.field1 = "";是 object.field1 = ""; in thread 1 implicitly part of the happens-before relationship?在线程 1 中隐含地是发生之前关系的一部分?

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 ) ( JLS 17.4.7 )

Actions before a synchronization edge (ie 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.传递性表示在另一个线程中通过获取相同锁来排序的操作因此具有先发生顺序,释放该锁和释放该锁之前的操作,无论它是否在synchronized块。 The important thing to remember about this is that ordering occurs on actions (ie Acquire/release of a lock) not a block such as implied by the brackets of the synchronized keyword.关于这一点要记住的重要一点是,排序发生在动作(即获取/释放锁)上,而不是像 synchronized 关键字的括号所暗示的块。 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.最后,请记住,happens-before 是一个“部分”顺序。 It means:它的意思是:

  1. Happens before enforces memory consistency when actions happen to come in the particular order (ie release/acquire, write/read, etc)当操作以特定顺序(即释放/获取、写入/读取等)发生时,发生在强制执行内存一致性之前
  2. Happens before depends on stronger guarantees such as program order to produce the correct functionality.发生之前取决于更强的保证,例如程序顺序来产生正确的功能。
  3. Happens before does not prevent errors coming from interleaving of nonatomic actions发生在之前并不能防止来自非原子操作交错的错误
  4. Happens before is the transitive relationship between the action and a strong action. Happens before 是动作和强动作之间的传递关系。 (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). (您可以将共享变量的读取放在synchronized块之外,只要写入在块之前并且读取在块之后)。 Stronger ordering guarantees also follow happens before ordering, but they also provide additional effects described in the spec.更强的排序保证也发生在排序之前,但它们也提供了规范中描述的额外效果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM