-
定义
- 保证一个类仅有一个实例,并提供一个访问它的全局访问点。 结构和说明
- Singleton负责创建Singleton类自己的唯一实例,并且提供一个getInstance的方法,为外部提供一个访问全局访问点。
//懒汉式实现
public class Singleton {
//定义一个变量来存储创建好的实例
//因为变量在静态方法中使用 所以使用static
private static Singleton uniqueInstance = null;
//构造器私有化
private Singleton(){}
//提供一个方法来为客户端提供类实例并且定义类方法,也要加static
public static synchronized getInstance(){
//是否实例存在
if (uniqueInstance == null){
//不存在实例化
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
//时间上:(以时间换空间)
//线程安全:一般不加synchronized,严重影响性能 线程不安全
}
//饿汉式实现
public class Singleton{
//定义一个静态变量来存储创建好的实例
//类装载时候初始化,由虚拟机来保证只会创建一次
private static Singleton instance = new Singleton();
//构造器私有化
private Singleton(){}
//定义一个方法为客户端提供实例并且定义类方法,也要加static
public static Singleton getInstance(){
return instance;
}
//时间上去看:(以空间换时间)
//线程安全 :线程安全
}
-
理解单例模式
-
a.读取配置文件(应用)
读取配置文件一般使用单例模式,只初始化一次文件配置。
b.单例模式的功能
单例模式的功能是用来保证这个类在运行期间只被创建一个实例,并且提供一个全局唯一访问这个实例的访问点。
单例模式的范围是个一个ClassLoader及其子ClassLoader范围。
c.延迟加载的思想
延迟加载,就是一开始不要加载资源或者数据,一直等到马上就要使用这个资源或数据躲不过了才加载Lazy Load,延迟加载,在实际开发中是一种很常见的思想,尽可能的节省资源。懒汉式单例getInstance()方法判断实例是否存在,是否需初始化。
d. 缓存思想
单例模式懒汉式实现体现了缓存思想,缓存也是实际开发中非常常见的功能,缓存是一种典型的空间换取时间的方案。
public class JavaCache{
private Map<String,Object> map = new HashMap<>();
public Object getValue(String key){
Object obj = map.get(key)
if (obj == null){
obj = key +",value"
map.put(key,obj);
}
return obj;
}
//1.定义一个缓存数据容器
//2.从缓存中获取数据
//2.1从缓存中取值
//2.2判断缓存中是否有值
//2.3如果有值,就直接使用这个值
//2.4如果没有,那么去获取响应数据,或者创建相应的对象
//2.4.1把新值放入缓存中
}
- 使用缓存实现单例模式
public class Singleton{
private final static String DEFAULT_KEY = "singleton"
private static Map<String,Singleton> map = new HashMap<>();
private Singleton(){}
public static Singleton getInstance(){
Singleton instance = (Singleton) map.get(DEFAULT_KEY)
if (instance == null) {
instance = new Singleton();
map.put(DEFAULT_KEY,instance);
}
return instance;
}
}
单例模式的优缺点
- 时间和空间:懒汉式是典型的时间换取空间,饿汉式是典型的空间换取时间。
- 线程安全:不加同步 的懒汉式是线程不安全的。饿汉式是线程安全的。因为虚拟机保证只会加载一次。懒汉式线程安全:加上synchronized即可。
双重检查
public class Singleton{
//volatile 修饰的变量线程共享
private volatile static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance(){
if (instance == null){
synchronized(Single.class){
if (instance == null){
instance = new Singleton();
}
}
}
}
}
- java一种更好的单例实现方式
public class Singleton{
//类级的内部类,也就是静态的成员内部类,该内部类实例与外部类实例没有绑定关系,而且只有被调到才会装载,从而实现延迟加载
private static class SingletonHolder{
//静态初始化,由jvm来保证线程安全
private static Singleton instance = new Singleton();
}
private Singleton(){
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
- 单例和枚举
使用枚举来实现单例的实例
public enum Singleton{
//定义一个枚举的元素,它就代表了Singleton的实例
uniqueInstance;
public void SingletonOperation(){
//自身功能处理
}
}
-
单例模式的本质
- 控制实例数目 如何实现实例数目?比如说控制实例数目3个?
public class OneExtend{
private final static String DEFAULT_PREKEY = "Cache";
//缓存实例容器
private static Map<String,OneExtend> map = new HashMap<>();
//用来记录当前正在使用第几个实例,到了控制的最大数目,那就返回从1开始
private static int num =1 ;
//定义控制实例的最大数目
private static int NUM_MAX = 3;
private OneExtend(){}
public static OneExtend getInstance(){
String key = DEFAULT_PREKEY + num;
OneExtend oneExtend = map.get(key);
if (oneExtend == null){
oneExtend = new OneExtend();
map.put(key,oneExtend);
num++;
if (num > NUM_MAX){
//若果实例序号已经达到最大数目了那么重1开始
num = 1
}
return oneExtend;
}
}
public static void main(String[] args){
OneExtend t1 = getInstance();
OneExtend t2 = getInstance();
OneExtend t3 = getInstance();
OneExtend t4 = getInstance();
OneExtend t5 = getInstance();
OneExtend t6 = getInstance();
System.out.println("t1="+t1);
System.out.println("t2="+t2);
System.out.println("t3="+t3);
System.out.println("t4="+t4);
System.out.println("t5="+t5);
System.out.println("t6="+t6);
}
}
-
何时选用单例模式
- 当需要控制一个类的实例只能有一个,而且客户只能从一个全局访问点访问它时,可以选用单例模式。