【转载】单例模式的7种写法(整合自两篇文章)
2018-08-13 07:39:16来源:博客园 阅读 ()
转载出处:
1)http://www.blogjava.net/kenzhh/archive/2013/03/15/357824.html
这篇文章介绍了7种单例模式写法,其实是5种:懒汉,恶汉,双重校验锁,枚举和静态内部类。
2)https://www.jianshu.com/p/ad86f107425c
由于上篇文章年代较久,又在网上见到了一种新的写法:使用容器实现单例模式。
本文章整合自上述两篇文章,感谢原作者!
1.定义
- 一个类只有一个实例,并且只有一个全局获取入口。
2.适用场景
- 某个实例对象频繁被访问。
- 某个实例占用的资源较多。
3.实现方式
3.1 懒汉模式(线程不安全)
这样可能会出现线程不同的方法,所以必须对getSingleton方法进行同步。
public class Singleton { private static Singleton singleton;//私有静态变量 private Singleton(){};//私有构造方法 //全局静态访问入口 public static Singleton getSingleton(){ if(singleton==null){ singleton=new Singleton(); } return singleton; } }
3.2 懒汉模式(线程安全)
public class Singleton { private static Singleton singleton;//私有静态变量 private Singleton(){};//私有构造方法 //全局静态访问入口 public static synchronized Singleton getSingleton(){ if(singleton==null){ singleton=new Singleton(); } return singleton; } }
这种写法能够在多线程中很好的工作,而且看起来它也具备很好的lazy loading,但是,遗憾的是,效率很低,99%情况下不需要同步。
3.3 饿汉模式(线程安全)
public class Singleton { private static Singleton singleton=new Singleton();//私有静态变量 private Singleton(){};//私有构造方法 //全局访问入口 public Singleton getSingleton(){ return singleton; } }
这种方式基于classloder机制避免了多线程的同步问题,不过,singleton在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用getSingleton方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化singleton显然没有达到lazy loading的效果。
3.4 静态内部类模式
public class Singleton { private Singleton(){} public static Singleton getSingleton(){ return SingletonHolder.singleton; } private static class SingletonHolder{ private final static Singleton singleton=new Singleton(); } }
这种方式同样利用了classloder的机制来保证初始化singleton时只有一个线程,它跟第三种方式不同的是(很细微的差别):第三种方式是只要Singleton类被装载了,那么singleton就会被实例化(没有达到lazy loading效果),而这种方式是Singleton类被装载了,singleton不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getSingleton方法时,才会显示装载SingletonHolder类,从而实例化singleton。想象一下,如果实例化singleton很消耗资源,我想让他延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化singleton显然是不合适的。这个时候,这种方式相比第三方式就显得很合理。
3.5 枚举模式
public enum Singleton{ singleton; public void hello(){ System.out.print("hello"); } }
这样很简单,线程时安全的,并且避免了序列化和反射攻击。
除了枚举模式,其他模式在实现了Serializable接口后,反序列化时单例会被破坏。所以要重写readResolve()方法。
private Object readResolve() throws ObjectStreamException { return INSTANCE; }
3.6 双重校验锁DCL模式(Double CheckLock)
public class Singleton { private static Singleton singleton;//私有静态内部变量 private Singleton(){};//私有构造方法 //全局访问入口 public static synchronized Singleton getSingleton(){ if(singleton==null){ synchronized (Singleton.class){ if(singleton==null){ singleton=new Singleton(); } } } return singleton; } }
通过两个判断,第一层是避免不必要的同步,第二层判断是否为null。
可能会出现DCL模式失效的情况。
DCL模式失效:
singleton=new Singleton();这句话执行的时候,会进行下列三个过程:
- 分配内存。
- 初始化构造函数和成员变量。
- 将对象指向分配的空间。
由于JMM(Java Memory Model)的规定,可能会出现1-2-3和1-3-2两种情况。
所以,就会出现线程A进行到1-3时,就被线程B取走,然后就出现了错误。这个时候DCL模式就失效了。
Sun官方注意到了这种问题,于是就在JDK1.5之后,具体化了volatile关键字,这时候只用调整一行代码即可。
private volatile static Singleton singleton;
3.7 使用容器实现单例模式
public class SingletonManger{ private static Map<String,Object> objectMap=new HashMap<String,Object>(); private SingletonManger(){} public static void registerService(String key,Object singleton){ if(!objectMap.containsKey(key)){ objectMap.put(key,singleton); } } public static Object getObjectService(String key){ return objectMap.get(key); } }
这样可以将多个单例对象注入到HashMap中,进行统一管理,更加方便快捷。
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
下一篇:数据结构-概念
- 设计模式-委派/策略模式 2020-06-09
- 深入理解:设计模式中的七大设计原则 2020-06-07
- 设计模式---类之间的关系知多少 2020-06-07
- 你与面试官所了解的单例模式并不一样! 2020-06-06
- 高手眼中的观察者模式有什么不一样 2020-06-05
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash