我想知道以下(人为的)示例是否是线程安全的:
public class SpringSingleton
{
private MyObject _myObject = new MyObject("hello");
public void useObject()
{
_myObject.doSomethingCool();
}
public void changeObject()
{
_myObject = new MyObject("goodbye");
}
public static void main(String[] args)
{
// Have multiple threads, some using and some changing the object
}
}
我的主要问题是:当一个线程试图在另一个线程试图调用useObject()
的同时调用changeObject()
时会发生什么?
答案 0 :(得分:2)
分配引用是一种原子操作。您永远不会看到半分配的参考。因此,调用doSomethingCool()
方法的线程将在旧引用或新引用上调用它。
但这并不能使代码线程安全。您还可能遇到可见性问题:即使线程已经编写了新引用,读取引用的线程也可能会看到旧的引用。要解决该问题,您需要使字段变为volatile,或将其包装到AtomicReference中,或者同步对字段的所有访问。
另请注意,如果您将代码更改为
_myObject.doSomethingCool();
_myObject.doSomethingElse();
然后你会遇到另一个问题:第一次调用可能是在旧对象上进行的,第二次是在新对象上进行的。如果在这两个调用之间需要一致性,那么这两个调用以及与_myObject的每次其他交互都应该被包装到一个synchronized块中(使用相同的锁)。
答案 1 :(得分:0)
如果一个线程试图同时调用useObject()
另一个线程试图调用changeObject()
,那么该行为是不确定的,调用useObject()
的线程可能会看到旧的或新的价值。
是否安全"取决于你想要的行为。
在很短的时间内,您的代码可能无关紧要。