java设计模式之单例模式(singleton)

单例设计模式是面试的时候比较经常问的问题之一。单例设计模式保证一个类有且仅有一个实例,创建 单例对象,有很多种方式,但是不管如何创建一个单例对象,都必须确保其他开发人员不能创建该单例对象的其他实例。

单例模式一(饿汉式):

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来代替。

这种需要产生固定数量对象的模式就叫做有上限的多例模式,它是单例模式的一种扩展。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值