Java:引用同步对象是否需要易失性/最终性?
这似乎是一个非常基本的问题,但我找不到明确的确认。
假设我有一个类本身已正确同步:
public class SyncClass {
private int field;
public synchronized void doSomething() {
field = field * 2;
}
public synchronized void doSomethingElse() {
field = field * 3;
}
}
如果我需要引用该类的实例,在线程之间共享,我仍然需要声明该实例易失性或最终性,我是对的吗?如:
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();
}
}
或者,如果不能是最终的,因为它的实例化取决于其他一些条件(与GUI的交互,来自套接字的信息等),事先不知道:mySharedObject
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();
}
}
最终或易失性是强制性的,将访问同步到其自己的成员的事实并不免除确保在线程之间共享引用时要小心。是吗?MyClass
Java中易失性和同步之间的差异
1-引用的问题是关于同步和易失性作为替代方案,对于相同的字段/变量,我的问题是关于如何正确使用已经正确同步的类(即已选择同步),考虑调用方需要考虑的含义,可能在已经同步的类的引用上使用 volatile/final。
2-换句话说,引用的问题/答案是关于锁定/易失相同的对象,我的问题是:我如何确定不同的线程实际上看到相同的对象?在锁定/访问它之前。
当引用问题的第一个答案显式引用易失性引用时,它是关于一个没有同步的不可变对象。第二个答案将自己限制为基元类型。我确实发现它们很有用(见下文),但还不够完整,无法对我在这里给出的案例产生任何疑问。
3-引用的答案是对一个非常开放的问题的非常抽象和学术的解释,根本没有代码;正如我在引言中所述,我需要清楚地确认引用特定但非常常见的问题的实际代码。当然,它们是相关的,但就像教科书与特定问题相关一样。(在打开这个问题之前,我实际上已经阅读了它,并发现它很有用,但我仍然需要讨论一个特定的应用程序。如果教科书解决了人们可能应用它们的所有问题/疑虑,我们可能根本不需要stackoverflow。
考虑到,在多线程中,你不能“只是尝试一下”,你需要一个正确的理解并确保细节,因为竞争条件可以正确一千次,然后错得可怕一千次+1次。