单例设计模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类
所以单例有三个要点
- 单例类只能有一个实例
- 他必须自行创建这个实例
- 他必须自行向整个系统提供这个实例
在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个全局对象,这样有利于我们协调系统的整体行为。 比如在某个服务器程序中,服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象在通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。其实生活中的这样的例子很多很多。
1.单例设计模式
(1)如何对对象的唯一性的控制,这就是单例模式需要解决的问题
(2)单例模式的结构:单例模式向系统外界提供了唯一的自身对象,外界无法自行创建一个单例的对象
2.单例设计模式的作用:
单例模式,是一种常用的软件设计模式。通过单例模式可以保证系统中,应用该模式的这个类只有一个实例。即一个类只有一个对象实例。
3.单例设计模式实现步骤
类结构图:
1. 将构造方法私有化,使其不能在类的外部通过 new 关键字实例化该类对象。2. 在该类内部产生一个唯一的实例化对象,并且将其封装为 private static 类型的成员变量。3. 定义一个静态方法返回这个唯一对象。
4.单例设计模式的类型
根据实例化对象的时机单例设计模式又分为以下两种 :1. 饿汉单例设计模式2. 懒汉单例设计模式
4.1 饿汉式单例设计模式
package com.wsl.demo;
/**
* 饿汉式单例模式
* */
public class Singleton {
/**
* 私有的静态的自身类对象
* */
2.在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型的成员变量。
private static final Singleton singeton = new Singleton();
/**
* 私有构造方法
* */
1.将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
private Singleton(){
}
/**
* 共有的静态获得实例方法
* */
3.定义一个静态方法返回这个唯一对象
public static Singleton getInstance(){
return singeton;
}
}
饿汉式的特点:
- 具有私有的构造方法
- 具有私有的静态属性,维护自身的实例,在初始化的数据就创建实例
- 具有共有的服务方法、
“饿汉模式”的优缺点:
优点:实现起来简单,没有多线程同步问题。
缺点:当类SingletonTest被加载的时候,会初始化static的instance,静态变量被创建并分配内存空间,从这以后,这个static的instance对象便一直占着这段内存(即便你还没有用到这个实例),当类被卸载时,静态变量被摧毁,并释放所占有的内存,因此在某些特定条件下会耗费内存。
4.2 懒汉式单例设计模式
package com.wsl.demo;
public class SingletonLazyLoad {
/**
* 私有的静态的自身类的对象
* */
// 2.在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型的成员变量。
private static SingletonLazyLoad singletonLazyLoad;
/**
* 私有构造方法
* */
1.将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
private SingletonLazyLoad(){
}
/**
* 共有的静态获得实例方法
* */
3.定义一个静态方法返回这个唯一对象。要用的时候才例化出对象
public static synchronized SingletonLazyLoad getInstance(){
if (singletonLazyLoad==null){
singletonLazyLoad = new SingletonLazyLoad();
}
return singletonLazyLoad;
}
}
注意:懒汉单例设计模式在多线程环境下可能会实例化出多个对象,不能保证单例的状态,所以加上关键字:synchronized,保证其同步安全。
优点:在多线程情形下,保证了“懒汉模式”的线程安全。
缺点:众所周知在多线程情形下,synchronized方法通常效率低,显然这不是最佳的实现方案。
5.懒汉式和饿汉式 区别
两者的区别在于 懒汉式 不会在类初始化的时候就实例化其对象,而在外部调用共有服务方法时才判断是否需要进行创建。
通常使用 懒汉式 单例模式多一些,因为在初始化的过程中,他的系统资源少,并且在系统运行时,会有选择的进行实例化工作。
单例模式的使用情况通常有两种:
- 直接新建单例对象, 一般我们会加入一个private 或者protected的构造函数,这样系统就不会自动添加public 的构造函数了,因此只能调用里面的static方法,无法通过new来创建对象
- 通过反射构造单例对象。反射时可以使用setAccessible方法来突破private的限制,我们需要直接新建单例对象的同时,在RelectPermission(‘’suppressAccessChecks‘’)权限下使用安全管理器(SecurityManager)的checkPermission方法来限制这种突破,一般来说,这些事情都是通过应用服务器进行后台配置实现。
6. 4.2中的线程安全的单例设计模式还有一种其他的解决方法;他充分利用了java虚拟机的特性、
package com.wsl.demo;
//单例模式,线程安全
public class SingletionLazyton {
//内部类
private static class SingletonHolder{
static final SingletionLazyton uniqueInstance = new SingletionLazyton();
}
private SingletionLazyton(){
}
//共有的静态获得实例方法
public static SingletionLazyton getInstance(){
return SingletonHolder.uniqueInstance;
}
}
特点:效率高,线程安全,多线程操作原子性
原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。
- 线程安全:由静态内部类中的静态成员初始化时创建实例,通过JVM类加载机制来保证线程的安全性。
- 懒加载:使用静态内部类的方式,让类SingletonHolder只有在使用的时候才会被加载,实例才会创建,借机实现了懒加载。
7.单例模式在JDK中的实例
单例模式在JDK和各种框架中十分常见,因为在各种需求下都有对某种资源唯一化的需求
例如:java.lang.System 此类提供了很多工具方法,比如获取系统输入,输出对象,获取系统属性,获取系统当前时间,比如:
由于JDK对外开放的System这个单例,所以系统代码中任何一个地方都可以使用这些服务而无需考虑其对象的多例问题,以及多线程安全问题、
在比如JDK中的Runtime类,此类就是一个典型的单例模式
JDK和各种框架中有大量的单例模式的例子,所有多在学习过程中进行积累总结、
总结:
1.单例模式的功能
- 确保一个类只有一个实例被建立
- 提供了一个对对象的全局访问指针
- 在不影响单例类的客户端的情况下,运行将来有多个实例
2.单例模式的优点
为一个面向对象的应用程序提供了对象的唯一访问点,不管他实现何种功能,此种模式都为设计及开发团队提供了共享的概念
3.缺点
单例模式类的派生有很大的困难,因为其构造方法为私有,所以子类也不能使用。
4.单例模式的应用场景
系统只需要一个实例对象,或者客户调用类的单个实例只允许使用一个公共访问点时、
5.最后建议在使用单例模式时,使用 4.1 饿汉式的单例模式 或者 使用 6 中的利用java虚拟机的特性的通过内部类的方式实现懒汉式的单例模式