欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java 单例设计模式 常见4种

程序员文章站 2022-07-14 10:40:19
...

适合功能场景

  • 配置文件读写对象, 数据库连接池, Spring的 IOC容器 ApplicationContext, Windows的任务管理/回收站等

主要特点

  1. 单例类只能实例化一次
  2. 提供唯一全局访问入口来获取该实例

饿汉式单例 Eager loading(立即加载方式)

  • 项目启动时类被加载, 对象与之同时实例化
  • 除非项目重启否者对象不会有变化, 也就是线程安全的

public class EagerSingleton implements Serializable {
    private static final long serialVersionUID = 7073777279565036708L;

    private static volatile EagerSingleton instance = new EagerSingleton();

    /**
     * 为了防止通过反射机制实例化构造方法抛异常
     * */
    private EagerSingleton() {
        if(instance != null){
            throw new RuntimeException("不允许被反射实例化");
        }
    }

    public static EagerSingleton getInstance() {
        return instance;
    }

    /**
     * readResolve方法的作用为防止序列化单例时破坏唯一实例的规则
     * */
    private Object readResolve() throws ObjectStreamException {
        return instance;
    }

}

public class App {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                System.out.println("EagerSingleton > " + Thread.currentThread().getName() + " > " + EagerSingleton.getInstance());
            });
            thread.start();
        }
    }

}

EagerSingleton > Thread-0 > [email protected]
EagerSingleton > Thread-1 > [email protected]
EagerSingleton > Thread-2 > [email protected]
EagerSingleton > Thread-3 > [email protected]
EagerSingleton > Thread-4 > [email protected]
EagerSingleton > Thread-5 > [email protected]
EagerSingleton > Thread-6 > [email protected]
EagerSingleton > Thread-7 > [email protected]
EagerSingleton > Thread-8 > [email protected]
EagerSingleton > Thread-9 > [email protected]

懒汉式单例 Lazy Loading(延迟加载方式)

  • 类被加载时, 对象不被实例化. 此单例是通过类提供的全局访问入口来获取对象或实例化首个实例后获取对象
  • 注: 懒汉式由于有线程安全问题必须做双重检查并加锁

public final class LazySingleton implements Serializable {
    private static final long serialVersionUID = -5683703520820349246L;

    private static volatile LazySingleton instance = null;

    /**
     * 为了防止通过反射机制实例化构造方法抛异常
     * */
    private LazySingleton() {
        if (instance != null) {
            throw new RuntimeException("不允许被反射实例化");
        }
    }

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

    /**
     * readResolve方法的作用为防止序列化单例时破坏唯一实例的规则
     * */
    private Object readResolve() throws ObjectStreamException {
        return instance;
    }

}

public class App {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                System.out.println("LazySingleton > " + Thread.currentThread().getName() + " > " + LazySingleton.getInstance());
            });
            thread.start();
        }
    }

}

LazySingleton > Thread-0 > [email protected]
LazySingleton > Thread-1 > [email protected]
LazySingleton > Thread-2 > [email protected]
LazySingleton > Thread-3 > [email protected]
LazySingleton > Thread-4 > [email protected]
LazySingleton > Thread-5 > [email protected]
LazySingleton > Thread-6 > [email protected]
LazySingleton > Thread-7 > [email protected]
LazySingleton > Thread-8 > [email protected]
LazySingleton > Thread-9 > [email protected]

枚举单例

  • Java虚拟机默认防止了枚举类型的序列化和反射破坏, 所以构造方法无需抛异常以及无需加 readResolve方法

public enum EnumSingleton {
    INSTENCE;

    private EnumSingleton() {}

    private Object data;

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public static EnumSingleton getInstance() {
        return INSTENCE;
    }

}

public class App {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                System.out.println("EnumSingleton > " + Thread.currentThread().getName() + " > " + EnumSingleton.getInstance());
            });
            thread.start();
        }
    }

}

EnumSingleton > Thread-0 > INSTENCE
EnumSingleton > Thread-1 > INSTENCE
EnumSingleton > Thread-2 > INSTENCE
EnumSingleton > Thread-3 > INSTENCE
EnumSingleton > Thread-4 > INSTENCE
EnumSingleton > Thread-5 > INSTENCE
EnumSingleton > Thread-6 > INSTENCE
EnumSingleton > Thread-7 > INSTENCE
EnumSingleton > Thread-8 > INSTENCE
EnumSingleton > Thread-9 > INSTENCE

ConcurrentHashMap容器单例

  • 通过 ConcurrentHashMap管理多个对象, 虽然它本身是线程安全的但获取实例的方法不是, 所以需要使用同步锁

public class ContainerSingleton {
    private ContainerSingleton() {}

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

    public static Object getBean(final String className) {
        if (className != null && !"".equals(className)) {
            synchronized (className) {
                if (ioc.containsKey(className)) {
                    return ioc.get(className);
                }
                Object obj = null;
                try {
                    obj = Class.forName(className).newInstance();
                    ioc.put(className,obj);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return obj;
            }
        }
        return null;
    }

}

/**
 * 此测试类需通过反射机制实例化, 所以必须有无参构造方法
 * */
public class TestA {
    private Integer id;
    private String name;

    public TestA() {}

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class App {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(() -> {
                System.out.println("ContainerSingleton > " + Thread.currentThread().getName() +
                        " > " + ContainerSingleton.getBean("com.test.web4.singleton.TestA"));
            });
            thread.start();
        }
    }

}

ContainerSingleton > Thread-0 > [email protected]
ContainerSingleton > Thread-1 > [email protected]
ContainerSingleton > Thread-2 > [email protected]
ContainerSingleton > Thread-3 > [email protected]
ContainerSingleton > Thread-4 > [email protected]
ContainerSingleton > Thread-5 > [email protected]
ContainerSingleton > Thread-6 > [email protected]
ContainerSingleton > Thread-7 > [email protected]
ContainerSingleton > Thread-8 > [email protected]
ContainerSingleton > Thread-9 > [email protected]

如果您觉得有帮助,欢迎点赞哦 ~ 谢谢!!