设计模式-单例模式
核心作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。
常见应用场景
- Windows中的任务管理器。
- Windows的Recycle Bin(回收站)。在整个系统运行过程中,回收站一直维护着一个仅有的实例。
- 项目中读取配置文件的类一般也只有一个对象,没有必要每次使用配置文件数据都去new一个对象去读取。
- 网站的计数器一般也是使用单例模式实现,否则难以实现同步。
- 应用程序的日志应用一般都采用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
- 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。
- 操作系统的文件系统也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。
- Application也是单例的典型应用(Servlet编程中涉及)。
- Servlet编程中的每个Servlet也是单例。
- Spring中,每个Bean模式就是单例的,这样做的优点是Spring容器可以管理。
- Spring MVC框架/struts1框架中,控制器对象也是单例。
单例模式的优点
- 由于单例模式只生成一个实例,减小了系统性能的开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接生成一个单例对象,然后永久驻留内存的方式来解决。
- 单例模式可以在系统设置全局的访问点,优化环共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理。
常见的五种单例模式实现方式
主要
- 饿汉式(线程安全,调用效率高,但不能延时加载)
- 懒汉式(线程安全,调用效率不高,但可以延时加载)
其他
- 双重检测锁式(由于JVM底层内部模型原因,偶尔会出现问题,不建议使用)
- 静态内部类式(线程安全,调用效率高,可以延时加载)
- 枚举单例(线程安全,调用效率高,不能延时加载)
饿汉式实现(单例对象立即加载)
- 私有化构造器,不对外提供创建对象的方法。
- 提供私有静态属性创建对象,类加载时立刻创建该类对象。
- 提供公共静态方法返回创建的对象。
- Java代码实现:
private class SingletonDemo1{
private static SingletonDemo1 instance = new SingletonDemo1();
//类初始化时立即加载,并且可以保证线程安全
private SingletonDemo1(){ //构造方法私有,不对外提供
}
public static SingletonDemo1 getInstance(){
//不加锁效率高(synchronized )
return instance;
}
}
懒汉式实现(单例对象延迟加载)
- 与饿汉式不同点在于只有外部调用getInstance()方法时才创建对象,并且该方法需要用synchronized修饰,使之同步,并发效率低。
- Java代码实现:
private class SingletonDemo2{
private static SingletonDemo2 instance ;
//类初始化时不创建对象
private SingletonDemo1(){
//构造方法私有,不对外提供
}
public static synchronized SingletonDemo1 getInstance(){
//线程同步效率低
if(s==null)
instance = new SingletonDemo2();
return instance;
}
}
双重检测锁实现
- 由于编译器和JVM底层原因,该方式容易出现错误,不推荐使用。
- Java代码实现:
public class SingletonDemo03{
private static SingletonDemo03 instance = null;
private static SingletonDemo getInstance(){
if(instance==null){
SingletonDemo03 sc;
synchronized (SingletonDemo03.class){
sc = instance;
if(sc==null){
synchronized (SingletonDemo03.class){
if(sc==null){
sc = new SingletonDemo03();
}
}
instance =sc;
}
}
}
return instance;
}
private SingletonDemo03(){
}
}
静态内部类实现方式(也是一种懒加载方式)
- 外部类没有static属性,则不会像懒汉式那样立即加载对象。
- 只有调用getInstance(),才会加载静态内部类,加载时是线程安全的。instance是static final类型,保证了内存中有一个这样的实例存在,而且只能被赋值一次,从而保证了线程安全性。
- 兼备了并发高效调用和延迟加载的优势。
- Java代码实现:
public class SingletonDemo04{
private static class SingletonClassInstance{
private static final SingletonDemo04 instance = new SingletonDemo04();
}
public static SingletonDemo04 getInstance(){
return SingletonClassInstance.instance;
}
private SinglentonDemo04(){
}
}
枚举式实现
- 实现简单.
- 枚举本身就是单例模式.由JVM从根本上提供保障,避免反射和反序列化的漏洞.
- 无加载延迟.
- Java代码实现:
public enum SingletonDemo05{
INSTANCE;//定义一个枚举元素,代表一个单例实例
public void singletonOperation(){ //此处可以添加实现功能
}
}