当前位置: 首页 > 知识库问答 >
问题:

Java内存模型保证易失性

解翰采
2023-03-14

我对易变语义几乎没有疑问
假设有三个线程T1、T2和T3,以及给定类的一个实例。

class Foo {
    private int x = 1;
    private int y = 2;
    private int z = 3;
    private volatile int w = 4;
    private volatile int v = 5;

    public void setX(int x) {
        this.x = x;
    }

    public int getX() {
        return this.x;
    }

    (...)
}

假设发生以下读/写操作序列:

1. (T1) foo.getX(); // stored in a local memory of T1
2. (T1) foo.getY(); // stored in a local memory of T1

3. (T2) foo.setX(10);
4. (T2) foo.setY(20);

5. (T3) foo.getY(); // T3 may see 2 or 20, no guarantees if a write action from point 4 is visible to T3
6. (T3) foo.setZ(30);
7. (T3) foo.setW(40);
8. (T3) foo.setV(50);

9. (T1) foo.getW()
10. (T1) foo.getZ()
11. (T1) foo.getY()
12. (T1) foo.getX()

我知道可以保证点9的T1将看到点7的值,点10的T1将看到点6的值(确切地说,至少和这个值一样最新)。

但是,这些说法是真的吗?

  1. Java内存模型保证,点11处的T1将看到至少与点5处的T3相同的最新值(来自T3或更实际的本地内存的值,但即使共享内存中有更实际的值,T1也可能看不到)

请确认我的理解是正确的。

共有1个答案

王高超
2023-03-14

只要get/set操作只获取并设置变量,那么所有的假设都是正确的。

在Java中,变量存储在内存中。但编译器(和运行时)将允许变量临时存储在CPU缓存中,以便在算法或代码段的持续时间内更快地读取和写入。

这种缓存的缺点是,当内核处理完变量后,它会将其写回内存,就像只更新了一次一样。其他内核在使用变量时看不到该变量的状态。更糟糕的是,没有顺序保证何时将其写回内存

通过将变量设置为Volatile,可以告诉java不允许将该变量放入任何缓存中。必须在内存中读取或写入变量。

这意味着Volatile将对变量atomic执行单个操作。但它也会使变量的长时间操作慢得多。因此,volatile并不是从多线程代码中获得性能提升的解决方案。

值得注意的是,需要一次以上读取或写入的操作不是原子操作。例如,i实际上是i=i 1,可以在写入完成之前更改i的值。

如果您需要保证操作以原子方式进行,您可以使用锁或塞姆特克斯(慢),或者您可以使用像写时复制(COW)这样的巧妙范例来允许原子读取和原子写入。

 类似资料:
  • 我想澄清发生前关系是如何与不稳定变量一起工作的。让我们有以下变量: 和线程A: 和线程B: 根据Java内存模型(JMM),以下语句是否正确?如果不是,正确的解释是什么? 总是发生-之前 在JMM中发生在之前,只有当它实际发生在时间之前 在JMM中发生在之前(并且将被可预测地分配)如果实际发生在

  • 规范了Java虚拟机与计算机内存是如何协调工作的,规定了一个线程如何及何时能看到其他线程修改过的共享变量,在必须时如何同步地访问共享变量,控制线程本地内容和共享内容之间的同步。 2. 同步八种操作 操作 定义 lock(锁定) unlock(解锁) read(读取) load(载入) use(使用) assign(赋值) store(存储) write(写入) 3. 同步规则 Read和Load之

  • 在《有效Java》一书中: 后台线程不会在一秒钟后停止。因为提升,在JVM中优化,HotSpot服务器VM做。 您可以在以下主题中查看这一点: 为什么HotSpot会使用提升优化以下内容?。 优化过程如下: 有两种方法可以解决这个问题。 volatile的函数是 -禁止提升 -它保证任何读取该字段的线程都会看到最近写入的值 上面的代码在有效Java书中是正确的,它相当于使用来装饰。 如果此方法忽略

  • 问题内容: 我想说明 先发生的 关系如何与 volatile 变量一起使用。让我们有以下变量: 和线程A: 和线程B: 根据Java内存模型(JMM),以下语句正确吗? 如果没有,正确的解释是什么? 总是在 发生之前 __仅在JMM中实际发生时才 发生- 在JMM中 __ 如果实际上发生在时间之前,则发生在JMM中-before -before (并且将可预测地分配) 否则,和之间的顺序不确定,并

  • 使用包含Scala和Akka在内的Typesafe平台的主要好处是它简化了并发软件的编写过程。本文将讨论Typesafe平台,尤其是Akka是如何在并发应用中访问共享内存的。 Java内存模型 在Java 5之前,Java内存模型(JMM)定义是有问题的。当多个线程访问共享内存时很可能得到各种奇怪的结果,例如: 一个线程看不到其它线程所写入的值:可见性问题 由于指令没有按期望的顺序执行,一个线程观

  • 一、Java内存区域 方法区(公有): 用户存储已被虚拟机加载的类信息,常量,静态常量,即时编译器编译后的代码等数据。异常状态 OutOfMemoryError 其中包含常量池:用户存放编译器生成的各种字面量和符号引用。 堆(公有): 是JVM所管理的内存中最大的一块。唯一目的就是存放实例对象,几乎所有的对象实例都在这里分配。Java堆是垃圾收集器管理的主要区域,因此很多时候也被称为“GC堆”。异