单例规则不适用于静态成员变量

时间:2014-04-23 13:38:44

标签: java design-patterns singleton

我在单身设计模式中工作。我使用一个静态变量作为我的类的成员变量。根据我的代码它创建了多个实例,即使我是单独的类。请帮帮我,这是正确的做事方式吗? //这是我的代码

public class MySingleton {
    public static MySingleton instance = null;// new MySingleton();
    static int count;

    private MySingleton() {
        count++;
    }

    public static MySingleton getInstance() {
        if (instance == null) {
            synchronized (MySingleton.class) {
                instance = new MySingleton();
            }

        }
        return instance;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        MySingleton news = new MySingleton().getInstance();
        System.out.println(news.count);
        MySingleton news1 = new MySingleton().getInstance();

        System.out.println(news1.count);
        MySingleton news2 = new MySingleton().getInstance();
        System.out.println(news2.count);
    }

}

7 个答案:

答案 0 :(得分:2)

您的代码不是线程安全的。

假设您从2个主题到MySimgleton().getInstance()

进行2次调用

如果在if之后发生上下文切换,那么你将创建2个实例

答案 1 :(得分:1)

您需要使用静态方法来访问类,以允许类控制对其唯一实例的访问

MySimgleton news = new MySimgleton().getInstance();

应该是

MySimgleton news = MySimgleton.getInstance();

但这种懒惰的初始化方法不是线程安全的。你可以做到

public class MySingleton {
    private static class SingletonHolder {
        static final MySingleton INSTANCE = new MySingleton();
    }

    public static MySingleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
    ...
}

答案 2 :(得分:1)

在Main函数中,它应该是:

public static void main(String[] args) {
    // TODO Auto-generated method stub

    MySimgleton news = MySimgleton.getInstance();
    System.out.println(news.count);
    MySimgleton news1 = MySimgleton.getInstance();

    System.out.println(news1.count);
    MySimgleton news2 =  MySimgleton.getInstance();
    System.out.println(news2.count);
}

对于这种情况,它更好:

public class Test {
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        MySimgleton news = MySimgleton.getInstance();
        System.out.println(news.count);
        MySimgleton news1 = MySimgleton.getInstance();

        System.out.println(news1.count);
        MySimgleton news2 = MySimgleton.getInstance();
        System.out.println(news2.count);
    }
}

class MySimgleton {
    public static MySimgleton instance = null;// new MySimgleton();
    static int count;

    private MySimgleton() {
        count++;
    }

    public static MySimgleton getInstance() {
        if (instance == null) {
            synchronized (MySimgleton.class) {
                instance = new MySimgleton();
            }

        }
        return instance;
    }
}

答案 3 :(得分:0)

要避免多线程访问错误,请在声明中初始化instance。 如果您确实想要在getInstance方法中对其进行初始化,请将同步块包裹在if语句周围,并使字段instance private(远程final }关键字)

通过类名访问getInstance方法,不要先调用构造函数。

public class MySimgleton {
    // You don't need a synchronized block if you initialize it in the declaration
    public static final MySimgleton instance = new MySimgleton();
    static int count;

    private MySimgleton() {
        count++;
    }

    public static MySimgleton getInstance() {
        // Only if you didn't initialize it in the declaration itself.
        // synchronized (MySimgleton.class) {
        //     if (instance == null) {
        //         instance = new MySimgleton();
        //     }
        // }
        return instance;
    }

    public static void main(String[] args) {
        MySimgleton news = MySimgleton.getInstance();
        System.out.println(news.count);
        // etc.
    }
}

答案 4 :(得分:0)

您的代码的问题在于您自己调用构造函数

new MySimgleton().

即使构造函数是私有的,您也可以从类中调用它。

您应该调用静态getInstance方法来获取对象的实例,并且可以直接通过Class接收静态mehtod。

MySimgleton.getInstance();

答案 5 :(得分:0)

您的类首先是单线程应用程序的完美单例,

唯一的事情是你有一个名为count的静态varibale,static对你创建的所有对象都是通用的,而evrytime你创建的对象是你递增计数因此它给出1,2,3输出。

但是尝试打印对象,您将看到相同的引用地址

我将打印状态添加到打印对象并获得如下

2
com.kb.designpatterns.MySingleton@15db9742
3
com.kb.designpatterns.MySingleton@15db9742
com.kb.designpatterns.MySingleton@15db9742
4

答案 6 :(得分:0)

正如@Mzf提到的那样

  

您的代码不是线程安全的

您可以通过在同步块中包含if (instance == null)来解决问题。

但是,为了在极度多线程的环境中最小化同步影响,您可以考虑进行双重检查:

public static MySingleton getInstance() {
  if (instance == null) {
    synchronized (MySingleton.class) {
      if (instance == null) {
        instance = new MySingleton();
      }
    }
  }
  return instance;
}