3.设计模式-单例模式(创建型)

资料:https://gitee.com/chuanqi1995/java

什么是单例模式?

保证整个程序中只有一个类的实例叫做单例模式

饿汉式

饿汉式

package hungry;

/**
 * 饿汉式
 * 优点:效率高,线程安全
 * 缺点:有可能浪费空间
 */
public class HungrySingleton {
    private static HungrySingleton hungrySingleton = new HungrySingleton();

    private HungrySingleton() {
    }

    public static HungrySingleton get(){
        return hungrySingleton;
    }
}

饿汉式 - 静态代码块

package hungry;

public class HungryStaticSingleton {
    private static HungryStaticSingleton hungryStaticSingleton;
    private HungryStaticSingleton() {
    }
    static {
        hungryStaticSingleton = new HungryStaticSingleton();
    }
    public static HungryStaticSingleton get(){
        return hungryStaticSingleton;
    }
}

懒汉式

懒汉式

package lazy;

/**
 * 懒汉式
 * 优点:节省空间,线程安全
 * 缺点:效率太慢
 */
public class LazySingleton {
    private static LazySingleton lazySingleton = null;
    private LazySingleton() {
    }
    public synchronized static LazySingleton get(){
        if(null == lazySingleton){
            return new LazySingleton();
        }
        return lazySingleton;
    }
}

懒汉式 - 双重检查锁

package lazy;

/**
 * 懒汉式 - 双重检查锁
 * 优点:线程安全,节省空间
 * 缺点:代码可读性差
 */
public class LazyDoubleCheckSingleton {
    private static volatile LazyDoubleCheckSingleton lazySingleton = null;
    private LazyDoubleCheckSingleton() {
    }
    public static LazyDoubleCheckSingleton get(){
        // 校验是否加锁
        if(null == lazySingleton){
            synchronized (LazyDoubleCheckSingleton.class){
                // 校验是否可以实例化
                if(null == lazySingleton){
                    lazySingleton = new LazyDoubleCheckSingleton();
                    // 有指令重排序问题
                    // lazySingleton = new LazyDoubleCheckSingleton(); 这行代码 在JVM底层有三个操作
                    // 1、开辟空间
                    // 2、对象实例化new
                    // 3、指针指向
                }
            }
        }
        return lazySingleton;
    }
}

懒汉式 - 内部类

package lazy;

/**
 * 懒汉式 - 内部类
 * 优点:节省空间、线程安全,代码复杂度低,不可以被反射破坏
 * 缺点:可读性又变差了
 */
public class LazyStaticInnerClassSingleton {

    private LazyStaticInnerClassSingleton(){
        if(LazyHolder.instance != null){
            throw new RuntimeException("非法访问");
        }
    }
    public static LazyStaticInnerClassSingleton get(){
        return LazyHolder.instance;
    }
    private static class LazyHolder{
        private static LazyStaticInnerClassSingleton instance = new LazyStaticInnerClassSingleton();
    }
}

注册式

注册式 - 枚举

package register;

/**
 * 注册式 - 枚举类
 * 优点:节省空间、线程安全,代码复杂度低,不可以被反射破坏,可读性好
 * 缺点:如果枚举类多的话,浪费内存
 */
public enum EnumSingleton {
    INSTANCE;
    public static EnumSingleton get(){
        return INSTANCE;
    }
}

注册式 - 容器

package register;

import java.util.HashMap;
import java.util.Map;

/**
 * 注册式 - 容器类
 * 优点:节省空间、线程安全,代码复杂度低,不可以被反射破坏,可读性好
 * 缺点:可以被反序列化破坏
 */
public class ContainerSingleton {
    private ContainerSingleton(){

    }
    private static volatile Map<String, Object> ioc = new HashMap<>();
    public static Object get(String className) throws Exception {
        if(!ioc.containsKey(className)){
            synchronized (ContainerSingleton.class){
                if(!ioc.containsKey(className)){
                    Object o = Class.forName(className).newInstance();
                    ioc.put(className, o);
                    return ioc.get(className);
                }else{
                    return ioc.get(className);
                }
            }
        }else {
            return ioc.get(className);
        }
    }


}
package register;

import java.io.Serializable;

public class User {
}

ThreadLocal式

ThreadLocal式

