天天看点

spring设计模式-单例模式

单例模式

:是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。单例模式是创建型模式

  • 懒汉式单例模式:在类加载的时候就立即初始化,并且创建为单例对象,它绝对线程安全,线程还没出现的时候就实例化了
  • 不可能存在访问安全问题。
  • 优点:没有加任何锁,执行效率比较高,用户体验比懒汉式单例模式更好
  • 缺点:类加载的时候就初始化,不管用不用都占着空间,浪费了内存。
饿汉式:
public class HungrySingleton {
    private static HungrySingleton hungrySingleton=new HungrySingleton();
    //另一种写法
    private static HungrySingleton hungrySingleton1;
    static{
        hungrySingleton1=new HungrySingleton();
    }
    private HungrySingleton(){}
    public static HungrySingleton getInstance(){
        return hungrySingleton;
    }
}
懒汉式:
/**
 * 特点:被外部类调用的时候,内部类才会被加载.缺点:线程不安全
 */
public class LazySingleton {
    private LazySingleton(){}
    private  static LazySingleton lazySingleton=null;
    public static LazySingleton getInstance(){
        if (lazySingleton==null){
            lazySingleton=new LazySingleton();
        }
        return lazySingleton;
    }
    //方法一:线程不安全的办法,加锁,缺点:性能下降
    public static synchronized LazySingleton getInstance1(){
        if (lazySingleton==null){
            lazySingleton=new LazySingleton();
        }
        return lazySingleton;
    }
    //方法二:双重检验所:解决线程安全和性能问题(双重检验锁)
    public static LazySingleton getInstance2(){
        if(lazySingleton==null){
            synchronized (LazySingleton.class){
                if(lazySingleton==null){
                    lazySingleton=new LazySingleton();
                    //1、分配内存给这个对象
                    //2、初始化对象
                    //3、设置lazysingleton指向刚分配的内存地址
                }
            }
        }
        return lazySingleton;
    }
}
内部类:
package com.wanda.singleton;

import java.lang.reflect.Constructor;

/**
 * 这种形式兼顾了饿汉式内存浪费问题和synchronized性能问题
 */
public class LazyInnerSingleton {
   // private LazyInnerSingleton(){}
    //修改后的构造方法
    private LazyInnerSingleton(){
        if(LazyHolder.lazy!=null){
            throw new RuntimeException("不允许创建多个实例");
        }
    }
    public static final  LazyInnerSingleton getInstance(){
        return LazyHolder.lazy;
    }

    //内部类在方法调用之前初始化,避免了线程不安全的问题
    private static class LazyHolder{
        private static final LazyInnerSingleton lazy=new LazyInnerSingleton();
    }

    public static void main(String[] args) {
        //反射破坏单例情况,通过这种方式会创建两个不同的单例。可以在构造方法中做一些限制,一旦多次重复创建就抛出异常。
        try {
            Class<?> clazz=LazyInnerSingleton.class;
            Constructor constructor=clazz.getDeclaredConstructor(null);
            //强制访问
            constructor.setAccessible(true);
            Object o1=constructor.newInstance();
            Object o2=constructor.newInstance();
            System.out.println(o1==o2);
        }catch (Exception e){
            e.printStackTrace();
        }

    }
}
序列化破坏单例
package com.wanda.singleton;

import java.io.*;

//一个单例对象创建后,有时需要序列化到磁盘,下次使用时在从磁盘读入,进行反序列化,反序列华的对象会重新分配内存
//即重新创建,如果序列化的对象是单例,就违背了单例的意义。
public class SeriableSingleton  implements Serializable {
    public static final 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=null;
        SeriableSingleton s2=SeriableSingleton.getInstance();
        FileOutputStream fos=null;
        try {
            fos=new FileOutputStream("seriablesingleton.obj");
            ObjectOutputStream os=new ObjectOutputStream(fos);
            os.writeObject(s2);
            os.flush();
            os.close();

            FileInputStream fis=new FileInputStream("seriablesingleton.obj");
            ObjectInputStream ois=new ObjectInputStream(fis);
            s1=(SeriableSingleton) ois.readObject();
            ois.close();
            System.out.println(s1);
            System.out.println(s2);
            System.out.println(s1==s2);//false 解决方法:加上readResolve方法
        }catch (Exception e){

        }
    }
}
枚举:
package com.wanda.singleton;

import java.io.*;

//一个单例对象创建后,有时需要序列化到磁盘,下次使用时在从磁盘读入,进行反序列化,反序列华的对象会重新分配内存
//即重新创建,如果序列化的对象是单例,就违背了单例的意义。
public class SeriableSingleton  implements Serializable {
    public static final 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=null;
        SeriableSingleton s2=SeriableSingleton.getInstance();
        FileOutputStream fos=null;
        try {
            fos=new FileOutputStream("seriablesingleton.obj");
            ObjectOutputStream os=new ObjectOutputStream(fos);
            os.writeObject(s2);
            os.flush();
            os.close();

            FileInputStream fis=new FileInputStream("seriablesingleton.obj");
            ObjectInputStream ois=new ObjectInputStream(fis);
            s1=(SeriableSingleton) ois.readObject();
            ois.close();
            System.out.println(s1);
            System.out.println(s2);
            System.out.println(s1==s2);//false 解决方法:加上readResolve方法
        }catch (Exception e){

        }
    }
}
容器式:
package com.wanda.singleton;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 容器式单例模式:非线程安全
 */
public class ContainerSingleton {
    private ContainerSingleton(){}
    private static Map<String,Object> map=new ConcurrentHashMap<>();
    public static Object getBean(String clazzName){
        synchronized (map){
            if(!map.containsKey(clazzName)){
                Object obj=null;
                try{
                    obj=Class.forName(clazzName).newInstance();
                    map.put(clazzName,obj);


                }catch (Exception e){
                    e.printStackTrace();
                }
                return obj;
            }else{
                return map.get(clazzName);
            }
        }
    }
}