关于设计模式:设计模式单例模式

32次阅读

共计 8318 个字符,预计需要花费 21 分钟才能阅读完成。

单例模式

  • 定义:保障一个类仅有一个实例,并提供一个全局拜访点
  • 类型:创立型
  • 实用场景:想确保任何状况下都相对只有一个实例
  • 长处:

    • 在内存里只有一个实例,缩小了内存开销
    • 能够防止对资源的多重占用
    • 设置全局拜访点,严格控制拜访
  • 毛病:没有接口,扩大艰难
  • 重点:

    • 公有结构器
    • 线程平安
    • 提早加载
    • 序列化和反序列化平安
    • 反射
  • Double Check

  • 动态外部类:

  • 实用技能

    • 反编译
    • 内存原理
    • 多线程 Debug

  • 相干设计模式

    • 单例模式和工厂模式
    • 单例模式和享元模式
代码示例
懒汉式
public class LazySingleton {
    private static LazySingleton lazySingleton;

    private LazySingleton() {}

    /**
     * synchronized(同步锁比拟耗费资源)* 加在静态方法上:锁的是类的 class 文件
     * 加在一般办法上:锁的是堆内存中的对象
     * @return
     */
    public synchronized static LazySingleton getInstance(){// 懒汉式
        if(lazySingleton==null){lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }
}
public class T implements Runnable{
    @Override
    public void run() {LazySingleton lazySingleton = LazySingleton.getInstance();
        System.out.println(Thread.currentThread()+" "+lazySingleton);
    }
}

测试类:

public class Test {public static void main(String[] args) {//        LazySingleton lazySingleton = LazySingleton.getInstance();
        Thread t1  = new Thread(new T());
        Thread t2  = new Thread(new T());
        t1.start();
        t2.start();
        System.out.println("program end");
/*        for (int i = 0; i < 10; i++) {new Thread(new T()).start();}*/
    }
}

双重校验(改良):

public class LazyDoubleCheckSingleton {// volatile 多线程运行代码执行时重排序引起的问题 ( 不容许重排序)
    private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton;

    private LazyDoubleCheckSingleton() {}

    public  static LazyDoubleCheckSingleton getInstance(){// 懒汉式
        if(lazyDoubleCheckSingleton==null){synchronized (LazyDoubleCheckSingleton.class){if (lazyDoubleCheckSingleton==null){lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
                }
            }
        }
        return lazyDoubleCheckSingleton;
    }
}

基于类初始化的提早加载解决方案:

/**
 * 基于类初始化的提早加载解决方案
 */
public class StaticInnerClassSingleton {private StaticInnerClassSingleton() { }

    private static class InnerClass{private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
    }

    public static StaticInnerClassSingleton getInstance(){return InnerClass.staticInnerClassSingleton;}
}
public class T implements Runnable{
    @Override
    public void run() {//        LazySingleton lazySingleton = LazySingleton.getInstance();
//        LazyDoubleCheckSingleton lazyDoubleCheckSingleton = LazyDoubleCheckSingleton.getInstance();
        StaticInnerClassSingleton staticInnerClassSingleton = StaticInnerClassSingleton.getInstance();
        System.out.println(Thread.currentThread()+" "+staticInnerClassSingleton);
    }
}
饿汉式
public class HungrySingleton {// 饿汉式
    // 申明为 final 的变量必须在类加载时实现赋值
    private static final HungrySingleton hungrySingleton;
    static{hungrySingleton = new HungrySingleton();
    }

    private HungrySingleton() {}

    public static HungrySingleton getInstance() {return hungrySingleton;}
}
序列化毁坏单例模式
public class HungrySingleton implements Serializable {// 饿汉式
    // 申明为 final 的变量必须在类加载时实现赋值
    private static final HungrySingleton hungrySingleton;
    static{hungrySingleton = new HungrySingleton();
    }

    private HungrySingleton() {}

    public static HungrySingleton getInstance() {return hungrySingleton;}

    /**
     * 如果不写该办法,反序列化时会通过反射创立一个新的对象并返回,与序列化的对象不是同一对象。* 若写了该办法,则反序列化时,尽管通过反射创立一个新的对象,但会返回该对象。* @return
     */
    private Object readResolve(){return hungrySingleton;}
}
public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException {HungrySingleton instance = HungrySingleton.getInstance();
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
        oos.writeObject(instance);

        File file = new File("singleton_file");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
        HungrySingleton newInstance = (HungrySingleton) ois.readObject();

        System.out.println(instance);
        System.out.println(newInstance);
        System.out.println(instance==newInstance);
    }
}
反射攻打解决方案
public class HungrySingleton implements Serializable {// 饿汉式
    // 申明为 final 的变量必须在类加载时实现赋值
    private static final HungrySingleton hungrySingleton;
    static{hungrySingleton = new HungrySingleton();
    }

