单例模式

单例模式是创建型模式,结合创建型和单例这两个关键词,我们不难想出单例模式就是保证一个类只有一个实例,每次"创建"这个类的时候都是返回这同一个实例,这就涉及到了两个问题,怎么保证只有一个实例,什么时候创建这个实例,这里我们还是用java语言来说

怎么保证只有一个实例

把这个类的构造方法设置为private,这样就无法new获得这个对象的实例了,但是这里有个小问题,就是序列化然后反序列这个对象是不经过构造函数的,可能会无法保证只有一个实例,为了解决这个问题我们可以为类加上如下函数

  private Object readResolve() {
    return  singleton;  //返回这个单实例
  }

这样就能保证反序列化之后得到的实例也是同一个。

我们也可以使用枚举类来实现单例模式,枚举类天然支持保证单实例的反序列化,不过使用枚举类有些不易理解。

public enum Single {
    // 唯一枚举:
	INSTANCE;

	private String name = "single";

	public String getName() {
		return this.name;
	}

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

什么时候创建这个实例

我们可以在类加载的时候就创建这个实例

public class Singleton {

    private static final Singleton instance = createInstance()
    
    private static Singleton createInstance() {
        return new Singleton();
    }

    private Singleton() {
    }

    public static Singleton getInstance() {
        return instance;
    }
}

静态变量是在类加载的时候初始化这个实例的,这时候就有人会说,加载时就创建,一旦之后我们没有用到,那多浪费空间啊,还是用到的时候在加载比较好,这就是懒加载,

public class Singleton {
    private static final Singleton instance = null;

    public static Singleton getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new Singleton();
        }
        return INSTANCE;
    }
    private Singleton() {
    }
}

单线程貌似没什么问题,要是多个线程并发的情况下可能就会创建多个实例,接下来应该想到的就是对方法加锁解决这个问题,但是加锁影响并发性能,接着就是双重检查性能会稍微好一些[代码来自廖大的博客,懒得写了复制一下]

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

总结

单例模式就是实例唯一,但是我们不一定需要强制的编写代码让他唯一,也可以用约定的方式,比如Spring容器,我们把bean注册在容器里,我们要用的时候再去取,我们先不考虑Spring 容器是怎么处理的,从我们注册bean到取出使用这个实例的流程就是单例。

posted @ 2020-04-18 21:30  林静生寒  阅读(185)  评论(0编辑  收藏  举报