单例模式
设计原则:无
常用场景:应用中有对象需要是全局的且唯一
使用概率:99.99999%
复杂度:低
变化点:无
选择关键点:一个对象在应用中出现多个实例是否会引起逻辑上或者是程序上的错误
逆鳞:在以为是单例的情况下,却产生了多个实例
相关设计模式
原型模式:单例模式是只有一个实例,原型模式每拷贝一次都会创造一个新的实例。
常用场景:
1.需要频繁实例化然后销毁的对象。
2.创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
3.有状态的工具类对象。
4.频繁访问数据库或文件的对象。
以下都是单例模式的经典使用场景:
1.资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
2.控制资源的情况下,方便资源之间的互相通信。如线程池等。
优点:
1.在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就 防止其它对象对自己的实例化,确保所有的对象都访问一个实例
2.单例模式具有一定的伸缩性,类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩性。
3.提供了对唯一实例的受控访问。
4.由于在系统内存中只存在一个对象,因此可以 节约系统资源,当 需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。
5.允许可变数目的实例。
6.避免对共享资源的多重占用。
缺点:
1.不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
2.由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
3.单例类的职责过重,在一定程度上违背了“单一职责原则”。
4.滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。
基本思想
1.在类中实例化一个私有对象
2.构造方法私有化
3.提供一个静态方法返回实例化的对象
现有的一些单例模式区别主要在
1.类加载时 直接进行对象初始化 增大项目启动时系统开销
类加载时不初始化 在方法中判断空 进行初始化
2.并发
直接初始化 不存在并发、产生多对象、非单例问题
使用时初始化 要考虑 初始化方式 防止并发可能产生 多实例问题
在实际使用场景中,不推荐使用直接初始化的方式。
public class Singleton {
private Singleton() {
}
/*
//最基本方式 但是会引起并发创建多实例问题 一定不能用
private static Singleton singleton;
public static Singleton getInstance() {
if (singleton==null) {
singleton = new Singleton();
}
return singleton;
}
*/
/*
//直接方法同步 不会存在并发多实例问题 但设计很糟糕在获取实例时会产生等待 不推荐
private static Singleton singleton;
public synchronized static Singleton getInstance() {
if (singleton==null) {
singleton = new Singleton();
}
return singleton;
}
*/
/*
//双重加锁 使用类实例进行加锁
//只是看起来好很多,在Java指令中创建对象和赋值操作是分开进行的,也就是说instance = new Singleton();
// 语句是分两步执行的。但是JVM并不保证这两个操作的先后顺序,也就是说有可能JVM会为新的Singleton实例分配空间,
// 然后直接赋值给instance成员,然后再去初始化这个Singleton实例。这样就可能出错了
private static Singleton singleton;
public static Singleton getInstance() {
if (singleton==null) {
synchronized (Singleton.class) {
if (singleton==null) {
singleton = new Singleton();
}
}
}
return singleton;
}
*/
//终极模式 使用内部类
//主要依据static 只会在jvm加载类时初始化一次,即内部类中 instance 由jvm保证了只初始化一次
private static class SingletonFactory {
private static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonFactory.instance;
}
}