在开始写之前我想吐槽下CSDN! 在上面写的源码探索系列6和14居然不见了,上次找版主去找回一次别的文章! 这次居然跑了两篇,服务器要高可用啊!
现在还记得14写的内容是HandleThread,但第六篇那么久那里还记得写的是哪篇,想补都补不回来了!
(更新:12/30, 记起来了,那个第六篇是四大金刚之一的广播,唉,那篇写了好久才整理出来的,跪了!)
为了写这篇文章,内心压制了好久,那些文章都是我每天下完班辛辛苦苦熬到凌晨一两点才写完的! 翻看了那么多代码,熬了这么久!真的内心难以忍受这样的错误!
一个可以让人舒服写字的地方真不容易找!
起航
我们的单例模式在我们开发安卓的过程多多少少会遇到,或者我们在写的过程就可能写过了。 他的最原始的样子像下面这样:
1 | public class MySingleWork { |
看上面的例子,我们可以看到一个基本的模型:
- 一个静态的实例变量
- 一个私有的构造函数
- 一个获取这个静态实例的静态函数
这个就是单例的基本套路,他起源于对资源的控制上要求有且只有一人,真像我们以前的皇帝一样,一个国家只能有一个皇帝,如果有两个,变成双重心,那可是要出问题的啊。就像你有两个脑袋,一个说要前进,一个说要后退,你说该怎么办呢?所以最好只有一个负责人。因此我们需要一个独当一面的东西出来。 这个就是单例(Singleton
)
但上面的单例是有点小问题的,不过如果不涉及多线程,多进程的话,那就没什么问题。 所有的问题基本是确保是否唯一和效率的问题! 上面的单例模式的问题就是可能会导致不惟一,当有多个线程并发的调用MySingleWork.getInstance()
的时候,就有可能闹问题啦! 维持我们加了一个同步锁synchronized
,这个加锁也挺有学问的,加的方式也挺多的,下面列几个曾经看到的。
版本:
1 | public synchronized static MySingleWork getInstance() { |
版本2:
1 | public synchronized static MySingleWork getInstance() { |
版本3:
1 | public synchronized static MySingleWork getInstance() { |
这三个版本,显然是第三个最好,因为其实我们大部分的情况是实例化了,再继续调用的情况。即多次的调用,这时候如果还有synchronized
要面对,效率就降下来了。虽然第三版的第一次效率低,不过后面就没有影响了,是笔合理的代价,而且在很多高并发情况,这个也是不会有错误的,除了多进程的情况。
不过这个模式还是存在失效的情况,到底怎么个失效法呢,欢迎看下这里,清英大神的并发编程网里面的一篇完美的单例实现(The Perfect Singleton)对这个问题的讨论,这里复制下解决方案,静态内部类单例模式
1 | public class MySingleWork { |
可以看到,这里由一个静态的内部类来持有,可以满足线程安全,而且知道我们调用getInstance的时候。才会去生成,即延迟加载。
除了以上,还有遇到过一种容器单例模式,这个在我们的源码探索系列里面有提到过。
1 | public class ContainerSingleton { |
通过这个方式,我们把单例根据key-value对来保存,然后后面需要的就在获取。 这种看起来不是很想前几个常见的模式。
但有一点不变,某东西只有一个,不会重复的原则!
后记
本来还想继续补充点内容,但今天的心情真的一般般,特别是看到我的文章少了,下次有空再继续补充。
由于传图不怎么方便,关于UML的设计等图片就略了,下次看有什么优雅的方法提高下效率吧。
自己学可以有多一些的思考,就像看别人写的代码一样,觉浅需行。 书上看的时候觉得浅,想彻底掌握还是需要自己亲行力践