在开始写之前我想吐槽下CSDN!
源码探索系列6和14居然不见了,上次找版主去找回一次别的文章!这次居然跑了两篇,服务器要高可用啊!
现在还记得14写的内容是HandleThread,但第六篇那么久那里还记得写的是哪篇,想补都补不回来了!
我很怀疑这CSDN的人自己都不用这个来写文章的,写文章过程遇到一堆bug也没改进下!
整个CSDN的博客产品线一点真的都不用户友好,设计逻辑上一堆乱起八糟的!
怪不得没落成这样,还是有点原因的。
为了写这篇文章,内心压制了好久,那些文章都是我每天下完班辛辛苦苦熬到凌晨一两点才写完的!
翻看了那么多代码,熬了这么久!真的内心难以忍受这样的错误!
我要寻找一个替代CSDN来写文章的地方!
以前自己搭博客写,但传图片太麻烦了,现在很多网站都限制外链的。哎!
一个可以让人舒服写字的地方真不容易找!
好了,我大骂完了,并且也不打算删除这些负面文字
起航
我们的单例模式在我们开发安卓的过程多多少少会遇到,或者我们在写的过程就可能写过了。
他的最原始的样子像下面这样:
public class MySingleWork {
private static MySingleWork mySingleWork;
MySingleWork() {
}
public static MySingleWork getInstance() {
if (mySingleWork == null) {
mySingleWork = new MySingleWork();
}
return mySingleWork;
}
}
看上面的例子,我们可以看到一个基本的模型:
- 一个静态的实例变量
- 一个私有的构造函数
- 一个获取这个静态实例的静态函数
这个就是单例的基本套路,他起源于对资源的控制上要求有且只有一人,真像我们以前的皇帝一样,一个国家只能有一个皇帝,如果有两个,变成双重心,那可是要出问题的啊。就像你有两个脑袋,一个说要前进,一个说要后退,你说该怎么办呢?所以最好只有一个负责人。因此我们需要一个独当一面的东西出来。
这个就是单例(Singleton
)
但上面的单例是有点小问题的,不过如果不涉及多线程,多进程的话,那就没什么问题。
所有的问题基本是确保是否唯一和效率的问题!
上面的单例模式的问题就是可能会导致不惟一,当有多个线程并发的调用MySingleWork.getInstance()
的时候,就有可能闹问题啦!
维持我们加了一个同步锁synchronized
,这个加锁也挺有学问的,加的方式也挺多的,下面列几个曾经看到的。
版本:
public synchronized static MySingleWork getInstance() {
if (mySingleWork == null) {
mySingleWork = new MySingleWork();
}
return mySingleWork;
}
版本2:
public synchronized static MySingleWork getInstance() {
synchronized (MySingleWork.class) {
if (mySingleWork == null) {
mySingleWork = new MySingleWork();
}
return mySingleWork;
}
}
版本3:
public synchronized static MySingleWork getInstance() {
if (mySingleWork == null) {
synchronized (MySingleWork.class) {
if (mySingleWork == null) {
mySingleWork = new MySingleWork();
}
}
}
return mySingleWork;
}
这三个版本,显然是第三个最好,因为其实我们大部分的情况是实例化了,再继续调用的情况。即多次的调用,这时候如果还有synchronized
要面对,效率就降下来了。虽然第三版的第一次效率低,不过后面就没有影响了,是笔合理的代价,而且在很多高并发情况,这个也是不会有错误的,除了多进程的情况。
不过这个模式还是存在失效的情况,到底怎么个失效法呢,欢迎看下这里,清英大神的并发编程网里面的一篇完美的单例实现(The Perfect Singleton)对这个问题的讨论,这里复制下解决方案,静态内部类单例模式
public class MySingleWork {
private MySingleWork() { }
public synchronized static MySingleWork getInstance() {
return SingletonHolder.mySingleWork;
}
private static class SingletonHolder {
private static MySingleWork mySingleWork = new MySingleWork();
}
}
可以看到,这里由一个静态的内部类来持有,可以满足线程安全,而且知道我们调用getInstance的时候。才会去生成,即延迟加载。
除了以上,还有遇到过一种容器单例模式,这个在我们的源码探索系列里面有提到过。
public class ContainerSingleton {
private static Map<String, Object> singletonList = new HashMap<>();
private ContainerSingleton() {
}
public static Object getInstance(String key) {
return singletonList.get(key);
}
public static void registerInstance(String key, Object singletonObject) {
if (!singletonList.containsKey(key)) {
singletonList.put(key, singletonObject);
}
}
}
通过这个方式,我们把单例根据key-value对来保存,然后后面需要的就在获取。
这种看起来不是很想前几个常见的模式。
但有一点不变,某东西只有一个,不会重复的原则!
后记
本来还想继续补充点内容,但今天的心情真的一般般,特别是看到我的文章少了,下次有空再继续补充。