创建型模式--单例模式、原型模式(二)

单例模式

  • 定义:保证一个类仅有一个实例,并提供一个全局访问的点。
  • 适用场景:任何情况下都绝对只有一个实例。
  • 优点:减少内存开销、避免对资源的多重占用、设置全局访问点,严格控制访问
  • 缺点:没有接口,扩展困难。

单例模式下记得 添加私有构造器,防止被外部方法直接new创建。

懒汉模式(线程不安全)

public class LazySingleton {
    private static LazySingleton lazySingleton = null;
    private LazySingleton(){}
    
    /**
     * 有线程安全问题,需要添加synchronized
     * @return
     */
    public synchronized static LazySingleton getInstance(){
        if(lazySingleton == null){
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }
}

DoubleCheck 双重检查

只在第一次初始化时加锁,提高效率。使用volatile消除重排序的隐患。(初始化类和给本地绑定引用,如果先绑定引用,还未初始化完成,其他线程进来,获取到值会直接报错。)

public class DoubleCheckLazySingleton {
    private volatile static DoubleCheckLazySingleton lazySingleton = null;
    private DoubleCheckLazySingleton(){}

    public static DoubleCheckLazySingleton getInstance(){
        if(lazySingleton == null){
            synchronized (DoubleCheckLazySingleton.class){
                if(lazySingleton == null){
                    lazySingleton = new DoubleCheckLazySingleton();
                }
            }
        }
        return lazySingleton;
    }
}

静态内部类

public class StaticInnerSing {

    private static class InnerClass{
        private static StaticInnerSing staticInnerSing = new StaticInnerSing();
    }

    public static StaticInnerSing getInstance(){
        return InnerClass.staticInnerSing;
    }
}

饿汉式

public class HungraySingleton {
    private HungraySingleton(){};
    
    private final static HungraySingleton hungraySingleton = new HungraySingleton(); 
    
    public static HungraySingleton getInstance(){
        return hungraySingleton;
    }
}

解决序列化 破环单例模式原则

把单例类写入文件,读取出来和原来的不是同一个对象。

重写readResolve方法,可以使原则不被破坏

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        HungraySingleton singleton = HungraySingleton.getInstance();
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("single_file"));
        oos.writeObject(singleton);

        File file = new File("single_file");
        ObjectInputStream oin = new ObjectInputStream(new FileInputStream(file));
        HungraySingleton otherSingleton = (HungraySingleton)oin.readObject();

        System.out.println(singleton);
        System.out.println(otherSingleton);
        System.out.println(singleton == otherSingleton);
    }
public class HungraySingleton implements Serializable{
    private HungraySingleton(){};

    private final static HungraySingleton hungraySingleton = new HungraySingleton();

    public static HungraySingleton getInstance(){
        return hungraySingleton;
    }

    private Object readResolve(){
        return hungraySingleton;
    }

反射攻击的解决方案(在私有构造方法内加判断)

public class HungraySingleton implements Serializable{
    private final static HungraySingleton hungraySingleton = new HungraySingleton();

    private HungraySingleton(){
        if(hungraySingleton != null){
            throw new RuntimeException("单例不允许反射构建!!");
        }
    }

    public static HungraySingleton getInstance(){
        return hungraySingleton;
    }

    private Object readResolve(){
        return hungraySingleton;
    }

枚举单例(最推荐的一种方式)

public enum  EnumSingleton {
    DATASOURCE;
    
    private EnumModule module = null;
    private EnumSingleton(){
        module = new EnumModule();
    }

    public EnumModule getInstance(){
        return module;
    }

    public static class EnumModule{}
}

通过threadLocal每个线程获取自己的单例

public class ThreadLocalInstance {
    
    private static final ThreadLocal<ThreadLocalInstance> threadLocalInstance
            = new ThreadLocal<ThreadLocalInstance>(){
        protected ThreadLocalInstance initialvalue(){
            return new ThreadLocalInstance();
        }
    };

    private ThreadLocalInstance(){}

    public static ThreadLocalInstance getInstance(){
        return threadLocalInstance.get();
    }
}

原型模式

定义:原型实例指定创建对象种类,通过拷贝这些原型创建新的对象。不需要知道任何创建细节,不调用构造函数。

适用场景:类初始化消耗资源多,new产生的对象需要非常繁琐的过程。构造函数比较复杂,循环体中产生大量对象。

优点:比直接new性能高,简化创建过程。

缺点:必须配备克隆方法。深拷贝、浅拷贝要运用得当。

原型模式会破坏单例

浅拷贝 

    @Override
     protected Object clone() throws CloneNotSupportedException  {
         return super.clone();
     }

深拷贝


    public Object clone() {
        Date d = null;
        try {
            d = (Date)super.clone();
            if (cdate != null) {
                d.cdate = (BaseCalendar.Date) cdate.clone();
            }
        } catch (CloneNotSupportedException e) {} 
        return d;
    }
发布了123 篇原创文章 · 获赞 2 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_35418518/article/details/104155748
今日推荐