创建型设计模式之单例模式

Posted 丨Jack_Chen丨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了创建型设计模式之单例模式相关的知识,希望对你有一定的参考价值。

单例模式

概述

常见单例:

懒汉式:就是需要的才会去实例化,线程不安全。

饿汉式:就是当class文件被加载的时候,初始化,天生线程安全。

比如:ServletContext、ServletContextConfig、ApplicationContext等都是单例形式

优缺点

优点:

1.在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。

2.避免对资源的多重占用。

缺点:

1.没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

懒汉式

注意:该方式在多线程中使用存在线程安全问题。

public class Singleton 
    //需要时才会被实例化
    private static Singleton singleton;

    private Singleton() 
    
	public static Singleton getSingleton() 
        if (singleton == null) 
            singleton = new Singleton();
        
        return singleton;
    

使用synchronized关键字使方法变成线程同步方法。

这种方法在线程数量较多情况下,如果CPU压力过大,则会导致大批线程阻塞,从而导致程序性能大幅下降。

public class Singleton 
    //需要时才会被实例化
    private static Singleton singleton;

    private Singleton() 

    
    synchronized public static Singleton getSingleton() 
        if (singleton == null) 
            singleton = new Singleton();
        
        return singleton;
    


    public static void main(String[] args) 
        Singleton sl1 = Singleton.getSingleton();
        Singleton sl2 = Singleton.getSingleton();
        System.out.println(sl1 == sl2);
    

使用双重检查锁的的单例模式可进一步提升性能。

public class Singleton 
    //需要时才会被实例化
    private static Singleton singleton;
    private Singleton() 
    
    public static Singleton getSingleton() 
        if (singleton == null) 
            synchronized (Singleton.class) 
                //检查是否要重新创建实例
                if (singleton == null) 
                    singleton = new Singleton();
                
            
        
        return singleton;
    

饿汉式

优点:能保证绝对线程安全、执行效率比较高

缺点:所有对象类加载的时候就实例化

public class Singleton
    //当class文件被加载初始化
    private static Singleton singleton = new Singleton();

    private Singleton() 

    public static Singleton getSingleton() 
        return singleton;
    


  public static void main(String[] args) 
        Singleton singleton1 = Singleton.getSingleton();
        Singleton singleton2 = Singleton.getSingleton();
        System.out.println(singleton1 == singleton2);
    

上述是标准写法,还有另外一种写法,利用静态代码块的机制

public class Singleton
    //当class文件被加载初始化
    private static Singleton singleton;

	static
	 singleton = new Singleton()
	

    private Singleton() 

    public static Singleton getSingleton() 
        return singleton;
    

其他实现方式

静态内部类实现单例

public class Singleton 

    private Singleton() 
        if (LazySingleton.INSTANCE != null) 
            throw new RuntimeException("非法访问");
        
    

    /**
     * 在返回结果前先加载内部类
     */
    private static Singleton getInstance() 
        return LazySingleton.INSTANCE;
    

    /**
     * 默认不加载
     */
    private static class LazySingleton 
        private static final Singleton INSTANCE = new Singleton();
    

ThreadLocal实现线程单例

public class ThreadLocalSingleton 
    private static final ThreadLocal<ThreadLocalSingleton> threadLocaLInstance =
            new ThreadLocal<ThreadLocalSingleton>() 
                @Override
                protected ThreadLocalSingleton initialValue() 
                    return new ThreadLocalSingleton();
                
            ;

    private ThreadLocalSingleton() 
    

    public static ThreadLocalSingleton getInstance() 
        return threadLocaLInstance.get();
    

    public static void main(String[] args) 
        ThreadLocalSingleton threadLocalSingleton1 = ThreadLocalSingleton.getInstance();
        ThreadLocalSingleton threadLocalSingleton2 = ThreadLocalSingleton.getInstance();
        System.out.println(threadLocalSingleton1 == threadLocalSingleton2);
    

注册式单例模式

注册式单例模式有两种:枚举式单例模式容器式单例模式

枚举式单例模式

枚举式单例模式是比较推荐的一种单例模式实现,写法优雅

注意:与饿汉式类似,在类加载时就将所有对象初始化,不适合大量创建单例对象的场景

public enum EnumSingleton 
    INSTANCE;
    
    public static EnumSingleton getInstance() 
        return INSTANCE;
    

    public static void main(String[] args) 
        EnumSingleton instance1 = EnumSingleton.getInstance();
        EnumSingleton instance2 = EnumSingleton.getInstance();
        System.out.println(instance1 == instance2);
    

容器式单例模式

容器式单例模式适用于需要大量创建单例对象的场景,便于管理。注意:它是非线程安全的。

public class ContainerSingleton 

    private ContainerSingleton() 
    

    private static Map<String, Object> ioc = new ConcurrentHashMap<String, Object>();

    public static Object getInstance(String className) 
        Object instance = null;
        if (!ioc.containsKey(className)) 
            try 
                instance = Class.forName(className).newInstance();
                ioc.put(className, instance);
             catch (Exception e) 
                e.printStackTrace();
            
            return instance;
         else 
            return ioc.get(className);
        
    

    public static void main(String[] args) 
        Object instance1 = ContainerSingleton.getInstance("cn.ybzy.demo.ContainerSingleton");
        Object instance2 = ContainerSingleton.getInstance("cn.ybzy.demo.ContainerSingleton");
        System.out.println(instance1 == instance2);
    


单例模式的破坏

反射破坏

private Singleton() 
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException 
        Class<Singleton> singletonClass = Singleton.class;
        // 反射强制获取私有构造函数
        Constructor<Singleton> declaredConstructor = singletonClass.getDeclaredConstructor(null);
        // 强制访问私有构造函数
        declaredConstructor.setAccessible(true);
        // 暴力调用私有构造函数进行初始化
        Singleton singleton1 = declaredConstructor.newInstance();
        Singleton singleton2 = declaredConstructor.newInstance();

        System.out.println(singleton1 == singleton2);
    

在私有构造函数中添加限制处理,防止实例多次重复创建。

    private Singleton() 
        if (LazySingleton.INSTANCE != null) 
            throw new RuntimeException("非法访问");
        
    

序列化破坏

public class SeriableSingleton implements Serializable 
    public final static SeriableSingleton INSTANCE = new SeriableSingleton();

    private SeriableSingleton() 
    

    public static SeriableSingleton getInstance() 
        return INSTANCE;
    

//    private Object readResolve() return INSTANCE;


    public static void main(String[] args) 

        SeriableSingleton s1 = SeriableSingleton.getInstance();
        SeriableSingleton s2 = null;
        FileOutputStream fos = null;
        try 

            fos = new FileOutputStream("SeriableSingleton.obj");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(s1);
            oos.flush();
            oos.close();

            FileInputStream fis = new FileInputStream("SeriableSingleton.obj");
            ObjectInputStream ois = new ObjectInputStream(fis);
            s2 = (SeriableSingleton) ois.readObject();
            ois.close();

            System.out.println(s1 == s2);

         catch (Exception e) 
            e.printStackTrace();
        
    

关键核心在于ObjectInputStreamreadObject(Class<?> type)方法调用readObject0方法中的switch (tc)判断处理。

private Object readResolve() return INSTANCE;

以上是关于创建型设计模式之单例模式的主要内容,如果未能解决你的问题,请参考以下文章

创建型模式之单例模式

3创建型模式之单例模式

python设计模式---创建型之单例模式

设计模式之单例模式(创建型)

创建型设计模式之单例模式

创建型模式之单例模式