单例设计模式:单例模式一共多少种?细分的话可达8种
说到单例模式,大家应该都有所了解,懒汉式、饿汉式马上浮上心头。
那么懒汉式和饿汉式有什么区别?除了常见的两种,还有别的实现单例模式的方法吗?
1、单例模式的概念(个人总结非官方):
单例顾名思义就是程序运行中,最多只能有一个实例化的对象。(至于为什么这里不做介绍)
2、懒汉式、饿汉式的区别:
区别实际上体现在加载时间上,饿汉式是在类加载的时候就加载;懒汉式是需要用到该实例时才加载。
使用饿汉式的话,不管你用不用得到这个实例,它都会在类加载的时候加载;假如我一直没使用到这个实例,是不是就浪费资源了?
使用懒汉式的话,用到时候才会去加载,资源的利用上更为合理。
总结:如果确定某个单例一定会用上,饿汉式是一种很合适方法;如果不一定会用的某个单例,懒汉式是比较合适的方法。
2、单例模式的实现
2.1、饿汉式
方法1:静态变量方式(线程安全)
/*1.将构造方法私有化,外部无法使用new构造方法创建实例*/
private Singleton1() {}
/*2.内部创建对象*/
private static Singleton1 instence = new Singleton1();
/*3.对外获取实例的方法*/
public static Singleton1 getInstence() {
return instence;
}
方法2:静态代码块方式(线程安全)
/*1.将构造方法私有化,外部无法使用new*/
private Singleton2() {}
/*2.内部静态代码块中创建对象*/
private static Singleton2 instence;
static {
instence = new Singleton2();
}
/*3.对外获取实例的方法*/
public static Singleton2 getInstence() {
return instence;
}
2.1、懒汉式
方法3:简单判断非空(多线程并发不安全,单线程无影响)
/*1.将构造方法私有化,外部无法使用new*/
private Singleton3() {}
/*2.创建类成员变量instence*/
private static Singleton3 instence;
/*3.对外获取实例的方法,先判断instence是否为空,为空则创建*/
public static Singleton3 getInstence() {
if(instence == null) {
instence = new Singleton3();
}
return instence;
}
不安全的原因:
方法4:synchronized锁方法(线程安全,但是synchronized锁了整个方法,下一个线程必须等上一个线程释放锁,效率很低,不建议使用)
/*1.将构造方法私有化,外部无法使用new*/
private Singleton4() {}
/*2.创建类成员变量instence*/
private static Singleton4 instence;
/*3.对外获取实例的方法,先判断instence是否为空,为空则创建*/
public static synchronized Singleton4 getInstence() {
if(instence == null) {
instence = new Singleton4();
}
return instence;
}
方法5:同步代码块(多线程并发不安全)
/*1.将构造方法私有化,外部无法使用new*/
private Singleton5() {}
/*2.创建类成员变量instence*/
private static Singleton5 instence;
/*3.对外获取实例的方法,先判断instence是否为空,为空则创建*/
public static Singleton5 getInstence() {
if(instence == null) {
synchronized (Singleton6.class) {
instence = new Singleton5();
}
}
return instence;
}
不安全原因:与之前的描述一致,虽然它加了锁,但是实际上没有起到作用,如果很多线程已经同时进入if语句块内,结果是一样的。
方法6:双重检查(线程安全)这个方法比较常用
/*1.将构造方法私有化,外部无法使用new*/
private Singleton6() {}
/*2.创建类成员变量instence*/
private static volatile Singleton6 instence;
/*3.对外获取实例的方法,双重判断*/
public static Singleton6 getInstence() {
if(instence == null) {
synchronized (Singleton6.class) {
if (instence == null){
instence = new Singleton6();
}
}
}
return instence;
}
方法7:静态内部类(线程安全)这个方法比较常用
/*1.将构造方法私有化,外部无法使用new*/
private Singleton7() {}
/*2.编写一个静态内部类*/
private static class SingletonInstence {
private static final Singleton7 INSTENCE = new Singleton7();
}
/*3.提供一个静态公有方法,直接返回SingletonInstence*/
public static Singleton7 getInstence() {
return SingletonInstence.INSTENCE;
}
方法8:枚举(线程安全,还可以防止反序列化重新生成的对象,推荐使用)这个方法被大佬推荐使用,至于为啥博主暂时未去了解
public class Singleton8{
}
enum Sing{
insance;
public void method(){}
}