jjzjj

java - 相对于其他字段的易变语义

coder 2023-08-31 原文

假设我有以下代码

private volatile Service service;

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

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

标记为易变的修改字段,其值不依赖于先前的状态。所以,这是正确的多线程代码(暂时不要为 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(写入对象引用是原子的),因此您可以通过任何一种方式将其从关注列表中划掉——唯一 Unresolved 问题是更改的可见性和“正确性”顺序。

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

我们可以通过查看 section 17.4.5 of the Java Language Specification 来详细解释这一点,具体有以下几个要点:

  1. “如果 x 和 y 是同一线程的 Action ,并且 x 在程序顺序中出现在 y 之前,则 hb(x, y)”(即,同一线程上的 Action 不能以与程序顺序)
  2. “写入可变字段 (§8.3.1.4) 发生在该字段的每次后续读取之前。” (这是澄清文本,解释了 volatile 字段的先写后读是一个同步点)
  3. “如果 hb(x, y) 和 hb(y, z),则 hb(x, z)”(happens-before 的传递性)

所以在你的例子中:

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

这意味着您可以保证“服务”设置正确,在这种情况下,一旦 serviceReady 为真。

您可以看到一些很好的文章使用几乎完全相同的例子,一个在IBM DeveloperWorks -- 参见“对 Volatile 的新保证”:

values that were visible to A at the time that V was written are guaranteed now to be visible to B.

还有一个在 the JSR-133 FAQ ,由该 JSR 的作者编写:

Thus, if the reader sees the value true for v, it is also guaranteed to see the write to 42 that happened before it. This would not have been true under the old memory model. If v were not volatile, then the compiler could reorder the writes in writer, and reader's read of x might see 0.

关于java - 相对于其他字段的易变语义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1351168/

有关java - 相对于其他字段的易变语义的更多相关文章

  1. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  2. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  3. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  4. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  5. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  6. ruby-on-rails - 在 Rails 和 ActiveRecord 中查询时忽略某些字段 - 2

    我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr

  7. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  8. ruby - 调用其他方法的 TDD 方法的正确方法 - 2

    我需要一些关于TDD概念的帮助。假设我有以下代码defexecute(command)casecommandwhen"c"create_new_characterwhen"i"display_inventoryendenddefcreate_new_character#dostufftocreatenewcharacterenddefdisplay_inventory#dostufftodisplayinventoryend现在我不确定要为什么编写单元测试。如果我为execute方法编写单元测试,那不是几乎涵盖了我对create_new_character和display_invent

  9. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  10. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

随机推荐