如果在多线程中使用实例化,我们是否应该将私有(private)字段声明为volatile?
在Effective Java ,有一个例子,如果没有 volatile,代码就无法工作:
import java.util.concurrent.TimeUnit;
// Broken! - How long would you expect this program to run?
public class StopThread {
private static boolean stopRequested; // works, if volatile is here
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable() {
public void run() {
int i = 0;
while (!stopRequested)
i++;
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
解释是这样说的
while(!stopRequested)
i++;
优化成这样:
if(!stopRequested)
while(true)
i++;
因此后台线程看不到 stopRequested 的进一步修改,因此它会永远循环。 (顺便说一句,该代码在 JRE7 上没有 volatile 就终止了。)
现在考虑这个类:
public class Bean {
private boolean field = true;
public boolean getField() {
return field;
}
public void setField(boolean value) {
field = value;
}
}
和一个线程如下:
public class Worker implements Runnable {
private Bean b;
public Worker(Bean b) {
this.b = b;
}
@Override
public void run() {
while(b.getField()) {
System.err.println("Waiting...");
try { Thread.sleep(1000); }
catch(InterruptedException ie) { return; }
}
}
}
以上代码在不使用 volatiles 的情况下按预期工作:
public class VolatileTest {
public static void main(String [] args) throws Exception {
Bean b = new Bean();
Thread t = new Thread(new Worker(b));
t.start();
Thread.sleep(3000);
b.setField(false); // stops the child thread
System.err.println("Waiting the child thread to quit");
t.join();
// if the code gets, here the child thread is stopped
// and it really gets, with JRE7, 6 with -server, -client
}
}
我认为由于公共(public) setter,编译器/JVM 永远不应该优化调用 getField() 的代码,但是 this article说有一些“Volatile Bean”模式(模式#4),应该应用于创建可变的线程安全类。 更新:也许那篇文章仅适用于 IBM JVM?
问题是:JLS 的哪一部分明确或隐含地指出具有公共(public) getter/setter 的私有(private)原始字段必须声明为 volatile(或者他们不必声明)?
抱歉,问题很长,我试着详细解释了问题。如果有什么不清楚的地方,请告诉我。谢谢。
最佳答案
The question is: which part of JLS explicitly or implicitly says that private primitive fields with public getters/setters must be declared as volatile (or they don't have to)?
JLS 内存模型不关心 getter/setter。从内存模型的角度来看,它们是空操作——您也可以访问公共(public)字段。将 boolean 值包装在方法调用后面不会影响其内存可见性。您的后一个示例完全靠运气。
Should we declare the private fields as volatile if the instanced are used in multiple threads?
如果要在多线程环境中使用一个类(bean),您必须以某种方式考虑到这一点。使私有(private)字段 volatile 是一种方法:它确保每个线程都能看到该字段的最新值,而不是任何缓存/优化过的陈旧值。但是并没有解决atomicity的问题.
The article you linked to适用于任何遵循 JVM 规范(JLS 所依赖的)的 JVM。根据 JVM 供应商、版本、标志、计算机和操作系统、运行程序的次数(HotSpot 优化通常在第 10000 次运行后开始)等,你会得到不同的结果,所以你真的必须理解规范并认真遵守遵守规则以创建可靠的程序。在这种情况下进行实验并不是了解事情如何工作的好方法,因为 JVM 可以按照它想要的任何方式运行,只要它符合规范,而且大多数 JVM 确实包含各种动态优化的负载。
关于java: `volatile` 带有 getter 和 setter 的私有(private)字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10996669/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?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,如果没有检查,请帮助我,非常感谢,谢谢
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我知道我可以指定某些字段来使用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
我正在尝试使用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
我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我
什么是ruby的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/