单例模式

191 阅读2分钟

饿汉模式:

重点是类加载的时候就会创建实例 1.私有化构造器;
2.创建一个实例;
3.创建一个方法来给其他类提供实例;

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

优点是:线程安全。因为在类加载的时候就完成实例化,避免了线程同步问题。
缺点是:有浪费内存的可能。如果从未使用过实例,那么会造成内存的浪费。调用实例方法会进行类加载,但也有其他可能也会导致类加载,这时候初始化instance就没有达到lazy loading的效果。

懒汉模式:

重点是只有在调用getInstance方法后才会构造实例 1.私有化构造器; 2.创建一个类的变量; 3.创建一个方法来构造实例并返回。

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

优点:达到了懒加载的效果,但只有在单线程状态下才能使用;
缺点:线程不安全。如果一个线程进入了if中但还没有创建实例,此时另一个线程也进入if中,这便会产生多个实例。

加个synchronized锁在方法上可以解决线程同步问题,但缺点是效率太低:只需要在第一次时创建实例,其他时候只用直接return就够了,但这种同步是每次进入都有重新创建一遍,造成浪费。

ps:如果想在if中加个synchronized同步块来解决这个问题是错误的,没解决不说还会造成线程不安全。

双层检验

特点是判断两次if(instance==null)
1.构造器私有化
2.创建一个静态volatile属性;
3.创建一个共有方法来new并返回。

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

线程安全,效率高

静态内部类

特点是用静态内部类来new实例
1.构造器私有化;
2.创建一个静态内部类,里面构造一个静态属性并new;
3.创建一个公有方法来返回静态内部属性。

public class Singleton{
    private Singleton(){}
    private static class SingletonInstance{
        private static final Singleton INSTANCE=new Singleton();
    }
    public static Singleton getInstance(){
        return SingletonInstance.INSTANCE;
    }
}

类加载的时候,实例不会初始化,因为SingletonInstance类没有被主动调用,只有显式调用了getInstance方法才会显式加载SingletonInstance,从而实例化instance。
注意内部类SingletonInstance要用static修饰且其中的静态变量INSTANCE必须是final的
优点:线程安全,效率高