使用volatile和synchronized时,刷新或发布到各种线程的内存范围是多少? [英] What is the scope of memory flushed or published to various threads when using volatile and synchronized?

查看:117
本文介绍了使用volatile和synchronized时,刷新或发布到各种线程的内存范围是多少?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

This question is in reference to memory visibility only, not happens-before and happens-after. There are four ways in Java that guarantees changes to memory in one thread to be made visible to another thread. (reference http://gee.cs.oswego.edu/dl/cpj/jmm.html)


  1. 写入线程释放同步锁,读取线程随后获取相同的同步锁。

  2. 如果某个字段被声明为volatile,则在写入程序线程执行任何进一步的内存操作之前,写入该文件的任何值都会被写入线程刷新并使其可见(即,为了手头的目的,它会被刷新立即)。

  3. 线程第一次访问对象的字段时,它会看到字段的初始值或者由其他线程写的值。

  4. 当一个线程终止时,所有写入的变量都被刷新到主内存。

  1. A writing thread releases a synchronization lock and a reading thread subsequently acquires that same synchronization lock.
  2. If a field is declared as volatile, any value written to it is flushed and made visible by the writer thread before the writer thread performs any further memory operation (i.e., for the purposes at hand it is flushed immediately).
  3. The first time a thread accesses a field of an object, it sees either the initial value of the field or a value since written by some other thread.
  4. As a thread terminates, all written variables are flushed to main memory.

根据Java Concurrency in Practice,圣经上这样的问题:

According to Java Concurrency in Practice, the bible on such questions:


volatile变量的可见性效果超出了volatile变量本身的值。当线程 A 写入易失性变量并且随后线程 B 读取同一个变量时,可见的所有变量的值在读取volatile变量之后,写入volatile变量之前的 B 可见。

The visibility effects of volatile variables extend beyond the value of the volatile variable itself. When thread A writes to a volatile variable and subsequently thread B reads that same variable, the values of all variables that were visible to A prior to writing to the volatile variable become visible to B after readin the volatile variable.



易变问题



这是否意味着JVM实际上跟踪volatile变量读写,以便知道如何将内存从 A 刷新到 B 而不是 A C ?所以 A 写入变量,后来 C 从变量读取,然后 B 从变量读取,刷新完成 A B A C 之间的每线程基础,但 B C ?或者,它是否暗示所有缓存的内存都被刷新,无论线程如何?只是刷新了易失性变量,还是所有高速缓存的内存?

Volatile question

Does this mean that the JVM actually keeps track of volatile variable reads and writes, in order to know how to flush memory from A to B and not A to C? So A writes to the variable, and later C reads from the variable, and then later B reads from the variable, the flushing is done on a per-thread basis between A and B and A and C, but not B and C? Or, does it imply that all cached memory is flushed, regardless of threads? Are only the volatile variables flushed, or all cached memory?

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

For the synchronized keyword flushing, it says that only memory updated inside the lock is guaranteed to be published to other threads. That implies that in the following code, two threads running method(), leaving the synchronized block will flush staticVar2 to the other thread, but not staticVar1, is that correct?

此外,在 method2(),同步超过 differentLock 可能导致发生 - 如果发生另一个线程正在执行问题之前发生 - code>()的方法。但是,问题在于可见性。如果线程 A 执行方法,则后来的线程 B 执行 method2(),是从 A 发布到 B staticVar2 的值,即使这两个线程没有' t在同一个锁上同步?

Also, in method2(), synchronizing over differentLock can cause happens-before happens-after problems if another thread is executing method(). However, the question is in terms of visibility. If thread A executes method, then later thread B executes method2(), is the value of staticVar2 published from A to B, even though the two threads don't synchronize over the same lock?

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



静态问题



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

Static question

It appears to me that if staticVar1 is never updated to other threads, then all static variables in any program require a volatile declaration, or should only be accessed in synchronized blocks. That seems rather harsh, but is it correct? I've sure seen a whole lot of static variables in my time that aren't synchronized.


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

  2. 当退出同步块时,是否所有更改的内存都被刷新,或者只是块中更改的内存?如果没有刷新所有内存,则线程同步的锁定对象是否必须相同才能看到值(即锁定对象是否对内存可见性有影响)?

  3. 两个线程访问的所有静态变量是否必须同步?


推荐答案

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

There is no scope limitation in terms of memory. When you have a read or write barrier it applies for all memory reads/writes.

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

Where I have seen a limitation is in memory mappings. When you memory map a file you have to be careful how you make this available to another threads as this new memory mapping might not be visible in another thread immediately resulting in a BUS error (and a crash of the JVM) This appears to be a OS bug as the newest versions of Linux and Windows don't appear to have this problem.


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

That implies that in the following code, two threads running method(), leaving the synchronized block will flush staticVar2 to the other thread, but not staticVar1, is that correct?

statixVar1当staticVar2可能更快时,它将永远被刷新。不保证何时,但订单有保证。

statixVar1 will always be flushed when staticVar2 is, perhaps sooner. No guarantee as to when, but the order is guaranteed.


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

If thread A executes method, then later thread B executes method2(), is the value of staticVar2 published from A to B, even though the two threads don't synchronize over the same lock?

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

Yes, the lock used doesn't matter for the happen-before guarantees.


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

Do volatile read-writes flush all memory to all threads, or only between the two accessing threads? Whichever the answer, is all memory flushed or only the volatile variables?

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

All dirty memory is flushed on a write barrier and all reads will be order consistent on a read barrier. volatile performs both a write barrier on a write and a read barrier on a read.


当退出同步块时,是否所有更改的内存都被刷新了,或者只是块内更改的内存?

Is all changed memory flushed when exiting a synchronized block, or just the memory that was changed within the block?

所有的该线程更改了内存。

All of the memory changed by that thread.


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

Do all static variables accessed by two threads have to be synchronized?

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

Only if one thread modifies the variable. Any number of threads can read static values without synchronization.

这篇关于使用volatile和synchronized时,刷新或发布到各种线程的内存范围是多少?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