应用场景:程序or系统运行期间中,某个类被要求仅能产生唯一的一个对象,以供使用。
- 单例模式的定义:保证一个类仅会产生一个对象,且对外提供一个可被访问的方法。
- 一个类能够被创建多个对象的根源,在于类的构造方法是公开的,外部可以通过构造方法去创建多个对象。
- 想要控制一个类只能创建一个对象,首先要把外部能创建对象的权限收回,让类自身完成对象的创建工作。其次让类提供一个对外公开的方法间接的去访问对象。这就是单例模式的实现方式。
- 单例模式分为懒汉式和饿汉式,区别在类创建对象时实现方式不同。
懒汉式
// 单例示例 懒汉式
public class Singleton {
// 定义一个变量来存储创建好的对象 ,此变量要在静态方法中使用,所以需要加上static修饰
private static Singleton uniqueInstance = null;
// 私有化构造方法,禁止外部创建对象,且好在内部控制创建实例的数目
private Singleton(){
}
/**
* 该方法为外部提供唯一的一个对象,该方法需要定义成类方法,由类本身创建去
* 对象,如果不加static,此方法就变成实例方法,必须先有对象才能调用,而该方法
* 就是来获得对象的,这样以来变成死循环。有static,就可以直接通过类调用方法
* 获得对象
*/
public static synchronized Singleton getInstance(){
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
// 示意方法,单例可以有自己的操作
public void singletonOperation(){
}
// 示意属性,单例可以有自己的属性
private String singletonData;
// 示意方法,让外部通过这些方法来访问属性的值
public String getSingletonData(){
return singletonData;
}
}
懒汉式:比较懒,只有在第一次使用时才进行对象的创建。因此装载对象的时候不创建对象,
private static Singleton uniqueInstance = null;
饿汉式
// 饿汉式单例实现的示例
public class Singleton {
// 定义变量来存储创建好的类实例,直接在这里创建类实例,static只会创建一次
private static Singleton uniqueInstance = new Singleton();
// 私有化构造方法,好在内部控制创建实例的数目
private Singleton(){
//
}
// 定义一个方法来为客户端提供类实例
public static Singleton getInstance(){
//直接使用已经创建好的实例
return uniqueInstance;
}
// 示意方法,单例可以有自己的操作
public void singletonOperation(){
//功能处理
}
// 示意属性,单例可以有自己的属性
private String singletonData;
// 示意方法,让外部通过这些方法来访问属性的值
public String getSingletonData(){
return singletonData;
}
}
饿汉式:既然饿,那么在创建对象的时候就比较着急,于是在装载类的时候就创建了对象。
private static Singleton uniqueInstance = new Singleton();
使用了static的特性。
调用顺序示意图
衍生思想
- 延迟加载的思想:一开始不要加载数据或者资源,等马上要被使用了,才去加载。很节约资源
- 缓存思想:把频繁使用到的数据,缓存到内存中,每次操作的时候,先到内存里查找,有直接拿来用,没有就去获取它。下次访问的时候节约大量的时间,是一种空间换时间的方案。
- 懒汉式线程不安全,饿汉式线程安全,虚拟机保证只会装载一次,装载类的时候不会出现并发。
- 另一种巧妙的实现单例模式
public class Singleton {
// 定义静态成员内部类,该内部类的实例与外部类的实例
// 没有绑定关系, 而且只有被调用到才会装载,从而实现了延迟加载
private static class SingletonHolder{
// 静态初始化器,由JVM来保证线程安全
private static Singleton instance = new Singleton();
}
// 私有化构造方法
private Singleton(){
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
- 使用枚举实现单例模式
/**
* 使用枚举来实现单例模式的示例
*/
public enum Singleton {
/**
* 定义一个枚举的元素,它就代表了Singleton的一个实例
*/
uniqueInstance;
/**
* 示意方法,单例可以有自己的操作
*/
public void singletonOperation(){
//功能处理
System.out.println("aa=="+Singleton.uniqueInstance.hashCode());
}
}
public class Client {
public static void main(String[] args) {
for(int i=0;i<3;i++){
Singleton.uniqueInstance.singletonOperation();
}
}
}
- 单例模式的本质:控制对象的数目。
- 何时选择单例模式:需要控制住类的实例只有一个,且外部只能从一个访问点访问实例,此时需要用到单例模式。
留一个小思索:
现在需要一个类产生3个固定的对象,而不是1个。此时该怎么办呢?