我正在研究 java 中同步和 volatile 变量的工作方式,我遇到了一个名为 read and write barrier 的概念。谁能帮我理解这些术语的含义
4 回答
(上面的答案很完整),我只是想用一个简单的方案来演示这个概念
Thread 1 Thread 2
|
|
| |
| |
| Everything Thread 1 |
| wrote before here |
| |
| |
_ _ _ _ _ _ _ _ _ _ |
( write barrier) (happens before) (read barrier) |
| _ _ _ _ _ _ _ _
|
| is guaranteed |
| to be visible to |
| Thread 2 |
| |
内存屏障是代码中的概念“线”,它阻止编译器进行某些优化,并可能向处理器插入特殊的“同步”命令。通常,编译器可以查看特定方法,并看到某些指令可以在不改变代码含义的情况下移动。例如,如果您有
int x = 0, y = 0;
x++;
y++;
如果编译器认为有一些好处,它可以改为输出代码
y++;
x++;
但是,如果x
和y
是某个类中的字段,以便可以从其他线程看到它们,则其他线程可能会在您的方法运行时修改值。
内存屏障强制编译器重新检查特定变量的值(在 Java 中,这些是那些volatile
和Atomic*
类),以防其他线程在方法运行时修改了它们,并且它阻止编译器进行重新排序,这可能不小心改变了计算结果。在支持多个内核/处理器的系统上,编译器还将强制处理器检查以确保其他一些处理器或硬件设备在此期间没有修改变量。Java(从 Java 5 开始)有一套非常明确的规则来说明其工作方式,称为发生前。
此常见问题解答包含一些有用的解释,这些解释是在开发 Java 内存模型时编写的。请注意,虽然内存屏障的概念是跨语言的,但大多数语言没有像 Java 那样明确定义的规则。
当你输入一个同步的代码块时,你通过了“读屏障”,当它退出时,你通过了“写屏障”。
Is 用于引用 volatile 属性,并在线程需要更新其 volatile 属性值时给出指示。如果其他人通过了写屏障,他们应该在通过读屏障时更新它。
对 volatile 属性的类似读取使您的线程通过读屏障,而写入 volatile 属性使您通过写屏障,因此比同步块更细粒度。
JVM 使用读写屏障在最低级别实现 Java 内存模型的语义。
但是,Java 语言规范中没有该术语,它仅根据发生前的关系进行推理。尤其是
- 对 volatile 变量的写入发生在随后读取同一变量之前
- 退出同步块发生在同一同步块的后续条目之前
当您的程序中的两个动作之间存在发生前的关系时,您可以保证这两个动作将以连续一致的顺序执行(即好像只有一个线程并且没有不直观的重新排序)。
编写正确的多线程程序不需要深入研究 JVM 的实现细节。但是,如果您想了解血淋淋的细节,那么JSR-133 食谱是一本有趣的读物。