在我们的开发中,很多时候为了避免多次创建同一个对象,而选择使用了单例模式,这样让我们节省了内存的消耗,对于开发是大有好处的。
最开始的时候,我写单例模式是这样的,代码如下:
public class Single {
private static Single mSingle = null;
public Single() {
}
public static Single getSingle() {
if (mSingle == null) {
mSingle = new Single();
}
return mSingle;
}
}
这样的写法,针对单个线程是没有问题的,由于mSingle是静态的,所以可以保证每次运行的的时候只存在一个实例;但是对于多线程的开发就存在问题了,比如我有两个线程A、B,同时去访问getSingle()方法,这个时候会各自new出一个对象出来,这样就存在了两个实例,违背了单例模式的规则。然后我们可以将代码改进如下:
public class Single {
private static Single mSingle = null;
public Single() {
}
public static Single getSingle() {
synchronized (Single.class) {
if (mSingle == null) {
mSingle = new Single();
}
}
return mSingle;
}
}
针对上述问题,我加了一个所机制,让他有序的去访问getSingle()方法,如果只是两三个线程的话,这样写是没有多大问题的,但是我们想一想,如果,在一个开发中有几百或者几千个线程呢?这样的话就存在一定的问题了,比如,首先是100个线程同时去抢mSingle的所有权,当一个线程抢到了,然后剩下的99个在继续这样抢,依此往下推,可能存在一个运气不好的,知道最后才抢到mSingle的所有权,那么客户端那边等待它返回的数据的时候就会过长,这对于开发者来说是不行的。
我们需要看一下上述代码,真的需要每次进入getInstance方法都要获得锁吗?其实不是的,整个Singleton类中,对mSingle进行访问的地方分为两类:读和写,而且仅当mSingle为null的时候才会写,mSingle一旦创建完毕,后面就只剩下读操作了,再怎么高并发也没什么关系了,反正mSingle已经是现成的,直接读就可以了。
所以,我们又可以对代码做如下修改:
public class Single {
private static Single mSingle = null;
public Single() {
}
public static Single getSingle() {
if (mSingle == null) {
synchronized (Single.class) {
if (mSingle == null) {
mSingle = new Single();
}
}
}
return mSingle;
}
}
最终,写下一种完全应用高并发的单例模式
public class Single {
private Single() {
}
private static class InstanceHolder {
private static final Single instance = new Single();
}
public static Single getInstance() {
return InstanceHolder.instance;
}
}
网友评论