当前位置: 首页 > 面试题库 >

关于其他领域的易变语义

富涛
2023-03-14
问题内容

假设我有以下代码

private volatile Service service;

public void setService(Service service) {
  this.service = service;
}

public void doWork() {
  service.doWork();
}

标记为volatile的修改字段及其值不取决于先前的状态。因此,这是正确的多线程代码(不要为Service实现而烦恼一分钟)。

据我所知,从内存可见性的角度来看,读取volatile变量就像输入锁一样。这是因为正常变量的读取不能与读取易变变量重新排序

这是否意味着以下代码正确?

private volatile boolean serviceReady = false;
private Service service;

public void setService(Service service) {
  this.service = service;
  this.serviceReady = true;
}

public void doWork() {
  if ( serviceReady ) {
    service.doWork();
  }
}

问题答案:

是的,从Java 1.5开始,此代码是正确的。

无论有无波动,原子性都不是问题(对对象引用的写操作是原子的),因此您可以通过任何一种方式将其从关注列表中剔除-
唯一未解决的问题是更改的可见性和排序的“正确性”。

任何对volatile变量的写操作都会建立“先发生”关系(如JSR-133中所指定的新Java内存模型的关键概念),以及随后对同一变量的读取。这意味着读取线程必须对写入线程可见的所有内容具有可见性:也就是说,它必须在写入时查看所有
至少具有 其“当前”值的变量。

我们可以通过查看Java Language
Specification的17.4.5节来
详细解释这一点,特别是以下要点:

  1. “如果x和y是同一线程的动作,并且x在程序顺序中排在y之前,则hb(x,y)”(即,同一线程上的动作不能以与程序顺序不一致的方式重新排序)
  2. “在以后每次对该字段进行读取之前,都会写入一个易失字段(第8.3.1.4节)。” (这是澄清的文本,解释了易失字段的先写后读是同步点)
  3. “如果hb(x,y)和hb(y,z),则hb(x,z)”(发生之前的传递)

因此,在您的示例中:

  • 由于规则1,对“服务”(a)的写入发生在对“服务就绪”(b)的写入之前
  • 由于规则2,对“ serviceReady”(b)的写入发生在读取相同的(c)之前
  • 因此,(a)发生在(c)之前(第3条规则)

这意味着在serviceReady为true的情况下,可以保证正确设置“ service”。

您可以使用 几乎完全相同 的示例看到一些好的文章,例如在IBM
DeveloperWorks上看到的-
请参阅“新的保证波动性”:

保证在写入V时A可见的值现在对B可见。

以及由该JSR作者撰写的JSR-133
FAQ中的一个:

因此,如果读者看到v的值为true,则也可以保证看到在它之前发生的对42的写入。在旧的内存模型下,情况并非如此。如果v不易变,则编译器可以对writer中的写入进行重新排序,而读者对x的读取可能会看到0。



 类似资料:
  • 以下是经典的实践中的一致性: 当线程A写入一个易失性变量,随后线程B读取相同的变量时,A在写入易失性变量之前可见的所有变量的值在读取易失性变量后变得对B可见。 我不确定我真的能理解这句话。例如,在这种情况下,所有变量的含义是什么?这是否意味着使用对使用非volatile变量也有副作用<在我看来,这句话有一些我无法理解的微妙含义<有什么帮助吗?

  • 问题内容: 当您这样做时: “类”字段到底是什么?我在API文档中找不到它。它是继承的静态字段吗? 我认为保留关键字不允许用作实体名称。 问题答案: 请阅读 : 类文字是由类,接口,数组或原始类型的名称或伪类型void组成的表达式,后跟“。”。和令牌类。类文字的类型C.Class,其中C是类,接口或数组类型的名称,是Class。如果p是原始类型的名称,则令B为装箱转换后的类型p的表达式的类型(第5

  • juttle 是一个 nodejs 项目,专注于数据处理和可视化。它自定义了一套自己的 DSL,提供交互式命令行、程序运行、界面访问三种运行方式。 在 juttle 的 DSL 中,可以用 | 管道符串联下列指令实现数据处理: 通过 read 指令读取来自 http、file、elasticsearch、graphite、influxdb、opentsdb、mysql 等数据源, 通过 filte

  • Grafana是一个开源的指标量监测和可视化工具。常用于展示基础设施的时序数据和应用程序运行分析。Grafana的dashboard展示非常炫酷,绝对是运维提升逼格的一大利器。 官方在线的demo可以在这里找到: http://play.grafana.org/ grafana的套路基本上跟kibana差不多,都是根据查询条件设置聚合规则,在合适的图表上进行展示,多个图表共同组建成一个dashbo

  • ElastAlert 是 Yelp 公司开源的一套用 Python2.6 写的报警框架。属于后来 Elastic.co 公司出品的 Watcher 同类产品。官网地址见:http://elastalert.readthedocs.org/。 安装 比官网文档说的步骤稍微复杂一点,因为其中 mock 模块安装时依赖的 setuptools 要求版本在 0.17 以上,CentOS6 默认的不够,需要

  • 目前 Elasticsearch 虽然以 Elastic Stack 作为主打产品,但其优秀的分布式设计,灵活的搜索评分函数和强大简洁的检索聚合功能,在运维领域也衍生出不少其他有趣的应用方式。 对于 Elastic 公司来说,这些周边应用,也随时可能成为他们的后续目标产品。就在本书第一版编写期间,packetbeat 就被 Elastic 公司收购,并且可能作为未来数据采集端的标准应用。所以,El