单例设计模式是面试的时候比较经常问的问题之一。单例设计模式保证一个类有且仅有一个实例,创建 单例对象,有很多种方式,但是不管如何创建一个单例对象,都必须确保其他开发人员不能创建该单例对象的其他实例。
单例模式一(饿汉式):
public class Singleton {
private Singleton(){}
//在自己内部定义自己一个实例,是不是很奇怪? //注意这是 private 只供内部调用
private static Singleton instance = new Singleton();
//这里提供了一个供外部访问本 class 的静态方法,可以直接访问
public static Singleton getInstance() {
return instance;
}
}
如果不希望提前创建单例实例,还可以在第一次需要该实例的时候,才创建他,延迟初始化。
单例模式二(懒汉式):
public class Singleton {
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
//这个方法比上面有所改进,不用每次都进行生成对象,只是第一次 //使用时生成实例,提高了效率!
if (instance==null)
instance=new Singleton();
return instance;
}
}
如果想在多线程的环境下延迟初始化一个单例模型,必须要小心,避免多线程同时初始化该单例对象。
在多线程环境下,可能会出现两个甚至多个线程同时初始化一个单例对象,可能在线程一初始化的时候,发现该单例对象是null,同时线程二也初始化了一个该单例对象,发现也是null。然后两个线程都会对该单例对象初始化。为了避免这种情况,需要用锁的机制去协调不同线程对同一方法的执行。
解决线程不安全的方法很有多,可以在get方法前加synchronized关键字,也可以在get方法内增加synchronized来实现,但都不是最优秀的单例模式。
当前类的锁进行同步,例:
public class Factory{
private static Factory factory;
private static Object classLock = Factory.class;
public static Factory getFactory(){
synchronized(classLock){
if(factory == null)
factory = new Factory();
return factory;
}
}
}
更推荐使用单例模式一的方法。
单例模式的扩展:
如果一个类可以产生多个对象,对象的数量不受限制,则是非常容易实现的,直接使用new关键字就可以了,如果只需要一个对象,使用单例模式就可以了,但是如果要求一个类只能产生两三个对象呢?
public class Emperor {
//定义最多能产生的实例数量
private static int maxNumOfEmperor = 2;
//每个都有名字,使用一个ArrayList来容纳,每个对象的私有属性
private static ArrayList<String> nameList=new ArrayList<String>();
//定义一个列表,容纳所有的实例
private static ArrayList<Emperor> emperorList=new ArrayList<Emperor>();
//当前序列号
private static int countNumOfEmperor =0;
//产生所有的对象
static{
for(int i=0;i<maxNumOfEmperor;i++){
emperorList.add(new Emperor("皇"+(i+1)+"帝"));
}
}
private Emperor(){
//目的就是不产生第二个
}
//传入名称,建立一个对象
private Emperor(String name){
nameList.add(name);
}
//随机获得一个对象
public static Emperor getInstance(){
Random random = new Random();
//随机拉出一个
countNumOfEmperor = random.nextInt(maxNumOfEmperor);
return emperorList.get(countNumOfEmperor);
}
}
在Emperor中使用了两个ArrayList分别存储实例和实例变量。当然,如果考虑到线程安全问题可以使用Vector来代替。
这种需要产生固定数量对象的模式就叫做有上限的多例模式,它是单例模式的一种扩展。