    private HungrySingleton() {if (hungrySingleton!=null){throw new RuntimeException("单例结构器禁止反射调用");
        }
    }

    public static HungrySingleton getInstance() {return hungrySingleton;}
}
public class StaticInnerClassSingleton {private StaticInnerClassSingleton() {if (InnerClass.staticInnerClassSingleton!=null){throw new RuntimeException("单例结构器禁止反射调用");
        }
    }

    private static class InnerClass{private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
    }

    public static StaticInnerClassSingleton getInstance(){return InnerClass.staticInnerClassSingleton;}
}
public class LazySingleton {
    private static LazySingleton lazySingleton;

    private LazySingleton() {if (lazySingleton!=null){throw new RuntimeException("单例结构器禁止反射调用");
        }
    }

    public synchronized static LazySingleton getInstance(){// 懒汉式
        if(lazySingleton==null){lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }
}

测试类:

/**
* 能够解决饿汉式的反射攻打,但没有解决懒汉式的反射攻打。*/
public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//        Class hungrySingletonClass = HungrySingleton.class;
//        Class objectClass = StaticInnerClassSingleton.class;

        Class objectClass = LazySingleton.class;

        Constructor constructor = objectClass.getDeclaredConstructor();
        constructor.setAccessible(true);
//        HungrySingleton instance = HungrySingleton.getInstance();
//        HungrySingleton newInstance  = (HungrySingleton) constructor.newInstance();

//        StaticInnerClassSingleton instance = StaticInnerClassSingleton.getInstance();
//        StaticInnerClassSingleton newInstance  = (StaticInnerClassSingleton) constructor.newInstance();

        LazySingleton newInstance = (LazySingleton) constructor.newInstance();
        LazySingleton instance = LazySingleton.getInstance();

        System.out.println(instance);
        System.out.println(newInstance);
        System.out.println(instance==newInstance);
    }
}
Enum 枚举单例

Jad:反编译工具

序列化

public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//        HungrySingleton instance = HungrySingleton.getInstance();
        EnumInstance instance = EnumInstance.getInstance();
        instance.setData(new Object());
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
        oos.writeObject(instance);

        File file = new File("singleton_file");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
//        HungrySingleton newInstance = (HungrySingleton) ois.readObject();
        EnumInstance newInstance = (EnumInstance) ois.readObject();

        System.out.println(instance.getData());
        System.out.println(newInstance.getData());
        System.out.println(instance.getData()==newInstance.getData());
    }
}

反射

public enum EnumInstance {
    INSTANCE{protected void printTest(){System.out.println("Feyl Print Test");
        }
    };
    protected abstract void printTest();
    private Object data;

    public Object getData() {return data;}

    public void setData(Object data) {this.data = data;}
    public static EnumInstance getInstance(){return INSTANCE;}
}
public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {


        Class objectClass = EnumInstance.class;
        Constructor constructor = objectClass.getDeclaredConstructor(String.class,int.class);
        constructor.setAccessible(true);
        EnumInstance instance = (EnumInstance) constructor.newInstance("Feyl",666);

        
//        EnumInstance instance = EnumInstance.getInstance();
//        instance.printTest();}
}
容器单例
public class ContainerSingleton {// 线程不平安
    private static Map<String,Object> singletonMap = new HashMap<>();

    private ContainerSingleton() {}

    public static void putInstance(String key, Object instance){if (!StringUtils.isNotBlank(key)&&instance!=null){if(!singletonMap.containsKey(key)){singletonMap.put(key,instance);
            }
        }
    }

    public static Object getInstance(String key){return singletonMap.get(key);
    }
}
public class T implements Runnable{
    @Override
    public void run() {ContainerSingleton.putInstance("object",new Object());
        Object instance = ContainerSingleton.getInstance("object");
        System.out.println(Thread.currentThread()+" "+instance);
    }
}

测试类:

public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {Thread t1  = new Thread(new T());
        Thread t2  = new Thread(new T());
        t1.start();
        t2.start();
        System.out.println("program end");
    }
}
TreadLocal 线程单例
public class ThreadLocalInstance {
    private static final ThreadLocal<ThreadLocalInstance> threadLocalInstance
            = new ThreadLocal<ThreadLocalInstance>(){
        @Override
        protected ThreadLocalInstance initialValue() {return new ThreadLocalInstance();
        }
    };

    private ThreadLocalInstance(){}

    public static ThreadLocalInstance getInstance() {return threadLocalInstance.get();
    }
}
public class T implements Runnable{
    @Override
    public void run() {ThreadLocalInstance instance = ThreadLocalInstance.getInstance();
        System.out.println(Thread.currentThread()+" "+instance);
    }
}

测试类同上

“以空间换工夫”:ThreadLocal 为每一个线程创立一个空间,各个线程获取其独有的对象。

正文完
 0