class MyClass
{
private static MyClass obj;
public static MyClass getInstance()
{
if(obj==null)
{
obj = new MyClass();
}
return obj;
}
在上面的java代码示例中,因为obj是类中的静态变量, getInstance仍然是非线程安全的吗?由于静态变量由所有线程共享,因此2个同时线程应使用相同的对象。不是吗?
Vipul Shah
答案 0 :(得分:6)
因为静态变量是如此广泛共享,所以它们非常非线程安全。
考虑如果两个线程同时调用你的getInstance会发生什么。两个线程都将查看共享静态obj
,并且两个线程将在if检查中看到obj
为空。然后,两个线程都将创建一个新的obj
。
您可能会想:“嘿,它是线程安全的,因为obj只会有一个值,即使它被初始化多次。”该陈述有几个问题。在前面的示例中,getInstance的调用者将返回自己的obj
。如果两个调用者都保持对obj
的引用,那么您将使用单个实例的多个实例。
即使我们上一个示例中的调用者只执行了:MyClass.getInstance();
并且没有保存对MyClass.getInstance();
返回的引用,您仍然可以在这些线程上从getInstance获取不同的实例。即使对getInstance的调用没有同时发生,你甚至可以进入创建obj
的新实例的情况!
我知道我的上一个声明似乎违反直觉,因为上次分配到obj
似乎是将来可能从MyClass.getInstance()
调用返回的唯一值。但是,您需要记住,JVM中的每个线程都有自己的主内存本地缓存。如果两个线程调用getInstance,它们的本地缓存可能会将不同的值分配给obj
,并且将来从这些线程调用getInstance将返回其缓存中的内容。
确保getInstance线程安全的最简单方法是使方法同步。这将确保
obj
的主题永远不会从其缓存中获得过时的obj
不要尝试变聪明并使用双重检查锁定: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
答案 1 :(得分:2)
答案 2 :(得分:2)
在这种情况下,即使使用静态变量,getInstance()也不是线程安全的。只有同步才能使这个线程安全。
答案 3 :(得分:0)
以下示例显示了一个奇怪的线程保存修改后的单吨模式,它也支持泛型。
要让它只是线程保存和同步保存只需采用synchronized块和transient和volatile关键字。 注意,有一个双重检查,synchronized块在if里面。这带来了更多的性能,因为synchronized是昂贵的。
当然对于一个真正的单身人士不使用地图,我说它是一个修改过的。
public class Edge<T> {
@SuppressWarnings({"unchecked"})
private static transient volatile HashMap<Object,HashMap<Object, Edge>> instances = new HashMap<Object, HashMap<Object,Edge>>();
/**
* This function is used to get an Edge instance
* @param <T> Datatype of the nodes.
* @param node1, the source node
* @param node2, the destination node
* @return the edge of the two nodes.
*/
@SuppressWarnings({"unchecked"})
public static <T> Edge<T> getInstance(T node1, T node2){
if(!(instances.containsKey(node1) && instances.get(node1).containsKey(node2))){
synchronized (Edge.class) {
if(!(instances.containsKey(node1) && instances.get(node1).containsKey(node2))){
Edge<T> edge = new Edge<T>(node1, node2);
if(!instances.containsKey(node1)){
instances.put(node1, new HashMap<Object, Edge>());
}
instances.get(node1).put(node2, edge);
}
}
}
return (Edge<T>)instances.get(node1).get(node2);
}
答案 4 :(得分:0)
public class Singleton{
private static transient volatile Singleton instance;
public static Singleton getInstance(){
if(instance==null)synchronized(Singleton.class){
if(instance==null){
instance = new Singleton();
}
}
return instance;
}
private Singleton(){
/*....*/
}
}
认为现在可以将其标记为已回答。
答案 5 :(得分:0)
class MyClass
{
private static MyClass obj;
private MyClass(){
// your initialization code
}
public static synchronized MyClass getInstance()
{
if(obj==null)
{
obj = new MyClass();
}
return obj;
}
我同意@Manoj。 我相信以上将是实现单例对象的最佳方法之一。 并且同步使对象线程安全。 甚至,它是静态的:)