我有一个类似下面的代码,其中在两个线程(主线程和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


ab是对同一实例的引用;更改一个引用不会对该实例或对该实例的任何其他引用产生影响。

因此,如果要在线程之间共享状态,则必须在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中的类型。

[编辑]我上面所说的不正确。相反,将volatilelong结合使用可达到Java 5及更高版本的预期。这是确保对该类型进行原子读/写的唯一方法。请参阅以下问题以供参考:Is there any point in using a volatile long?

赞扬Affe指出这一点。谢谢。

07-27 19:54