这似乎是一个非常基本的问题,但我找不到明确的确认。
假设我有一个正确同步的类:
public class SyncClass {
private int field;
public synchronized void doSomething() {
field = field * 2;
}
public synchronized void doSomethingElse() {
field = field * 3;
}
}
如果我需要对那个类的实例有一个引用,并在线程之间共享,我仍然需要声明那个实例是 volatile 或 final,我说得对吗?如:
public class MainClass { // previously OuterClass
public static void main(String [ ] args) {
final SyncClass mySharedObject = new SyncClass();
new Thread(new Runnable() {
public void run() {
mySharedObject.doSomething();
}
}).start();
new Thread(new Runnable() {
public void run() {
mySharedObject.doSomethingElse();
}
}).start();
}
}
或者,如果 mySharedObject 不能是最终的,因为它的实例化取决于一些其他条件(与 GUI 的交互、来自套接字的信息等),事先不知道:
public class MainClass { // previously OuterClass
public static void main(String [ ] args) {
volatile SyncClass mySharedObject;
Thread initThread = new Thread(new Runnable() {
public void run() {
// just to represent that there are cases in which
// mySharedObject cannot be final
// [...]
// interaction with GUI, info from socket, etc.
// on which instantation of mySharedObject depends
if(whateverInfo)
mySharedObject = new SyncClass();
else
mySharedObject = new SyncClass() {
public void someOtherThing() {
// ...
}
}
}
});
initThread.start();
// This guarantees mySharedObject has been instantied in the
// past, but that still happened in ANOTHER thread
initThread.join();
new Thread(new Runnable() {
public void run() {
mySharedObject.doSomething();
}
}).start();
new Thread(new Runnable() {
public void run() {
mySharedObject.doSomethingElse();
}
}).start();
}
}
Final 或 volatile 是强制性的,MyClass 同步对其自身成员的访问这一事实不会免除注意确保引用在线程之间共享.是吗?
与的区别Difference between volatile and synchronized in Java
1- 提到的问题是关于 synchronized 和 volatile 作为替代方案,对于相同的字段/变量,我的问题是关于如何正确使用已经正确同步的类(即选择了 synchronized),考虑需要考虑的影响由调用者,可能在已同步类的引用上使用 volatile/final。
2- 换句话说,提到的问题/答案是关于锁定/易变的同一个对象,我的问题是:我如何确定不同的线程实际上看到同一个对象?在锁定/访问它之前。
当引用问题的第一个答案明确引用一个 volatile 引用时,它是关于一个不可变对象没有同步。第二个答案仅限于原始类型。 我确实发现它们很有用(见下文),但还不够完整,不足以消除对我在这里给出的案例的任何疑虑。
3- 所提到的答案是对一个非常开放的问题的非常抽象和学术的解释,根本没有代码;正如我在介绍中所说,我需要明确确认引用特定但很常见的问题的实际代码。当然,它们是相关的,但就像教科书与特定问题相关一样。 (我实际上在打开这个问题之前阅读了它,发现它很有用,但我仍然需要讨论一个特定的应用程序。)如果教科书解决了人们可能在应用它们时遇到的所有问题/疑虑,我们可能根本不需要 stackoverflow。
考虑到,在多线程中,您不能“只是尝试一下”,您需要正确理解并确定细节,因为竞争条件可以正确一千次,然后再出现一千 + 1 次可怕的错误。
最佳答案
是的,你是对的。有必要使对变量的访问也是线程安全的。您可以通过将其设为 final 或 volatile 来实现,或者确保所有线程在同步块(synchronized block)内再次访问该变量。例如,如果您不这样做,可能是一个线程已经“看到”变量的新值,但另一个线程可能仍然“看到”null。
因此关于您的示例,当线程访问 mySharedObject 变量时,您有时会得到一个 NullPointerException。但这可能只发生在具有多个缓存的多核机器上。
Java 内存模型
这里的重点是 Java 内存模型。它指出,如果更新发生在所谓的先发生关系中读取该状态之前,则线程只能保证看到另一个线程的内存更新。可以通过使用 final、volatile 或 synchronized 来强制执行 happens-before 关系。如果您不使用这些构造中的任何一个,则一个线程的变量赋值永远不会保证对任何其他线程可见。
你可以认为线程在概念上有本地缓存,只要你不强制同步多个线程的缓存,一个线程就只是读取和写入它的本地缓存。这可能会导致两个线程在读取同一字段时看到完全不同的值。
请注意,还有一些额外的方法可以强制内存更改的可见性,例如,使用静态初始化程序。此外,新创建的线程总是看到其父线程的当前内存,而无需进一步同步。所以你的例子甚至可以在没有任何同步的情况下工作,因为你的线程的创建以某种方式强制发生在字段初始化之后。 但是依赖这样一个微妙的事实是非常危险的,如果您稍后在没有考虑这些细节的情况下重构您的代码,很容易崩溃。 Java Language Specification 中描述了(但难以理解)有关发生前关系的更多详细信息.
关于Java:引用同步对象是否需要 volatile/final?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29129820/
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
当我使用Bundler时,是否需要在我的Gemfile中将其列为依赖项?毕竟,我的代码中有些地方需要它。例如,当我进行Bundler设置时:require"bundler/setup" 最佳答案 没有。您可以尝试,但首先您必须用鞋带将自己抬离地面。 关于ruby-我需要将Bundler本身添加到Gemfile中吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/4758609/
给定这段代码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
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类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
我注意到像bundler这样的项目在每个specfile中执行requirespec_helper我还注意到rspec使用选项--require,它允许您在引导rspec时要求一个文件。您还可以将其添加到.rspec文件中,因此只要您运行不带参数的rspec就会添加它。使用上述方法有什么缺点可以解释为什么像bundler这样的项目选择在每个规范文件中都需要spec_helper吗? 最佳答案 我不在Bundler上工作,所以我不能直接谈论他们的做法。并非所有项目都checkin.rspec文件。原因是这个文件,通常按照当前的惯例,只
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
我实际上是在尝试使用RVM在我的OSX10.7.5上更新ruby,并在输入以下命令后:rvminstallruby我得到了以下回复:Searchingforbinaryrubies,thismighttakesometime.Checkingrequirementsforosx.Installingrequirementsforosx.Updatingsystem.......Errorrunning'requirements_osx_brew_update_systemruby-2.0.0-p247',pleaseread/Users/username/.rvm/log/138121