前言
这是设计模式的第一篇文章,我们从单例模式开始入手,单例模式是 Java 设计模式中最简单的一种,只需要一个类就能实现单例模式,但是,你可不能小看单例模式,虽然从设计上来说它比较简单,但是在实现当中你会遇到非常多的坑,所以,系好安全带,上车。
单例模式的定义
单例模式就是在程序运行中只实例化一次,创建一个全局唯一对象,有点像 Java 的静态变量,但是单例模式要优于静态变量,静态变量在程序启动的时候JVM就会进行加载,如果不使用,会造成大量的资源浪费,单例模式能够实现懒加载,在使用实例的时候才去创建实例。开发工具类库中的很多工具类都应用了单例模式,比例线程池、缓存、日志对象等,它们都只需要创建一个对象,如果创建多份实例,可能会带来不可预知的问题,比如资源的浪费、结果处理不一致等问题。
单例的实现思路
-
静态化实例对象
-
私有化构造方法,禁止通过构造方法创建实例
-
提供一个公共的静态方法,用来返回唯一实例
单例的好处
-
只有一个对象,内存开支少、性能好
-
避免对资源的多重占用
-
在系统设置全局访问点,优化和共享资源访问
单例模式的实现
单例模式的写法有饿汉模式、懒汉模式、双重检查锁模式、静态内部类单例模式、枚举类实现单例模式五种方式,其中懒汉模式、双重检查锁模式,如果你写法不当,在多线程情况下会存在不是单例或者单例出异常等问题,具体的原因,在后面的对应处会进行说明。我们从最基本的饿汉模式开始我们的单例编写之路。
饿汉模式
饿汉模式采用一种简单粗暴的形式,在定义静态属性时,直接实例化了对象。代码如下:
-
//在类加载时就完成了初始化,所以类加载较慢,但获取对象的速度快
-
public class SingletonObject1 {
-
// 利用静态变量来存储唯一实例
-
private static final SingletonObject1 instance = new SingletonObject1();
-
-
// 私有化构造函数
-
private SingletonObject1(){
-
// 里面可能有很多操作
-
}
-
-
// 提供公开获取实例接口
-
public static SingletonObject1 getInstance(){
-
return instance;
-
}
-
}
饿汉模式的优缺点
优点
-
由于使用了static关键字,保证了在引用这个变量时,关于这个变量的所以写入操作都完成,所以保证了JVM层面的线程安全
缺点
-
不能实现懒加载,造成空间浪费,如果一个类比较大,我们在初始化的时就加载了这个类,但是我们长时间没有使用这个类,这就导致了内存空间的浪费。
懒汉模式
懒汉模式是一种偷懒的模式,在程序初始化时不会创建实例,只有在使用实例的时候才会创建实例,所以懒汉模式解决了饿汉模式带来的空间浪费问题,同时也引入了其他的问题,我们先来看看下面这个懒汉模式
-
public class SingletonObject2