单例模式,顾名思义就是只存在一个类的实例,避免多实例造成的内存浪费。
1.饿汉模式
public class SingletonPattern {
//第一种,饿汉模式
private SingletonPattern() {
}
private static SingletonPattern singleton = new SingletonPattern();
public static SingletonPattern getInstance() {
return singleton;
}
}
这种方式在类加载时就完成了初始化,基于类加载的模式,避免了线程同步的问题,但是没有很好的控制加载的时机,可能会造成内存的浪费。
2.懒汉模式
public class SingletonPattern {
//第二种 懒汉式
private SingletonPattern() {
}
private static SingletonPattern singleton2 = null;
public static SingletonPattern getInstance2() {
if (singleton2 == null) {
singleton2 = new SingletonPattern();
}
return singleton2;
}
}
这种模式弥补了饿汉式的加载时机的把握,在第一次调用的时候去初始化,但是线程是不安全的的,为了解决线程多安全的问题,我们有了下面这中写法。
3.懒汉模式,线程安全
public class SingletonPattern {
//第三种 懒汉模式,线程安全
private SingletonPattern() {
}
private static SingletonPattern singleton3 = null;
private static synchronized SingletonPattern getInstance() {
if (singleton3 == null) {
singleton3 = new SingletonPattern();
}
return singleton3;
}
}
这种写法处理了线程的安全问题,但是每次都会进行同步,降低了代码的效率,造成不必要的开销,所以是不建议使用的,用锁的形式来保证线程安全是没错的,只是要考虑锁的位置。
4.双重检查模式
public class SingletonPattern {
//第四种 懒汉模式双重锁
private SingletonPattern() {
}
private static volatile SingletonPattern singleton4 = null;
public static SingletonPattern getInstance() {
if (singleton4 == null) {
synchronized (SingletonPattern.class) {
if (singleton4 == null) {
singleton4 = new SingletonPattern();
}
}
}
return singleton4;
}
}
首先是进行了两次if判断,第一次是为了不必要的同步操作,第二次是在对象为null的情况下,才初始化的。这里用到的volatile关键字,会屏蔽JVM的一些优化操作,对性能会有一些降低,所以我们推荐下面这种写法。
5.静态内部类单例模式
public class SingletonPattern {
//第五种 静态内部类
private SingletonPattern() {
}
private static class Singleton {
private static final SingletonPattern SINGLE = new SingletonPattern();
}
public static SingletonPattern getInstance() {
return Singleton.SINGLE;
}
}
第一次加载SingletonPattern类的时候,不会去初始化内部类,只有在调用getInstance()方法之后,才会加载内部类并且初始化静态变量,并且也保证了线程的安全性。
单例的优点
单例模式只产生一个实例,减少了内存的损耗,减少了性能的开销,避免了对资源的多重占用,可以在全局范围上进行管理。
单例的缺点
单例模式是不易扩展的,单例的方法不能生成子类的对象,必须要重写单例类才可以;如果单例方法需要传递Context的话,要小心内存泄漏的风险。