Java单例设计模式
2015-10-10 18:28
471 查看
单例设计模式
一 为什么要使用单例设计模式
在程序开发中,单例模式尝尝被用于管理共享的资源。有的类的对象我们只需要一个,比如线程池,缓存,注册表的对象,如果有多个实例就会导致很多问题的发生。所有我们要设计一个类,确保这个类只有一个对象,并提供一个全局访问点。
二 饿汉单例设计模式
例子:
输出的结果:is the same object? true
三 懒汉单例设计模式
例子:
输出的结果:is the same object? true
分析:饿汉与懒汉单例设计模式的相同点都是将构造函数私有化(此时,只有这个类内点代码可以调用这个构造函数),且有一个全局访问点getInstance。区别在于,饿汉单例模式在类加载的时候就进行了初始化,而懒汉单例设计模式在调用getInstance的时候,进行了判断。
假如不加这个判断,那么在内存中会出现什么情况呢:
上面这幅图显示了不加判断的情况(红色直线代表第一次调用getInstance,绿色直线代表第二次调用getInstance), 我们可以看到,unique内存储的内存地址在第二次调用时发生了变化,指向了新的实例的内存地址。这样也就同时有两个实例存在了。
四 多线程情况下单例模式遇到的问题
假设使用懒汉单例模式时,在多线程下可能会发生下面这种情况:
线程1调用getInstance方法----------------->并进行判断------------->unique为空,允许创建---------->切换到了线程2,调用getInstance--------->进行判断-------
---------->unique为空,允许实例化--------->线程2实例化了对象---------------->切换到了线程1,线程1实例化了对象
上面这这种情况,就会同时存在两个实例,违背了我们的需求。处理这种情况,我们可以使用一种加锁的方式确保只有一个实例:
分析:使用枷锁的方式有一个缺点,那就是只有在第一次执行此方法是,才需要同步。这样十分影响性能,同步一个方法可能会造成程序执行效率下降100倍。
所以在多线程的情况下,推荐使用饿汉单例设计模式(也存在缺点,在类加载时就实例化,浪费内存)
一 为什么要使用单例设计模式
在程序开发中,单例模式尝尝被用于管理共享的资源。有的类的对象我们只需要一个,比如线程池,缓存,注册表的对象,如果有多个实例就会导致很多问题的发生。所有我们要设计一个类,确保这个类只有一个对象,并提供一个全局访问点。
二 饿汉单例设计模式
例子:
public class SingletonPractice{ //单例设计模式。在内存中只允许一个对象---(static) public static void main(String[] args){ //Single ss = new Single();// 错误类型显式:构造器不可见!!!!阻止了此次创建Single对象 Single ss = Single.getInstance(); Single ss1 = Single.getInstance(); System.out.println("is the same object? " + (ss1 == ss)); } } //饿汉单例设计模式 class Single{ //(1)在类内创建本类的对象。在内存中,保证只有一个 private static Single unique = new Single(); //(2)私有化构造函数,防止在外部被新建对象 private Single(){} //(3)提供公共的静态方法让用户可以得到对象(否则在外部只能通过对象才能拿到这个方法,与需求产生矛盾) public static Single getInstance() { return unique; } }
输出的结果:is the same object? true
三 懒汉单例设计模式
例子:
public class SingletonPractice2 { //单例设计模式,懒汉单例设计模式 public static void main(String[] args){ //Single ss = new Single();// 错误类型显式:构造器不可见!!!!阻止了此次创建Single对象 Single ss = Single.getInstance(); Single ss1 = Single.getInstance(); System.out.println("is the same object? " + (ss1 == ss)); } } class Single{ //懒汉单例设计模式 //对象也可以放到方法区的内存中(这样只有1个) //(1)先不初始化对象 private static Single unique; //(2)私有化构造函数 private Single(){} //(3)加入判断,如果没有这个对象存在,则创建 public Single getInstance(){ if (unique == null) unique = new Single(); return unique; } }
输出的结果:is the same object? true
分析:饿汉与懒汉单例设计模式的相同点都是将构造函数私有化(此时,只有这个类内点代码可以调用这个构造函数),且有一个全局访问点getInstance。区别在于,饿汉单例模式在类加载的时候就进行了初始化,而懒汉单例设计模式在调用getInstance的时候,进行了判断。
假如不加这个判断,那么在内存中会出现什么情况呢:
上面这幅图显示了不加判断的情况(红色直线代表第一次调用getInstance,绿色直线代表第二次调用getInstance), 我们可以看到,unique内存储的内存地址在第二次调用时发生了变化,指向了新的实例的内存地址。这样也就同时有两个实例存在了。
四 多线程情况下单例模式遇到的问题
假设使用懒汉单例模式时,在多线程下可能会发生下面这种情况:
线程1调用getInstance方法----------------->并进行判断------------->unique为空,允许创建---------->切换到了线程2,调用getInstance--------->进行判断-------
---------->unique为空,允许实例化--------->线程2实例化了对象---------------->切换到了线程1,线程1实例化了对象
上面这这种情况,就会同时存在两个实例,违背了我们的需求。处理这种情况,我们可以使用一种加锁的方式确保只有一个实例:
class Single{ private static Single unique; private Single(){} public static Single getInstance(){ if(unique == null){ synchronized (Single.class){ if(unique == null){ unique = new Single(); } } } else{ System.out.println("对象已经存在"); } return unique; } }
分析:使用枷锁的方式有一个缺点,那就是只有在第一次执行此方法是,才需要同步。这样十分影响性能,同步一个方法可能会造成程序执行效率下降100倍。
所以在多线程的情况下,推荐使用饿汉单例设计模式(也存在缺点,在类加载时就实例化,浪费内存)
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树
- 设计模式之创建型模式 - 特别的变量问题