package threadlocal;

public class ThreadLocalSingleton {
    private ThreadLocalSingleton(){

    }
    private static ThreadLocal<ThreadLocalSingleton> threadLocal = new ThreadLocal<ThreadLocalSingleton>(){
        @Override
        protected ThreadLocalSingleton initialValue() {
            return new ThreadLocalSingleton();
        }
    };
    public static ThreadLocalSingleton get(){
        return threadLocal.get();
    }
}

问题

反射

被反射破坏

package lazy;

/**
 * 懒汉式 - 内部类
 * 优点:节省空间、线程安全,代码复杂度低,不可以被反射破坏
 * 缺点:可读性又变差了
 */
public class LazyStaticInnerClassSingleton {

    private LazyStaticInnerClassSingleton(){

    }
    public static LazyStaticInnerClassSingleton get(){
        return LazyHolder.instance;
    }
    private static class LazyHolder{
        private static LazyStaticInnerClassSingleton instance = new LazyStaticInnerClassSingleton();
    }
}
package lazy;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;

public class Test {
    public static void main(String[] args) throws Exception {
        LazyStaticInnerClassSingleton l = LazyStaticInnerClassSingleton.get();
        System.out.println(l);

        Class<LazyStaticInnerClassSingleton> clazz = LazyStaticInnerClassSingleton.class;
        Constructor<LazyStaticInnerClassSingleton> declaredConstructor = clazz.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        LazyStaticInnerClassSingleton lazyStaticInnerClassSingleton = declaredConstructor.newInstance();
        System.out.println(lazyStaticInnerClassSingleton);
    }
}

防止被反射破坏

package lazy;

/**
 * 懒汉式 - 内部类
 * 优点:节省空间、线程安全,代码复杂度低,不可以被反射破坏
 * 缺点:可读性又变差了
 */
public class LazyStaticInnerClassSingleton {

    private LazyStaticInnerClassSingleton(){
        if(LazyHolder.instance != null){
            throw new RuntimeException("非法访问");
        }
    }
    public static LazyStaticInnerClassSingleton get(){
        return LazyHolder.instance;
    }
    private static class LazyHolder{
        private static LazyStaticInnerClassSingleton instance = new LazyStaticInnerClassSingleton();
    }
}

反序列化

被反序列化破坏

package register;

import java.util.HashMap;
import java.util.Map;

/**
 * 注册式 - 容器类
 * 优点:节省空间、线程安全,代码复杂度低,不可以被反射破坏,可读性好
 * 缺点:可以被反序列化破坏
 */
public class ContainerSingleton {
    private ContainerSingleton(){

    }
    private static volatile Map<String, Object> ioc = new HashMap<>();
    public static Object get(String className) throws Exception {
        if(!ioc.containsKey(className)){
            synchronized (ContainerSingleton.class){
                if(!ioc.containsKey(className)){
                    Object o = Class.forName(className).newInstance();
                    ioc.put(className, o);
                    return ioc.get(className);
                }else{
                    return ioc.get(className);
                }
            }
        }else {
            return ioc.get(className);
        }
    }


}
package register;

import java.io.Serializable;

public class User implements Serializable {

}
package register;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Test {
    public static void main(String[] args) throws Exception {
        User u1 = (User) ContainerSingleton.get("register.User");

        // 序列化 内存中的Java对象 -> 磁盘
        // 反序列化 磁盘 —> 内存中的Java对象

        // 序列化
        FileOutputStream fileOutputStream = new FileOutputStream("obj.user");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(u1);
        fileOutputStream.close();
        objectOutputStream.close();

        // 反序列化
        FileInputStream fileInputStream = new FileInputStream("obj.user");
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        User u2 = (User) objectInputStream.readObject();
        fileInputStream.close();
        objectInputStream.close();

        System.out.println(u1);
        System.out.println(u2);
    }
}

防止被反序列化破坏

package register;

import java.io.Serializable;

public class User implements Serializable {
    private Object readResolve() throws Exception {
        return ContainerSingleton.get("register.User");
    }
}

总结

只有注册式 - 枚举不会被反射破坏和反序列化破坏,其余都会

posted @ 2022-03-16 22:53  Java-Legend  阅读(24)  评论(0编辑  收藏  举报