Java memory model保证对象的构造和终结器之间存在先行关系:
There is a happens-before edge from the end of a constructor of an object to the start of a finalizer (§12.6) for that object.
以及final字段的构造函数和初始化:
An object is considered to be completely initialized when its constructor finishes. A thread that can only see a reference to an object after that object has been completely initialized is guaranteed to see the correctly initialized values for that object's final fields.
对于 volatile 字段也有保证,因为对于所有对此类字段的访问存在先行关系:
A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.
但是常规的、好的旧的非 volatile 字段呢?我见过很多多线程代码,在使用非 volatile 字段构造对象后,它们不会费心创建任何类型的内存屏障。但我从未见过或听说过任何问题,而且我自己也无法重新创建这样的部分构造。
现代 JVM 是否只是在构建之后设置内存屏障?避免在施工期间重新排序?还是我只是幸运?如果是后者,是否可以随意编写重现部分构造的代码?
编辑:
为了澄清,我说的是以下情况。假设我们有一个类:
public class Foo{
public int bar = 0;
public Foo(){
this.bar = 5;
}
...
}
并且一些线程 T1 实例化了一个新的 Foo 实例:
Foo myFoo = new Foo();
然后将实例传递给其他线程,我们称之为T2:
Thread t = new Thread(() -> {
if (myFoo.bar == 5){
....
}
});
t.start();
T1 执行了我们感兴趣的两次写入:
myFoo 的 barmyFoo 变量对于 T1,我们得到一个 guarantee写#1 发生在之前写#2:
Each action in a thread happens-before every action in that thread that comes later in the program's order.
但就 T2 而言,Java 内存模型不提供此类保证。没有什么能阻止它以相反的顺序看到写入。所以它可以看到一个完全构建的 Foo 对象,但是 bar 字段等于 0。
编辑2:
我在写完上面的例子几个月后又看了一遍。由于 T2 是在 T1 写入之后启动的,因此该代码实际上可以保证正常工作。这使它成为我想问的问题的错误示例。修复它以假定当 T1 执行写入时 T2 已经在运行。假设 T2 正在循环读取 myFoo,如下所示:
Foo myFoo = null;
Thread t2 = new Thread(() -> {
for (;;) {
if (myFoo != null && myFoo.bar == 5){
...
}
...
}
});
t2.start();
myFoo = new Foo(); //The creation of Foo happens after t2 is already running
最佳答案
以您的示例作为问题本身 - 答案是是,这是完全可能的。正如您引用的那样,初始化字段仅对构造线程可见。这称为安全发布(但我打赌你已经知道了)。
事实是您没有通过实验看到这一点是 x86 上的 AFAIK(作为一个强大的内存模型),商店不会重新排序,所以除非 JIT 会重新排序这些商店T1 做到了 - 你看不到。但那是在玩火,字面意思,this question和后续行动(接近相同)here一个人(不确定是否属实)丢失了 1200 万台设备
JLS 只保证了几种实现可见性的方法。顺便说一句,这不是相反,JLS 不会说什么时候会中断,它会说什么时候会工作。
请注意该示例如何显示每个 字段必须是final - 即使在当前实现下一个单个 就足够了,并且在构造函数之后插入了两个内存屏障(当使用 final 时):LoadStore 和 StoreStore。
2) volatile fields (并且隐含地 AtomicXXX);我认为这个不需要任何解释,而且你似乎引用了这个。
3) Static initializers好吧,在我看来应该是显而易见的
4) Some locking involved - 这也应该是显而易见的,发生在规则之前...
关于java - 对象构造在实践中是否保证所有线程都看到已初始化的非最终字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51695962/
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev
在我的gem中,我需要yaml并且在我的本地计算机上运行良好。但是在将我的gem推送到rubygems.org之后,当我尝试使用我的gem时,我收到一条错误消息=>"uninitializedconstantPsych::Syck(NameError)"谁能帮我解决这个问题?附言RubyVersion=>ruby1.9.2,GemVersion=>1.6.2,Bundlerversion=>1.0.15 最佳答案 经过几个小时的研究,我发现=>“YAML使用未维护的Syck库,而Psych使用现代的LibYAML”因此,为了解决
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象