您的位置:首页 > 编程语言 > Java开发

Java单例设计模式

2015-10-10 18:28 471 查看
单例设计模式

一 为什么要使用单例设计模式

在程序开发中,单例模式尝尝被用于管理共享的资源。有的类的对象我们只需要一个,比如线程池,缓存,注册表的对象,如果有多个实例就会导致很多问题的发生。所有我们要设计一个类,确保这个类只有一个对象,并提供一个全局访问点。

二 饿汉单例设计模式

例子:

public class SingletonPractice{
//单例设计模式。在内存中只允许一个对象---(static)
public static void main(String[] args){
//Single ss = new Single();// 错误类型显式:构造器不可见!!!!阻止了此次创建Single对象
Single ss = Single.getInstance();
Single ss1 = Single.getInstance();
System.out.println("is the same object? " + (ss1 == ss));
}
}
//饿汉单例设计模式
class Single{
//(1)在类内创建本类的对象。在内存中,保证只有一个
private static Single unique = new Single();
//(2)私有化构造函数,防止在外部被新建对象
private Single(){}
//(3)提供公共的静态方法让用户可以得到对象(否则在外部只能通过对象才能拿到这个方法,与需求产生矛盾)
public static Single getInstance() {
return unique;
}
}

输出的结果:is the same object? true

三 懒汉单例设计模式

例子:

public class SingletonPractice2 {
//单例设计模式,懒汉单例设计模式
public static void main(String[] args){
//Single ss = new Single();// 错误类型显式:构造器不可见!!!!阻止了此次创建Single对象
Single ss = Single.getInstance();
Single ss1 = Single.getInstance();
System.out.println("is the same object? " + (ss1 == ss));
}
}
class Single{
//懒汉单例设计模式
//对象也可以放到方法区的内存中(这样只有1个)
//(1)先不初始化对象
private static Single unique;
//(2)私有化构造函数
private Single(){}
//(3)加入判断,如果没有这个对象存在,则创建
public Single getInstance(){
if (unique == null) unique = new Single();
return unique;
}
}

输出的结果:is the same object? true

分析:饿汉与懒汉单例设计模式的相同点都是将构造函数私有化(此时,只有这个类内点代码可以调用这个构造函数),且有一个全局访问点getInstance。区别在于,饿汉单例模式在类加载的时候就进行了初始化,而懒汉单例设计模式在调用getInstance的时候,进行了判断。

假如不加这个判断,那么在内存中会出现什么情况呢:



上面这幅图显示了不加判断的情况(红色直线代表第一次调用getInstance,绿色直线代表第二次调用getInstance), 我们可以看到,unique内存储的内存地址在第二次调用时发生了变化,指向了新的实例的内存地址。这样也就同时有两个实例存在了。

四 多线程情况下单例模式遇到的问题



假设使用懒汉单例模式时,在多线程下可能会发生下面这种情况:

线程1调用getInstance方法----------------->并进行判断------------->unique为空,允许创建---------->切换到了线程2,调用getInstance--------->进行判断-------

---------->unique为空,允许实例化--------->线程2实例化了对象---------------->切换到了线程1,线程1实例化了对象

上面这这种情况,就会同时存在两个实例,违背了我们的需求。处理这种情况,我们可以使用一种加锁的方式确保只有一个实例:

class Single{
private static Single unique;
private Single(){}
public static Single getInstance(){
if(unique == null){
synchronized (Single.class){
if(unique == null){
unique = new Single();
}
}
}
else{
System.out.println("对象已经存在");
}
return unique;
}
}

分析:使用枷锁的方式有一个缺点,那就是只有在第一次执行此方法是,才需要同步。这样十分影响性能,同步一个方法可能会造成程序执行效率下降100倍。

所以在多线程的情况下,推荐使用饿汉单例设计模式(也存在缺点,在类加载时就实例化,浪费内存)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息