设计模式之单例模式
来源:互联网 发布:数据找规律 编辑:程序博客网 时间:2024/06/02 05:48
设计模式之单例模式
单例模式
“单例(Singleton)”简单理解就是单一实例,全局最多只能创建一个该类的实例对象,该类提供得到该实例的全局访问点,通常是getInstance()
这个静态方法。可能你会疑问了,那我想得到对象,我new不就行了?对不起,这个类的构造方法修饰符是private,没给你new的机会啊。那好吧。。。我们来看一下最简单的例子:
public class Singleton { private static Singleton mInstance; // Singleton模式全局唯一的实例对象 private static int count = 0; // 代表当前类被实例化的次数 //私有构造方法,让你new无可new private Singleton() { count++; System.out.println("啊,被实例化了" + count); } /** * 全局提供的静态方法访问点 * @return 全局唯一的Singleton实例对象 */ public static Singleton getInstance() { if (mInstance == null) { mInstance = new Singleton(); } return mInstance; } /** * 打印一下当前对象的hashcode */ public void printHashCode() { System.out.println("hashCode--->" + this.hashCode()); }}
接下来,看看测试类:
public class Test { public static void main(String[] args) {// Singleton singleton = new Singleton(); //这个肯定报错的 Singleton st1 = Singleton.getInstance(); //这个嘛就是我们想要的了 st1.printHashCode(); Singleton st2 = Singleton.getInstance(); //再来一个 st2.printHashCode(); }}
你猜结果:
啊,被实例化了1hashCode--->366712642hashCode--->366712642
没有出乎你的想象吧,这两个实例的hashcode是相同的,而且构造方法只被调用了一次。注意点:
1. getInstance()这个方法必须是静态的;
2. 内部的对象mInstance也必须是静态的,不然静态方法怎么访问非静态成员呢?
3. 构造方法必须是private修饰的,不然可以被各种new,全局可就有数不清的Singleton对象了(好奇怪)。
你以为这样就完了?好吧,单线程中,这样确实差不多了哈,但是一遇到多线程,你可就要仔细仔细考虑了,来看个示意图吧
public static Singleton getInstance() { if (mInstance == null) { //① mInstance = new Singleton();//② } return mInstance; }
当两个线程同时执行到①这儿,是不是就有机会创造不同的对象了呢?答案是肯定的啊!
我们把测试类中主方法内容改一改:
public static void main(String[] args) { Runnable r = new Runnable() { @Override public void run() { Singleton st = Singleton.getInstance(); st.printHashCode(); } }; new Thread(r).start();//来一个新线程 new Thread(r).start();//再来一个新线程 //你还可以多来几个新线程,看看结果乱成什么样子,一定不会让你失望的}
看到结果,我是平静的,完全意料之中
啊,被实例化了2啊,被实例化了2hashCode--->358411109hashCode--->1980094282
那该怎么解决呢?想必你已经想到了,线程同步加synchronized
关键字,那我们不妨试试,public synchronized static Singleton getInstance()
仅仅多加了这个关键字,其他啥都变,再试试,结果一定是您期望的那样,这儿就不贴出来了,就让客官自己动手写写看效果吧。
扩展
谈到这儿,基本概念也应该知道了吧,那我们再扩展扩展呗,把传说中的“饿汉模式”、“懒汉模式”说说呗。
这两种都是单例模式,只是具体实现方式不同。
懒汉模式
其实前面写的代码就是懒汉模式,说他懒,是因为:每次你调用getInstance()
方法的时候,它才会去判断该唯一实例对象是否存在,不存在则new出来返回给你。
饿汉模式
说它‘饿’是因为它真的很饿,你饿了吗?我好像有点饿了。。。好吧,不知道说到哪儿去了。饿汉预先把对象new出来(就像人,饿了,先吃饱,好像比喻不怎么恰当,没关系啦)。上代码吧
public class LazySingleton { //类加载的时候,就预先new出来 private static LazySingleton mInstance = new LazySingleton(); private static int count = 0; private LazySingleton() { System.out.println("count--->" + (++count)); } //直接返回对象 public static LazySingleton getInstance() { return mInstance; } public void printHashCode() { System.out.println("hashcode--->" + this.hashCode()); }}
这个好处是:即使多线程,也不用考虑同步的问题,因为类加载的时候就创建了唯一的对象,要得到实例时,直接返回即可。
好吧,看似很简单的单例模式,其实也并不简单,对于饿汉模式,还有一些可以优化的地方,采用“双重检查加锁”,在getInstance()
中减少使用同步 。 具体请参考下面:
《Head First 设计模式(中文版)》 page182
题外话
这一段时间,一直在忙另外一个项目,所以没有更新,不过,以后打算还是要坚持规律的更新一下吧。MarkDown编辑器还不是很熟,慢慢用着用着就好了吧,毕竟以前也没用过,也没花时间去学,我承认我有点懒了。
这篇没有讲故事,因为单身和单例就比较配哦,没有故事可讲,嘻嘻。
- 设计模式之 单例设计模式
- 设计模式之 单例设计模式
- 设计模式之单例设计模式
- 设计模式之-----------单例设计模式
- 设计模式之:单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之单例设计模式
- 设计模式之-单例设计模式
- 设计模式之单例设计模式 标签: 设计模式
- 设计模式之单例
- 设计模式之单例
- 设计模式之 单例
- MySQL学习之——锁(行锁、表锁、页锁、乐观锁、悲观锁等)
- 线程池
- 清除临时文件,自己看别人看没有用
- android 电池(二):android关机充电流程、充电画面显示
- dubbo + springmvc + mybatis + ehcache + redis }企业大型互联网分布式架构{Java分布式架构
- 设计模式之单例模式
- Vuex基础
- 微信小程序开发:Flex布局
- js 冒泡排序
- LeetCode 485. Max Consecutive Ones
- 1066: [SCOI2007]蜥蜴
- C#
- Maven系列--pom.xml 配置详解
- VS2017 远程调试linux:新增/修改远程计算机连接