Java 懒汉式单例 饿汉式单例
来源:互联网 发布:空气刘海定型喷雾知乎 编辑:程序博客网 时间:2024/05/19 23:54
转载请注明出处:http://blog.csdn.net/mr_liabill/article/details/48374921 来自《LiaBin的博客》
单例模式很常见,在面试中也会经常直接让你写一个单例出来
单例模式写法一般分为两种,懒汉式和饿汉式
饿汉式
public class SingleTon { //加载类的时候会初始化static的instance,从这以后,这个static的instance对象便一直占着这段内存,永远不会被回收掉。 private static SingleTon instance = new SingleTon(); //将构造函数private掉,避免直接new SingleTon() private SingleTon() { } /** * 因为是单例,所以只能通过static方法来获取实例,因此必须是static的。 * 方法实现较为简单,因为instance已经在加载类的时候被初始化好了,所以不存在多线程并发造成的问题 */ public static SingleTon getInstance() { return instance; }}
优点:
不需要考虑多线程问题,因为instance是静态的,在类加载的时候就已经实例化了,同时也避免了synchronized所造成的性能问题,
缺点:
但这种方式也有点弊端,因为初始化类的时候就需要构造实例,(即便你还没有用到这个实例),因此在某些特定条件下会耗费内存。
懒汉式
为什么需要按如下这么复杂的去实现,参考有详细的解释 http://blog.csdn.net/guolin_blog/article/details/8860649
public class SingleTon { private static SingleTon instance = null; //将构造函数private掉,避免直接new SingleTon() private SingleTon() { } //synchronized避免多线程带来的问题,但同时效率降低,另一方面采取多重锁定,提高效率 public static SingleTon getInstance() { if (null == instance) { synchronized (SingleTon.class) { if (null == instance) { instance = new SingleTon(); } } } return instance; }}这样写是没问题的,因为私有构造函数中没有初始化任何属性,否则的话上面的代码还需要改进
public class SingleTon { private static volatile SingleTon instance = null; private String name; //将构造函数private掉,避免直接new SingleTon() private SingleTon() { name = "SingleTon"; } //synchronized避免多线程带来的问题,但同时效率降低,另一方面采取多重锁定,提高效率 public static SingleTon getInstance() { if (null == instance) { synchronized (SingleTon.class) { if (null == instance) { instance = new SingleTon(); } } } return instance; }}这里为什么需要使用volatile关键字呢?
假设线程thread1走到了第15行的if判断发现instance==null成立,于是都进入了外部的if体。这时候thread1先获取了synchronized块的锁,于是thread1线程会执行第18行的instance = new SingleTon();这句代码,问题就出在这里,这条语句它不是原子性执行的。在Java里,实例化一个对象的过程简单地讲,可以分为两步1)先为instance对象分配一块内存,2)在这块内存里为instance对象里的成员变量赋值(比如第11行里为url赋值)。假设当thread1执行完第1)步而还没有执行第2)步的时候,另外一个线程thread2走到了第15行,这时候instance已经不是null了,于是thread2直接返回了这个instance对象。有什么问题呢?instance对象的初始化(变量赋值等操作)还没执行完呢!thread2里直接得到了一个没有初始化完全的对象,就有可能导致很严重的问题了。
那么volatile关键字有啥作用呢?当用volatile修饰了instance变量之后,对instance的写操作”先行发生“于对它的读操作。(这是Java虚拟机里的先行发生原则)这样就保证了,thread1中的instance变量被完全初始化之后,thread2才能读取它,当没有完成初始化时,thread2只能等会儿啦。
优点:
需要的时候才去加载,内存消耗好一些。(因为在需要的时候才加载,所以叫懒汉式)
缺点:
代码如此复杂,,还有synchronized带来的运行效率问题,调用同步方法会慢不少
方式2: 基于类初始化的解决方案
public class Singleton { private static class SingletonHolder { public final static Singleton instance = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.instance; } }
内部类的初始化是延迟的,外部类初始化时不会初始化内部类,只有在使用的时候才会初始化内部类。而Java语言规范规定,对于每一个类或接口C,都有一个唯一的初始化锁LC与之对应。也就是说,SingletonHolder在各个线程初始化的时候是同步执行的,且全权由JVM承包了。
两种延迟初始化方案总结
延迟初始化降低了初始化类或创建实例的开销,但增加了访问被延迟初始化的字段的开销。在大多数时候,正常的初始化要优于延迟初始化。如果确实需要对实例字段使用线程安全的延迟初始化,请使用上面介绍的基于volatile的延迟初始化的方案;如果确实需要对静态字段使用线程安全的延迟初始化,请使用上面介绍的基于类初始化的方案。
总结
为了省麻烦,就用恶汉式吧。但是我一般用懒汉式,比较需要的时候才加载,可以节省内存。至于synchronized引起的效率问题,基本很少有这样的场景,因为很少有两个线程并发调用getInstance方法。
- Java 懒汉式单例 饿汉式单例
- Java饿汉式单例模式和懒汉式单例模式
- 懒汉式单例和饿汉式单例
- java懒汉式单例遇到多线程
- 懒汉式单例和饿汉式单例优缺点
- 饿汉式单例和懒汉式单例比较
- 饿汉式单例与懒汉式单例的C#实现
- 饿汉式单例与懒汉式单例的讨论
- 饿汉式单例模式和懒汉式单例模式
- 饿汉式单例与懒汉式单例的C#实现
- 饿汉式单例与懒汉式单例的讨论
- 饿汉式单例与懒汉式单例的C#实现
- 【java学习记】—勤快式、懒汉式单例
- 懒汉式和饿汉式单例
- 懒汉式单例模式(Singleton)
- 懒汉式单例设计模式
- 最佳懒汉式单例模式
- 懒汉式单例模式和饿汉式单例模式的区别
- Codeforces Round #319 (Div. 2) ——C. Vasya and Petya's Game(数学题)
- c语言链表-学生成绩管理系统
- Android Studio导入Project、Module的正确方法
- 内存管理与B树
- C#使用Log4Net记录日志
- Java 懒汉式单例 饿汉式单例
- 堆排序的问题——大顶堆例子
- nginx配置文件nginx.conf
- C++之多态性与虚函数
- Struts 2 @ResultPath annotation example
- [Celery]Run celery as daemon
- epoll详解
- Java反射机制及其获取InputStream的两种方式
- TreeSet保证元素唯一并实现排序的原理