有次面试的时候直接被虐了,其中一个问题是要我说单例模式的实现方式。当时直接答了懒汉和饿汉模式,然后又被问有没有其他方式,效率会更高些的,简直一脸的懵逼,回去后查了下,确实还有别的。
什么是单例?----单例就是确保一个类只有一个实例,而且自行实例化,并向系统提供这个实例。单个例还可以扩展,就是多例模式。
有些经验的,根据定义也知道怎么实现,就是构造方法私有化,不让外界实例化(当然反射技术来实现暂不考虑),然后自己实例化一个并提供一个静态的方法将它抛出,这就引出了我们都知道的两种模式:1.懒汉模式 2.饿汉模式
懒汉模式:既然是懒汉,那就说明这家伙比较懒,你问他要他才给你做,不要他就在那里闲着。怎么实现呢?
public class Single { private static Single mSingle = null; private Single(){ } public static Single getInstance(){ if (mSingle == null) { return new Single(); }else { return mSingle; } }}
这就是一个简单的单例,但是这样并不安全,尤其是线程多的时候,可能会产生多个实例。然后改进下:
public class Single {
private static Single mSingle = null;
private Single(){ }
public synchronized static Single getInstance(){
if (mSingle == null) {
return new Single();
}else {
return mSingle;
}
}
}
给获取实例的方法加锁,这样可以保证线程的安全。但是这样效率比较低,可以使用双重校验锁,改进如下public class Single { private static Single mSingle = null; private Single(){ } public static Single getInstance(){ if (mSingle == null) { synchronized (Single.class){ if (mSingle == null){ mSingle = new Single(); } } } return mSingle; } }
改进后就不会每次获取实例都去检查锁了,只有第一次才会。饿汉模式:饿汉嘛,自己就迫不及待的把实例做出来了,饿汉模式本身是线程安全的。但它不是懒加载的,实例一开始就被实例化了。public class Single { private static final Single mSingle = new Single(); private Single(){ } public synchronized static Single getInstance(){ return mSingle; } }静态内部类模式:属于懒加载,饿汉的升级public class Single { private static class SingleBuild { private static final Single INSTANCE = new Single(); } private Single() {} private static final Single getInstance() { return SingleBuild.INSTANCE; } } 个人比较喜欢懒汉中的双重检查锁的写法,通俗而且线程安全,并且效率也高。那次面试估计面试官要的答案就是双重检查锁的方法。当然也可以独立说成一种写法,另外还有查到使用枚举来实现单例,太不常用,就不写了。
多例模式(单例的变种)
//这里采用饿汉的模式 public class Single { private static int MAX_NUMBER = 3; private static ArrayList<Single> list = new ArrayList<Single>(); static { for (int a = 0;a<MAX_NUMBER;a++){ list.add(new Single()); } } private Single(){} public static Single getInstance(){ Random random = new Random(); //从实例中随机获取一个random.nextInt(3)会返回0,1,2 return list.get(random.nextInt(MAX_NUMBER)); } }
如果需要使用到多例,那想必逻辑也会稍微复杂,这里的代码只是一个简单的实现,可以根据实际来编写逻辑。