我有一个类似下面的代码,其中在两个线程(主线程和Monitor线程)之间共享一个对象。是否必须全局声明MyObject并将其设置为volatile
以确保将其推入内存?否则,如果MyObject仅由线程本地访问并且未声明为volatile,则if
语句可以显示“ Not null”。
public static void main(String[] args) {
MyObject obj = MyObjectFactory.createObject();
new Monitor(obj).start();
Thread.sleep(500);
if(obj == null)
System.out.println("Null");
else
System.out.println("Not null");
}
public void doSomethingWithObject(MyObject obj) {
obj = null;
}
private class Monitor extends Thread {
public Monitor(MyObject obj) {
this.obj=obj;
}
public void run() {
doSomethingWithObject(obj);
}
}
注意:该代码示例可能无法编译,因为我是在Stackoverflow上自己编写的。将其视为伪代码和实代码的混合。
最佳答案
该实例是共享的,但不共享对其的引用。例:
String a = "hello";
String b = a;
b = null; // doesn't affect a
a
和b
是对同一实例的引用;更改一个引用不会对该实例或对该实例的任何其他引用产生影响。因此,如果要在线程之间共享状态,则必须在
MyObject
内创建一个字段,该字段必须为volatile
:class MyObject { public volatile int shared; }
public void doSomethingWithObject(MyObject obj) {
obj.shared = 1; // main() can see this
}
请注意,
volatile
仅适用于某些类型(引用和除long
之外的所有原语)。由于这很容易出错,因此您应该查看java.util.concurrent.atomic
中的类型。[编辑]我上面所说的不正确。相反,将
volatile
与long
结合使用可达到Java 5及更高版本的预期。这是确保对该类型进行原子读/写的唯一方法。请参阅以下问题以供参考:Is there any point in using a volatile long?赞扬Affe指出这一点。谢谢。