use*_*039 2 singleton static multithreading thread-safety
class MyClass
{
private static MyClass obj;
public static MyClass getInstance()
{
if(obj==null)
{
obj = new MyClass();
}
return obj;
}
Run Code Online (Sandbox Code Playgroud)
在上面的java代码示例中,因为obj是类中的静态变量,getInstance仍然是非线程安全的吗?由于静态变量由所有线程共享,因此2个同时线程应使用相同的对象.不是吗?
Vipul Shah
因为静态变量是如此广泛共享,所以它们非常非线程安全.
考虑如果两个线程同时调用getInstance会发生什么.两个线程都将查看共享静态,obj并且两个线程将obj在if检查中看到为null.然后两个线程都将创建一个新的obj.
您可能会想:"嘿,它是线程安全的,因为obj只会有一个值,即使它被初始化多次." 该陈述有几个问题.在前面的例子中,getInstance的调用者都会自己obj回来.如果两个调用者保持对它们的引用,obj那么将使用单个实例的多个实例.
即使我们前面示例中的调用者刚刚执行了:MyClass.getInstance();并且没有保存对MyClass.getInstance();返回的内容的引用,您仍然可以在这些线程上从getInstance获取不同的实例.即使obj对getInstance的调用没有同时发生,你甚至可以进入创建新实例的情况!
我知道我的上一个主张似乎是违反直觉的,因为最后一次分配obj似乎是未来调用可以返回的唯一值MyClass.getInstance().但是,您需要记住,JVM中的每个线程都有自己的主内存本地缓存.如果两个线程调用getInstance,则它们的本地缓存可以分配不同的值,obj并且将来从这些线程调用getInstance将返回其缓存中的内容.
确保getInstance线程安全的最简单方法是使方法同步.这将确保这一点
obj永远不会obj从缓存中获得过时的值不要试图变得聪明并使用双重检查锁定:http: //www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html