Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Design-Pattern]-Singleton 其实单例也没那么简单 #2

Open
fred-ye opened this issue May 5, 2014 · 0 comments
Open

[Design-Pattern]-Singleton 其实单例也没那么简单 #2

fred-ye opened this issue May 5, 2014 · 0 comments

Comments

@fred-ye
Copy link
Owner

fred-ye commented May 5, 2014

单例模式:简单来说就是在系统中维持某个类的一个实例,并且自行实例化。通常分为两种:饿汉式单例和懒汉式单例。

饿汉式单例:在类初始化的时候就生成实例。

public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton(){}
    public static Singleton getInstance() {
        return instance;
    }
}

懒汉式单例:在需要实例的时候才初始化。

public class Singleton {
    private static Singleton instance = null;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            return new Singleton();
        }
        return instance;        
    }
}

其实,对于懒汉式单例的这种实现方式还存在着一个问题,那就是在多线程情况下会出现线程安全性问题。很自然我们联想到要采用同步的机制。为此,将代码改成如下方式[即对getInstance方法进行同步]:

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

当然,由于添加了sychronized,肯定会对性能产生影响,但是如果getInstance()方法调用不是很频繁,或者应用程序能够接受由此带来的负担,采用这种方式也OK. 饿汉式的单例由于是在JVM加载这个类时就会创建一个单例。可以保证在任何线程访问,实例就已经初始化好了。

在HeadFirst 设计模式中提到一种双重检查加锁的方式来实现单例。即采用valatile关键字。 注意,valatile关键适用于jdk1.5或1.5之后版本。代码如下:

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

注:

  • volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
  • getInstance()方法中需要使用同步锁synchronized (Singleton.class)防止多线程同时进入造成instance被多次实例化。
  • 在上面在synchronized (Singleton.class)外又添加了一层if,这是为了在instance已经实例化后下次进入不必执行synchronized (Singleton.class)获取对象锁,从而提高性能。
@fred-ye fred-ye changed the title [Design-Pattern]-Singleton [Design-Pattern]-Singleton 其实单例也没那么简单 Jun 22, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant