Java中同步关键字的记忆效应

Java中同步关键字的记忆效应,java,multithreading,java-memory-model,Java,Multithreading,Java Memory Model,这个问题以前可能已经得到了回答,但由于问题的复杂性,我需要得到确认。所以我重新措辞这个问题 问题1:当线程进入同步块时,内存屏障将包括所接触的任何字段,而不仅仅是我同步的对象的字段?因此,如果在一个同步块中修改了许多对象,那么在线程内存缓存之间会有大量内存移动 Thread 1 object.field1 = ""; synchronized (lock) { farAwayObject.field1 = ""; farAwayObject.evenFarther.field2 = ""

这个问题以前可能已经得到了回答,但由于问题的复杂性,我需要得到确认。所以我重新措辞这个问题

问题1:当线程进入同步块时,内存屏障将包括所接触的任何字段,而不仅仅是我同步的对象的字段?因此,如果在一个同步块中修改了许多对象,那么在线程内存缓存之间会有大量内存移动

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 ?
}
问题2:Is
object.field1=“”隐式地表示关系的一部分在发生之前

我希望是这样,但可能不是这样。如果没有,有没有一个技巧可以让它不进入同步块?否则,很难对该节目进行推理 把所有的东西都放在同步的{}下是不现实的

编辑:澄清:object.field1不是易变的,问题是“线程2是否保证至少看到线程1的写入”。我的问题是关于内存可见性。为了便于讨论,假设只有线程1写入非易失性object.field1

问题2可以重新表述为

“锁上的同步块会将以前所做的更改推送到在同一锁上同步的其他线程看到吗?”

当线程进入同步块时,内存屏障将 包括任何接触的字段,而不仅仅是我所接触的对象的字段 同步于

假设始终通过在应用程序周围的同一对象上获得
锁来修改和访问
farAwayObject
evenverter
的字段,所有线程都将始终看到对
farAwayObject
甚至更远的
所做的更新,因为
synchronized
强制执行一个before条件

//线程2保证将上面的所有字段都视为“”

在不知道如何声明的情况下,
object.field1
也不能这样说。假设
field1
是一个未标记为
volatile
的引用,它将不会成为发生之前关系的一部分,线程可能会看到它的过时值

我希望是这样,但可能不是这样。如果不是的话,有没有一个技巧可以做到这一点 不把它放进同步块

对。将
object.field1
标记为
volatile


添加并重新调整编辑:

问题2可以改为

“锁上的同步块是否会将之前所做的更改推送到 在同一锁上同步的其他线程看到了吗?”

假设写线程在读线程之前获得锁,那么答案是肯定的。不幸的是,这是您通常无法保证的,这就是为什么
object.field1
需要标记为
volatile
,或者语句需要移动到
synchronized
块中的原因

看一看,当线程退出
syncronized
块时,缓存被刷新到主存。这应该进一步澄清问题


1) 当一个线程进入一个同步块时,内存屏障将包括任何接触的字段,而不仅仅是我同步的对象的字段

对。(假设线程1和线程2在同一个锁上同步。)

因此,如果在一个同步块中修改了许多对象,那么在线程内存缓存之间会有大量内存移动

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 ?
}
可能是的。但是,它(可能)不是缓存之间的移动。更可能的是,它是从一个处理器的缓存移动到内存,以及从内存移动到另一个处理器的缓存。当然,这取决于硬件如何实现内存层次结构

2) 是object.field1=“”;在线程1中,是否隐式地将部分事件发生在关系之前

在关系发生之前有一连串的事情发生

  • 写入
    对象.field1
    发生在获取锁之前
  • 这发生在写入
    farAwayObject
    之前,依此类推
  • 这发生在线程1释放锁之前
  • 这发生在线程2获取锁之前
  • 这发生在线程2读取
    object.field1
    之前
  • 问题是,如果在线程1或其他线程获取
    锁之前,对
    对象.field1
    进行了一次中间写入,会发生什么情况。在这两种情况下,before链都不足以确保线程2看到线程1写入的值

    内存屏障将包括所接触的任何字段,而不仅仅是我同步的对象的字段

    是object.field1=“”;在线程1中,是否隐式地将部分事件发生在关系之前

    是的,即使它不易挥发


    发生在顺序之前的是偏序

    同步的传递闭包与边和程序顺序给出了“发生在前”顺序。它必须是一个有效的偏序:自反,传递和反对称

    ()

    同步边缘之前的操作(即同步锁的释放)按程序顺序排序,因此与释放同步。传递性表示,由另一个线程中的同一个锁的获取命令的操作因此在释放该锁和释放该锁之前的操作时都有一个before-before命令,无论它是否在
    synchronized
    块的主体内。关于这一点,需要记住的重要一点是,排序发生在操作(即获取/释放锁)上,而不是像synchronized关键字的括号所暗示的块。括号表示获取/释放操作的位置以及一组操作不能交错的位置

    最后,请记住发生在