软件开发中有很多常见的 "问题场景". 针对这些问题场景, 大佬们总结出了一些固定的套路,这些套路就被称为设计模式
而我们今天要介绍的就是设计模式中的单例模式
单例模式的定义
单例模式是一种常见的设计模式,它确保一个类只有一个实例,并提供一个全局访问点。这在需要控制资源访问、限制对象数量、或者跨系统访问时非常有用。
单例模式具体的实现方式, 分成 "饿汉" 和 "懒汉" 两种.
懒汉式单例:在第一次被调用时创建实例
示例代码如下:
public class SingleTon {//我们要创建的实例instance,因为全局只会存在一个,所以要加上staticprivate static SingleTon instance;//构造方法要手动设成private的,不然外部可以随意创建实例,违背了一个实例的初衷private SingleTon(){}//获取instance的方法,如果instance为null就创建一个,所以也要加上staticpublic static SingleTon getInstance(){if(instance==null){instance=new SingleTon();}return instance;}//最后返回instance
}
饿汉式单例:在类加载时就创建实例
示例代码如下:
public class SingleTon2 {我们要创建的实例instance,饿汉模式直接创建private static final SingleTon2 instance=new SingleTon2();private SingleTon2(){};//因为已经创建了,直接返回就行了public static SingleTon2 getInstance(){return instance;}}
单例模式的安全隐患
上面的懒汉模式的代码在单线程中是没有问题的,但在多线程中就有安全隐患了
首次创建实例时. 如果在多个线程中同时调用 getInstance 方法, 就可能导致 创建出多个实例
加上 synchronized 可以改善这里的线程安全问题.
package Singleton;public class SingleTon {private static SingleTon instance;private SingleTon(){}//加上synchronized关键字public static synchronized SingleTon getInstance(){if(instance==null){instance=new SingleTon();}return instance;}}
不清楚synchronized的可以参考Java中的监视器锁 (synchronized 关键字)-CSDN博客
当我们加上锁后,线程确实安全了,但我们每次获取instance实例时,即使用getInstance()方法时都要加锁,明明只有首次创建实例才需要加锁,后面都不需要加锁了,这就造成了很多多余的开销
所以我们改成getInstance()方法内部判断要不要加锁
代码如下:
public class SingleTon {//加上volatile关键字可以让instance每次使用时强制刷新,避免数据没有及时更新private static volatile SingleTon instance;private SingleTon(){}public static SingleTon getInstance(){//首先判断instance是不是null,如果是就进入方法if(instance==null){//注意这里,因为前面的if是没有加锁的,所以可能同时有多个线程进入方法synchronized (SingleTon.class){//进入锁中,此时因为前面可能有多个线程进入if语句,所以再判断一下if(instance==null){instance=new SingleTon();}}}return instance;}
}
到这里,关于单例模式的讲解就结束了~