12

这个问题仅涉及内存可见性,而不是发生在之前和之后。Java中有四种方法可以保证一个线程中对内存的更改对另一个线程可见。(参考http://gee.cs.oswego.edu/dl/cpj/jmm.html

  1. 写入线程释放同步锁,读取线程随后获取相同的同步锁。
  2. 如果一个字段被声明为易失性,则写入它的任何值都会在写入线程执行任何进一步的内存操作之前被写入线程刷新并使其可见(即,出于手头的目的,它会立即刷新)。
  3. 线程第一次访问对象的字段时,它会看到该字段的初始值或自其他线程写入以来的值。
  4. 当线程终止时,所有写入的变量都被刷新到主内存。

根据Java Concurrency in Practice,有关此类问题的圣经:

volatile 变量的可见性影响超出了 volatile 变量本身的值。当线程A写入 volatile 变量并且随后线程B读取相同的变量时,在写入 volatile 变量之前对A可见的所有变量的值在读取 volatile 变量后对B可见。

不稳定的问题

这是否意味着 JVM 实际上会跟踪 volatile 变量的读取和写入,以便知道如何将内存从A刷新到B而不是AC?所以A写入变量,然后C从变量中读取,然后B从变量中读取,刷新是在AB以及AC之间按线程完成的,但不是 BC?或者,这是否意味着所有缓存的内存都被刷新,而不管线程如何?是仅刷新 volatile 变量,还是所有缓存内存?

同步问题

对于synchronized关键字flushing,它表示只有在锁内更新的内存才能保证发布到其他线程。这意味着在下面的代码中,两个线程运行method(),离开同步块将刷新staticVar2到另一个线程,但不是 staticVar1,对吗?

此外,在 中method2(),如果另一个线程正在执行,则同步结束differentLock可能会导致发生前发生后发生问题method()。但是,问题在于可见性。如果线程A执行method,然后线程B稍后执行,即使两个线程没有在同一个锁上同步,method2()值是staticVar2A发布到B吗?

static int staticVar1, staticVar2;
void method() {
    staticVar1++;
    synchronized (lock) {
        staticVar2++;
    }
}
void method2() {
    synchronized (differentLock) {
        staticVar2++;
    }
}

静态问题

在我看来,如果staticVar1从未更新到其他线程,那么任何程序中的所有静态变量都需要volatile声明,或者只能在synchronized块中访问。这似乎相当苛刻,但它是正确的吗?我确实在我的时间里看到了很多不同步的静态变量。

总之

  1. 易失性读写是否将所有内存刷新到所有线程,还是仅在两个访问线程之间?无论答案是什么,是所有内存都被刷新还是只有 volatile 变量?
  2. 退出同步块时是否会刷新所有更改的内存,还是仅刷新块内更改的内存?如果不是所有内存都被刷新,线程同步的锁对象是否必须相同才能看到值(即锁对象对内存可见性有任何影响)?
  3. 两个线程访问的所有静态变量都必须同步吗?
4

1 回答 1

6

在内存方面没有范围限制。当您有读或写屏障时,它适用于所有内存读/写。

我看到的限制是内存映射。当您对文件进行内存映射时,您必须小心如何将其提供给另一个线程,因为这个新的内存映射可能在另一个线程中不可见,这会立即导致 BUS 错误(以及 JVM 崩溃) 这似乎是操作系统错误作为最新版本的 Linux 和 Windows 似乎没有这个问题。

这意味着在下面的代码中,两个线程运行 method(),离开同步块会将 staticVar2 刷新到另一个线程,但不会刷新 staticVar1,对吗?

statixVar1 将始终在 staticVar2 时刷新,也许更快。不保证什么时候,但保证顺序。

如果线程 A 执行方法,然后线程 B 执行 method2(),即使两个线程没有在同一个锁上同步,staticVar2 的值是否从 A 发布到 B?

是的,使用的锁对于发生前的保证无关紧要。

易失性读写是否将所有内存刷新到所有线程,还是仅在两个访问线程之间?无论答案是什么,是所有内存都被刷新还是只有 volatile 变量?

所有脏内存都在写屏障上刷新,所有读取将在读屏障上保持顺序一致。 volatile在写入时执行写入屏障,在读取时执行读取屏障。

退出同步块时是否会刷新所有更改的内存,还是仅刷新块内更改的内存?

该线程更改的所有内存。

两个线程访问的所有静态变量都必须同步吗?

仅当一个线程修改变量时。任意数量的线程都可以在不同步的情况下读取静态值。

于 2013-06-11T10:06:02.700 回答