共计 3825 个字符,预计需要花费 10 分钟才能阅读完成。
软件设计模式(Software Design Pattern),又称 设计模式,是一套被重复应用、少数人通晓的、通过分类编目标、代码设计教训的总结。它形容了在软件设计过程中的一些一直反复产生的问题,以及该问题的解决方案。
也就是说,它是解决特定问题的一系列套路,是前辈们的代码设计教训的总结,具备肯定的普遍性,能够重复应用。
其目标是为了进步代码的可重用性、代码的可读性和代码的可靠性。
那么咱们明天先来看看在咱们现学习阶段应用特地多的一种设计模式 -单例模式。
首先咱们看看 单例模式 在理论生存中的应用场景:
比方:
公司 CEO、部门经理等都属于单例模型
J2EE 规范中的 ServletContext 和 ServletContextConfig
Spring 框架利用中的 ApplicationContext
数据库中的连接池等也都是单例模式
还比方 Windows 的回收站
操作系统中的文件系统
多线程中的线程池
显卡的驱动程序对象
打印机的后盾解决服务
应用程序的日志对象
数据库的连接池
网站的计数器
Web 利用的配置对象
应用程序中的对话框
零碎中的缓存等经常被设计成单例。
那么这些场合为什么要设计成单例模式呢?单例模式的实现形式有哪些?单例模式的益处和弊病有哪些呢?
带着这些问题咱们一起来具体看看单例模式
1. 什么是单例模式?
单例(Singleton)模式 的定义:指一个类只有一个实例,且该类能自行创立这个实例的一种模式。
例如:Windows 中只能关上一个工作管理器,这样能够防止因关上多个工作管理器窗口而造成内存资源的节约,或呈现各个窗口显示内容的不统一等谬误。
2. 单例模式的实现形式有哪些?
常见的实现形式有:懒汉模式、饥汉模式、双重校验锁、动态外部类、枚举 等形式实现,那咱们咱们紧接着就具体的一个一个的来看看他们的实现
懒汉模式:
/**
* @author hz
* @version 1.0
*/
public class Singleton {
private static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance(){
// 如果还没有被实例化过,就实例化一个,而后返回
if(instance == null){instance = new Singleton();
}
return instance;
}
}
这段代码里,咱们没有思考线程平安,所以可能还是会参数多个实例,所以咱们须要对线程平安问题进行解决,从而得出懒汉模式的优化版
/**
* @author hz
* @version 1.0
*/
public class Singleton {
private static Singleton instance = null;
private Singleton(){}
public static synchronized Singleton getInstance(){
// 如果还没有被实例化过,就实例化一个,而后返回
if(instance == null){instance = new Singleton();
}
return instance;
}
}
通过关键字 synchronized
用于确保 getInstance
办法线程平安,然而这种形式弊病特地大,因为所有线程达到该办法当前须要进行排队等待,所以对性能的损耗十分大,该解决解决了线程平安平安问题,并没有解决效率问题,如果要既要解决线程平安问题又要解决效率问题则须要咱们前面的双重校验锁形式。
懒汉模式 将实例化的机会放到了须要应用的时候(饿汉是类加载了就有实例),也就是“提早加载”,相比饿汉,能防止了在加载的时候实例化有可能用不到的实例,然而问题也很显著,咱们要花精力去解决线程平安的问题。
饿汉模式:
/**
* @author hz
* @version 1.0
*/
public class Singleton {
// 类加载的时候 instance 就曾经指向了一个实例
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){return instance;}
}
饿汉模式相比懒汉模式,在类加载的时候就曾经存在一个实例,举个例子,比方数据库连贯吧,懒汉就是第一次拜访数据库的时候我才去创立一个连贯,而饿汉呢,是你程序启动了,类加载好了的时候,我曾经有个连贯了,你用不必不肯定了,所以饿汉的毛病也就进去了:可能会产生很多无用的实例。
那么加载机会的问题咱们曾经说过了,接下来就是线程平安了,代码里咱们并没有看见 synchronized
关键字,那么这种形式是如何确保线程平安的呢,这个就是 JVM 类加载的个性了,JVM 在加载类的时候,是单线程的,所以能够保障只存在繁多的实例
双重校验锁:
/**
* @author hz
* @version 1.0
*/
public class Singleton {
private static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance(){if(instance == null){synchronized (Singleton.class){if(instance == null){instance = new Singleton();
}
}
}
return instance;
}
}
首先要阐明的是,双重测验锁也是一种提早加载,并且较好的解决了在确保线程平安的时候效率低下的问题,比照一下最原始的那种线程平安的办法(就是懒汉模式的第二种代码),那种办法将整个 getInstance
办法锁住,那么每次调用那个办法都要取得锁,开释锁,期待等等 … 而双重校验锁锁住了局部的代码。进入办法如果查看为空才进入同步代码块,这样很显著效率高了很多。
动态外部类:
/**
* @author hz
* @version 1.0
*/
public class Singleton {
private static class SingletonHolder{private static Singleton instance = new Singleton();
}
private Singleton(){}
public static Singleton getInstance(){return SingletonHolder.instance;}
}
懒汉模式须要思考线程平安,所以咱们多写了好多的代码,饿汉模式利用了类加载的个性为咱们省去了线程平安的思考,那么,既能享受类加载确保线程平安带来的便当,又能提早加载的形式,就是 动态外部类。
Java 动态外部类的个性是:加载的时候不会加载外部动态类,应用的时候才会进行加载。而应用到的时候类加载又是线程平安的,这就完满的达到了咱们的预期成果。
枚举:
/**
* @author hz
* @version 1.0
*/
public enum Singleton {INSTANCE;}
JDK1.5 提供了一个新的数据类型:枚举。
枚举 的呈现提供了一个较为优雅的形式取代以前大量的 static final 类型的变量。而这里,咱们也利用枚举的个性,实现了单例模式,内部调用由原来的 Singleton.getInstance
变成了 Singleton.INSTANCE
了。
以上几种单例模式的实现各自有各自的劣势,所以咱们在理论应用中,须要依据本人的需要进行抉择,而通过上述实现形式咱们能够能够总结一下 单例模式的特点:
1). 单例模式只有一个实例对象;
2). 该单例对象必须由单例类创立;
3). 单例类对外提供一个拜访该单例的全局拜访点。
3. 单例模式的优缺点:
以上咱们具体的比照了几种单例模式的实现形式,那么单例模式有哪些优缺点呢?
长处:
单例模式能够保障内存里只有一个实例,缩小了内存的开销。
能够防止对资源的多重占用。
单例模式设置全局拜访点,能够优化和共享资源的拜访。
毛病:
单例模式个别没有接口,扩大艰难。如果要扩大,则除了批改原来的代码,没有第二种路径,违反开闭准则。
在并发测试中,单例模式不利于代码调试。在调试过程中,如果单例中的代码没有执行完,也不能模仿生成一个新的对象。
单例模式的性能代码通常写在一个类中,如果功能设计不合理,则很容易违反繁多职责准则。
4. 单例模式的 利用场景:
对于 Java 来说,单例模式能够保障在一个 JVM 中只存在繁多实例。
单例模式的利用场景次要有以下几个方面:
须要频繁创立的一些类,应用单例能够升高零碎的内存压力,缩小 GC。
某类只要求生成一个对象的时候,如一个班中的班长、每个人的身份证号等。
某些类创立实例时占用资源较多,或实例化耗时较长,且常常应用。
某类须要频繁实例化,而创立的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。
频繁拜访数据库或文件的对象。
对于一些管制硬件级别的操作,或者从零碎上来讲该当是繁多管制逻辑的操作,如果有多个实例,则零碎会齐全乱套。
当对象须要被共享的场合。因为单例模式只容许创立一个对象,共享该对象能够节俭内存,并放慢对象访问速度。如 Web 中的配置对象、数据库的连接池等。
5. 总结:
在单例模式各种设计的办法中,咱们应用到了外部动态类的个性,应用了枚举的个性,所以根底十分重要,单例模式是设计模式之一,而设计模式其实是对语言个性有余的一面进一步的包装。吸纳根底,工作学习多加思考,设计模式也就自然而然的可能了解。