设计模式——单例模式
一、引言
今天笔者想写的设计模式——单例模式,其意图就是为了使系统有且仅有一个实例化,也就是一个对象我只有new一次就够了,也是像我们平凡人一样,婚结一次就够了,但是现在的社会啊,我只能以“理想很丰满,现实很骨感”来形容了,让我们一起了解下单例设计模式吧。
二、单例模式
1. 定义:它是比较简单的一个模式,就是确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
2. 类图:单纯的单例模式,其实就一个类,所以在此处就省略一下类图吧。
三、单例模式示例
1. 懒汉式
package com.pattern.singleton.core; /** * 单例——懒汉式 * 典型的以时间换空间方式 * @author yemaoan * */ public class Singleton { private static Singleton singleton; private Singleton() { //注意是private哦 } public static Singleton getInstance() { if (singleton == null) { singleton = new Singleton(); } return singleton; } }
2. 饱汉式
package com.pattern.singleton.core; /** * 单例——饿汉式 * 典型的以空间换时间方式 * @author yemaoan * */ public class Singleton { public static Singleton singleton = new Singleton(); private Singleton() { } public static Singleton getInstance() { return singleton; } }
四、单例模式应用
单例看起来就是如上面的两种情况一样,相当简单,如果真的这么认为单例就这样完了,那你可能真的可能完了。说不定哪一天你的婚姻真的因插入一个小三给毁了,当然,言重了,那让我们分析一下弊病吧。
在大数据的背景下,并发处理就不可或缺了,而只是简简单单的单例就可能经不起压力测试了,从源码分析上,很容易就发现在问题所在了。怎么解决了,暂且可以在getSingleton()方法前加个关键字synchronized来解决吧。
解决线程不安全的方法挺多的,具体情况具体分析吧。笔者推荐一个:
package com.pattern.singleton.core; /** * 利用static在JVM启动时只实例化一次确保对象唯一 * @author yemaoan * */ public class Singleton { private Singleton() { } public static Singleton getInstance() { return SingletonInstance.instance; } //静态类——在Java应用启动只实例化一次,确实instance的唯一 private static class SingletonInstance { static Singleton instance = new Singleton(); } }
写个例子测试一下吧——就拿上文写的策略算法映射Service来写吧,为什么这么选择呢,也许有这么一个需求,笔者认为,这个类其实也就是一个服务类,很多细节是在开发前就已经配置好的,或者说在数据库里已经定义好的,这样的话,就想当一个工具类。
package com.pattern.stategy.factory; import java.util.HashMap; import java.util.Map; import com.pattern.stratgy.core.Car; import com.pattern.stratgy.core.Plane; import com.pattern.stratgy.core.Train; /** * 算法映射——改装成单例 * @author yemaoan * */ public class ContentService { private Map<String, Class> contentMap = new HashMap<String, Class>(); private ContentService() { contentMap.put("train", Train.class); contentMap.put("plane", Plane.class); contentMap.put("car", Car.class); } public static ContentService contentServiceInstance() { return ContentServiceInstance.instance; } private static class ContentServiceInstance { static ContentService instance = new ContentService(); } public Class get(String key) { return contentMap.get(key); } }
调用者代码:
package com.pattern.singleton.client; import java.util.ArrayList; import java.util.List; import com.pattern.stategy.factory.ContentService; /** * * @author yemaoan * */ public class ContentServiceThread extends Thread { private static List<ContentService> list = new ArrayList<ContentService>(); private String name; public ContentServiceThread(String name) { this.name = name; } @Override public void run() { for(int index = 0; index < 5; index++) { ContentService contentService = ContentService.contentServiceInstance(); list.add(contentService); System.out.print(this.name + " "); } } public static void main(String[] args) throws InterruptedException { //启动四线程,每线程生成5个ContentService //thread begin new ContentServiceThread("A").start(); new ContentServiceThread("B").start(); new ContentServiceThread("C").start(); new ContentServiceThread("D").start(); //thread end Thread.sleep(2000); System.out.println(); System.out.println("当前对象总数为:" + list.size()); for(int index = 0; index < list.size(); index++) { System.out.println((index+1) + " : " + list.get(index)); } } }
笔者用了四个线程,每个线程生成5个ContentService对象,让我们看一下具体运行效果:
B A D C D A B A D C D A B A D C B C B C 当前对象总数为:20 1 : com.pattern.stategy.factory.ContentService@1034bb5 2 : com.pattern.stategy.factory.ContentService@1034bb5 3 : com.pattern.stategy.factory.ContentService@1034bb5 4 : com.pattern.stategy.factory.ContentService@1034bb5 5 : com.pattern.stategy.factory.ContentService@1034bb5 6 : com.pattern.stategy.factory.ContentService@1034bb5 7 : com.pattern.stategy.factory.ContentService@1034bb5 8 : com.pattern.stategy.factory.ContentService@1034bb5 9 : com.pattern.stategy.factory.ContentService@1034bb5 10 : com.pattern.stategy.factory.ContentService@1034bb5 11 : com.pattern.stategy.factory.ContentService@1034bb5 12 : com.pattern.stategy.factory.ContentService@1034bb5 13 : com.pattern.stategy.factory.ContentService@1034bb5 14 : com.pattern.stategy.factory.ContentService@1034bb5 15 : com.pattern.stategy.factory.ContentService@1034bb5 16 : com.pattern.stategy.factory.ContentService@1034bb5 17 : com.pattern.stategy.factory.ContentService@1034bb5 18 : com.pattern.stategy.factory.ContentService@1034bb5 19 : com.pattern.stategy.factory.ContentService@1034bb5 20 : com.pattern.stategy.factory.ContentService@1034bb5
五、总结
1. 单例在设计模式中是比较简单的一个了,它是用途主要是保证一个类有且只有一个实例化对象。
2. 单例在多线程中需要注意一下并发产生对象不一的情况,这也许在压力过程中就能体现出来。
六、题外话
在这里就事论事地说一下,有人也许会认为直接把一个对象设置成一个全局变量就得了,何必这么纠结呢?呵呵,笔者认为,一个全局变量毕竟是一开始就要初始化创建,耗资源呐,再说倘若后期没用了,怎么办,岂不是白白浪费了......而采用单例的话,那又不同说法了,毕竟单例是我们需要的时候才去创建,再者单例模式可以确保一个对象只有被实例化一次。
出处: http://www.cnblogs.com/maoan/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。