想法来源:在学习使用retrofit网络请求框架时,学习了retrofit框架的源码分析,源码中用到了不少设计模式的思想 如:建造者模式、装饰模式、外观模式、代理模式、策略模式、工厂模式、单例模式等等,再加上之前的CVTE面试考察了设计模式的知识点,于是乎决定做个Java设计模式的总结。第一篇献给单例模式,因为单例模式最为常用,而且用法最多。
1.单例模式介绍
1.1单例模式说明
实现一个类只有1个实例化对象&提供一个全局访问点
1.2作用
保证一个类只有一个对象,降低耦合度
1.3单例模式优点
- 提供了对唯一实例的受控访问
- 由于一个类只有一个对象,节约系统资源,提高系统性能,降低耦合度
1.4单例模式缺点
- 单例类的职责过重,违背了“单一职责原则”
- 如果实例化对象长时间不使用,会被系统当成垃圾回收
2.单例模式的实现方式
2.1 饿汉式
1 2 3 4 5 6 7 8 9 10 11 12
| public class Singleton { private static Singleton ourinstance =new Singleton(); private Singleton(){ } public static Singleton getInstance(){ return ourinstance; } }
|
饿汉式优点:单例对象 线程安全 占用内存小,运行速度快
2.2 enum枚举类型
1 2 3 4 5 6 7
| package Singleton;
public enum Enum { Instance; }
|
枚举型优点:最简单、易用的单例模式,是实现单例模式的最佳方法
2.3 懒汉式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package Singleton;
public class Lanhan { private static Lanhan ourinstance =null; private Lanhan(){ } public static Lanhan newinstance() { if (ourinstance==null) { ourinstance=new Lanhan(); } return ourinstance; } }
|
懒汉型优点:创建单例时机可控,延迟加载,手动实例化对象
懒汉型缺点:多线程下不安全,假设线程A、B在并发创建对象,线程A执行到ourinstance=new Lanhan();时(实例化对象时需要时间),线程B执行到if (ourinstance==null)的判断条件中,此时判断为true,于是乎,线程A、B各实例化出对象,共有两个对象,违背了单例模式的原则
2.4同步锁(懒汉式的改进)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package Singleton;
public class Lanhan { private static Lanhan ourinstance =null; private Lanhan(){ } public synchronized static Lanhan newinstance() { if (ourinstance==null) { ourinstance=new Lanhan(); } return ourinstance; } }
package Singleton;
public class Lanhan { private static Lanhan ourinstance =null; private Lanhan(){ } public static Lanhan newinstance() { synchronized (Lanhan.class) { if (ourinstance==null) { ourinstance=new Lanhan(); } } return ourinstance; } }
|
同步锁优点:加入同步锁后,保证线程安全
同步锁缺点:每次执行该方法,都要线程同步,造成过多的成本开销(加锁的时候耗时、耗能)
2.5双重校验锁(同步锁的改进)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package Singleton;
public class doubleif { public static doubleif ourinstance =null;
private doubleif() { } private static doubleif getInstance() { if (ourinstance==null) { synchronized (doubleif.class) { if (ourinstance==null) { ourinstance =new doubleif(); } } } return ourinstance; } }
|
双重校验锁优点:在保证线性安全的同时,提升了系统性能
双重校验锁缺点:多种判断,容易出错
2.6静态内部类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package Singleton;
public class inStatic { private static class Instance{ private static inStatic ourinstance=new inStatic(); } private inStatic() { } public static inStatic getInstance (){ return Instance.ourinstance; } }
|
静态内部类优点:保证线程安全,节约资源,在保证只生成一个实例化对象的同时,还能实现延迟加载功能。
最后附上六大实现方式的总结与对比
![](/2019/03/12/单例模式/outline.png)