所谓设计模式就是软件开发人员对于软件开发过程的一种出色的方案
单例模式
使一个类有且仅有一个实例,并且自行实例化向整个系统提供
其目的是为了让类的一个对象成为该类系统中的唯一实例
要求
- 只能有一个实例
- 必须自行创建实例
- 而且得向整个系统提供这个实例,供其访问与使用
实现方法
- 只提供
私有
的构造方法 - 含有一个该类的
静态
私有对象 - 提供一个
静态
的共有方法用于创建、获取静态私有对象
代码实现方案
饿汉式
在类中私有对象创建的过程中即可完成实例化
特征:采用空间
换时间
,对象直接实例化在那儿,不管用还是不用,在类加载的时候,对象就已经完成了初始化,不过同时存在的周期也很长,因此更加费空间一点
package com.jachie.singleton;
/**
* 饿汉式
* @author 哒哒哒
*
*/
public class SingletonOne {
// 创建私有构造
private SingletonOne(){ }
// 含有一个该类的静态私有对象——创建后就初始化
private static SingletonOne instance = new SingletonOne();
// 提供一个静态的共有方法用于创建、获取静态私有对象
public static SingletonOne getInstance() {
return instance;
}
}
懒汉式
在静态公有方法中进行实例化,只有在用的时候才会实例化
特征:采用时间
换空间
,相比饿汉式
而言,懒汉式
在类加载的时候并不会去初始化对象,而是在使用的时候才会去初始化对象,如果一直不用则一直不会有空间的消耗。
package com.jachie.singleton;
/**
* 懒汉式:实例对象不会直接初始化,直到第一次调用的时候才会初始化
* @author 哒哒哒
*
*/
public class SingletonTwo {
// 创建私有构造
private SingletonTwo(){ }
// 含有一个该类的静态私有对象——创建后为空
private static SingletonTwo instance = null;
// 提供一个静态的共有方法用于创建、获取静态私有对象
public static SingletonTwo getInstance() {
// 判断是否为空,为空则实例化
if(instance == null)
instance = new SingletonTwo();
return instance;
}
}
问
:为什么用静态方法?
答
:因为对于单例模式而言,需要在类没有产生对象的情况下进行方法的调用,而实现此则需要设置static
多线程安全问题
当程序出现多线程并发执行的时候,会有多个线程同时进行操作,就是同一时刻做多件事儿,而饿汉式是在类加载的时候就对访问对象
进行了创建,因此对象是唯一的,而懒汉式是在第一次调用的时候才会用到,因此容易出错,那么线程容易出错,出错在哪儿:
public class SingletonTwo {
private SingletonTwo(){ }
private static SingletonTwo instance = null;
// 提供一个静态的共有方法用于创建、获取静态私有对象
public static SingletonTwo getInstance() {
// 判断是否为空,为空则实例化
if(instance == null){ // 1.
instance = new SingletonTwo(); // 2.
}
return instance;
}
}
观察上方代码,线程A在
1.
处交出时间片,线程A暂停,由线程B重新开始执行,当线程B执行返回singleton对象
后,此时线程A继续,从暂停的地方开始,线程A将会执行2.
处代码,从而没有进行空值的判断,线程A执行后将会再返回一个singleton对象
。
这就是线程不安全出现的问题
因此解决懒汉式线程安全的方法也有实际的解决方法
使用场景
- 创建对象时占用资源过多,但又同时需要用到该类的对象
- 对系统内资源要求统一读写,如读写配置信息
- 当多个实例存在可能引起程序逻辑错误,如
号码生成器
缺点
- 扩展困难
- 如果实例化以后对象长期不使用,系统将默认为垃圾进行回收,造成对象状态丢失